Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: gsingh93/archutil
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: rxrc/archutil
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Can’t automatically merge. Don’t worry, you can still create the pull request.

Commits on Mar 8, 2015

  1. Verified

    This commit was signed with the committer’s verified signature.
    gaborbernat Bernát Gábor
    Copy the full SHA
    56a1bba View commit details
  2. Remove .gitignore.

    razor-x committed Mar 8, 2015

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    3c5f919 View commit details
  3. Update LICENSE.

    razor-x committed Mar 8, 2015
    Copy the full SHA
    2880429 View commit details
  4. Copy the full SHA
    1ec9e85 View commit details
  5. Copy the full SHA
    74e1341 View commit details
  6. Update README.

    razor-x committed Mar 8, 2015
    Copy the full SHA
    9ba1d03 View commit details
  7. Update README.

    razor-x committed Mar 8, 2015
    Copy the full SHA
    e3df362 View commit details
  8. Use bin over sbin.

    razor-x committed Mar 8, 2015
    Copy the full SHA
    5b1ea7f View commit details
  9. Fix curl command.

    razor-x committed Mar 8, 2015
    Copy the full SHA
    5d0b397 View commit details

Commits on Mar 10, 2015

  1. Copy the full SHA
    89989c0 View commit details

Commits on Mar 13, 2015

  1. Add --sets argument.

    razor-x committed Mar 13, 2015
    Copy the full SHA
    47f99b5 View commit details
  2. Copy the full SHA
    0be806b View commit details
  3. Copy the full SHA
    667b297 View commit details

Commits on Mar 25, 2015

  1. Copy the full SHA
    110acd7 View commit details

Commits on Mar 29, 2015

  1. Use git.io short url.

    razor-x committed Mar 29, 2015
    Copy the full SHA
    9455f4d View commit details
  2. Copy the full SHA
    76a0ceb View commit details
  3. Copy the full SHA
    ae5d174 View commit details
  4. Copy the full SHA
    18dcf44 View commit details

Commits on Apr 14, 2015

  1. Copy the full SHA
    f98f6b6 View commit details

Commits on Apr 15, 2015

  1. Add bower.json.

    razor-x committed Apr 15, 2015
    Copy the full SHA
    0a9355b View commit details

Commits on May 7, 2015

  1. Update license badge.

    razor-x committed May 7, 2015
    Copy the full SHA
    246379e View commit details
  2. Use https for license badge.

    razor-x committed May 7, 2015
    Copy the full SHA
    9759e46 View commit details

Commits on May 13, 2015

  1. Add Release badge.

    razor-x committed May 13, 2015
    Copy the full SHA
    7c5e4ed View commit details
  2. v1.0.0

    razor-x committed May 13, 2015
    Copy the full SHA
    d6ab3fe View commit details

Commits on May 24, 2015

  1. Use /usr/bin/python.

    razor-x committed May 24, 2015
    Copy the full SHA
    614d572 View commit details
  2. v1.1.0

    razor-x committed May 24, 2015
    Copy the full SHA
    e556c4a View commit details

Commits on Oct 13, 2015

  1. Copy the full SHA
    b6fb38d View commit details
  2. v1.1.1

    razor-x committed Oct 13, 2015
    Copy the full SHA
    13559d2 View commit details

Commits on Oct 14, 2015

  1. Use sudo -S

    razor-x committed Oct 14, 2015
    Copy the full SHA
    643cf83 View commit details
  2. v1.1.2

    razor-x committed Oct 14, 2015
    Copy the full SHA
    80b9287 View commit details

Commits on Dec 26, 2016

  1. Copy the full SHA
    b557196 View commit details
  2. Update Warranty in README

    razor-x committed Dec 26, 2016
    Copy the full SHA
    77ac11f View commit details
  3. 1.2.0

    razor-x committed Dec 26, 2016
    Copy the full SHA
    6d0331f View commit details

Commits on Jun 27, 2019

  1. Update YAML loader to SafeLoader

    The default YAML loader is expolitable and causes a warning everytime
    that archutil runs. This changes the loader to SafeLoader to remove
    the warning and remove the exploit.
    mmcculle committed Jun 27, 2019
    Copy the full SHA
    a6578b8 View commit details

Commits on Jun 28, 2019

  1. Merge pull request #1 from mmcculle/feature/YAML-SafeLoader

    Update YAML loader to SafeLoader
    razor-x authored Jun 28, 2019
    Copy the full SHA
    a92188c View commit details
  2. Update LICENSE year

    razor-x committed Jun 28, 2019
    Copy the full SHA
    f065e07 View commit details
  3. 1.2.1

    razor-x committed Jun 28, 2019
    Copy the full SHA
    818c961 View commit details

Commits on Nov 13, 2020

  1. Change package namespace

    razor-x committed Nov 13, 2020
    Copy the full SHA
    b438f0c View commit details
  2. 1.2.2

    razor-x committed Nov 13, 2020
    Copy the full SHA
    e06b360 View commit details
  3. Publish to npm

    razor-x committed Nov 13, 2020
    Copy the full SHA
    01f7316 View commit details
  4. Move to rxrc

    razor-x committed Nov 13, 2020
    Copy the full SHA
    b4b0d2c View commit details
  5. 1.2.3

    razor-x committed Nov 13, 2020
    Copy the full SHA
    b66f11d View commit details
  6. Remove private

    razor-x committed Nov 13, 2020
    Copy the full SHA
    d446ad5 View commit details
  7. 1.2.4

    razor-x committed Nov 13, 2020
    Copy the full SHA
    8d685ef View commit details
  8. Set public access

    razor-x committed Nov 13, 2020
    Copy the full SHA
    23ef7e8 View commit details
  9. 1.2.5

    razor-x committed Nov 13, 2020
    Copy the full SHA
    bbf537b View commit details

Commits on Nov 16, 2020

  1. Update .gitignore

    razor-x committed Nov 16, 2020
    Copy the full SHA
    dab54ea View commit details
  2. Update year

    razor-x committed Nov 16, 2020
    Copy the full SHA
    445f1a6 View commit details
  3. 1.2.6

    razor-x committed Nov 16, 2020
    Copy the full SHA
    698bbf6 View commit details

Commits on Jan 28, 2022

  1. Copy the full SHA
    fcf6c74 View commit details
36 changes: 36 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
name: publish

on:
push:
tags:
- v*

jobs:
npm:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
- name: Publish
uses: JS-DevTools/npm-publish@v1
with:
access: public
token: ${{ secrets.NPM_TOKEN }}
github:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
- name: Publish
uses: JS-DevTools/npm-publish@v1
with:
access: public
token: ${{ secrets.GITHUB_TOKEN }}
registry: https://npm.pkg.github.com
137 changes: 136 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,136 @@
*.pyc
# Parts of this file were adapted from
# GitHub’s collection of .gitignore file templates
# which are Copyright (c) 2020 GitHub, Inc.
# and released under the MIT License.
# For more details, visit the project page:
# https://github.com/github/gitignore

# Build directories
package

# Tern
.tern-project
.tern-port

# npm config
.npmrc

# Yarn lockfile (only npm supported)
yarn.lock

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# Next.js build output
.next
out

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
1 change: 1 addition & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Copyright (c) 2014 Gulshan Singh
Copyright (c) 2015-2020 Evan Sosenko

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
79 changes: 55 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,69 @@
`archutil`
==========
# archutil

`archutil` is an Arch Linux utility that makes it easy to replicate an Arch Linux setup on any other machine in terms of both packages and configuration files. The configuration management functions can actually be used on any Linux distro, but the package management functions can only be used on Arch Linux While there are no plans to port this utility to other platforms, this shouldn't be hard to do with the current design of the tools. You can contact me if you're interested in working on this and pull requests are welcome.
[![Release](https://img.shields.io/github/release/rxrc/archutil.svg)](https://github.com/rxrc/archutil/releases)
[![MIT License](https://img.shields.io/github/license/rxrc/archutil.svg)](./LICENSE.txt)

This tool is still in development and is bound to have bugs. Please report any bugs you find in the issues section. There are also many features that could be added to improve the tool that weren't absolutely necessary for the release. If there's a feature you would find useful, please create an issue for it.
Please see the upstream project for the original
[README](https://github.com/gsingh93/archutil).

Package Management
------------------
The first use for `archutil` is for maintaining a package list so you can keep different Arch installs in sync, quickly replicate an Arch install on another machine, or selectively install specific groups of packages on a machine (i.e. there's no point in installing graphical packages from your local machine to a server running Arch). To list all of the explicitly installed packages on your machine (note that this does not include dependencies), run `./archutil.py list`. On your first run, this should essentially match the output of `pacman -Qe` (minus the `base` group, but we'll get to that). Place that list of packages into `config.py` in the `packages` Python dictionary (i.e. replace `package1` and `package2` with the packages given to you by `archutil`). Now if you run `./archutil.py list` again, it'll only list the packages you've explicitly installed but haven't added to your list, so in this case you should see nothing. You can try installing a random package at this point and then running the command to see if it works. This helps you easily maintain the package list in `config.py`. Note that if you put a package group (like `gnome` or `base-devel`) in your package list, all of the packages in that group won't be displayed in the output of the `list` command. The `base` package group is implicitly placed in your list, as every Arch Linux system should have these packages installed, so you should never see these packages in the output.
## Description

This also helps you keep your system lean and minimal. After putting the initial package list in `config.py` and not running `archutil` for a while, you may end up with a bunch of new packages on your machine. You might have only been trying these packages out, or maybe you needed a package for something but no longer need it. If you run `./archutil.py list`, you can quickly find all the packages you've installed since last running `./archutil.py list`, and you can choose to remove those packages or add them to `config.py`. Thus, you have complete knowledge and control over the packages installed on your system.
This fork has been updated for Python 3,
and modified to use a `yaml` configuration file: `archutil.yml`.
The configuration management functions have been removed.

You can also organize your packages into categories. One benefit of this is it helps you understand and maintain what packages you have installed. Another (and more important) benefit is that you can install specific categories of packages on certain systems. For example, you wouldn't want to install all the graphical packages from your personal laptop onto a server running Arch. To specify categories in `config.py`, simply use the category name as the key and a list of packages in that category as an example. You can then refer to these categories with the `--categories` flag, which we'll use in a bit.
The location of `archutil.yml` can be specified via the `-c` flag.
By default, `archutil` will look for this file in the following order:

We've talked about listing packages, but how do we actually install them? You can use `./archutil.py install` for that. This command first checks if all the packages about to be installed actually exist and tells you if there are any issues. It then installs them with the `--needed` flag, so only new packages will be installed. If you only want to install certain categories, you can run `./archutil.py install --categories graphical dev networking`, which would install all packages in the graphical, dev, and networking categories (note that these are user-defined categories that I made up for this example).
1. In the current working directory.
2. In `/usr/local/etc`.

Configuration Management
------------------------
Addtional changes include a new `--sets` flags and better AUR support.

The second use for `archutil` is for maintaining your configuration files. I (like many of you) version control my dotfiles and other configuration files. A common issue I run into is forgetting to update my Git repo after making changes to certain files, or making changes on one machine, updating the repo, but pulling the repo on another machine a few days later and not remembering which configuration files to sync. `archutil` helps to manage both of these issues.
## Installation

The `config_files` dictionary in `config.py` contains a list of configuration files to manage. All configuration files should be stored in a directory called `config_files` in the same folder as `archutil.py` (more on customizing this path later). Then the keys of the `config_files` dictionary are the paths to files in the `config_files` folders (relative to the `config_files` folder). The value of each key is the location of the file on the system. The example `config.py` shows this for a `.bashrc` file.
Only `bin/archutil` is required.
This can be installed manually to `/usr/local/bin`.

To see which files on the system differ from the files in your dotfiles repo, run `./archutil.py config -d`. This will print the files that differ. If you also want to see the output of the `diff` command for each file, run `./archutil.py config -dd`.
You will also need the `python` and `python-yaml` packages.

To install all the configuration files in the system with the files in the repo, run `./archutil.py config -i` to install the files. If a file already exists at the path of the system file, a `.bak` extension will be added to the original file. To update files in the repo with files in the system, run `./archutil.py config -u`. This will show the diff for each configuration file and prompt you to update the file in the repo with the file in the system.
For convenience, the latest version of `archutil` is provided at
https://io.evansosenko.com/archutil/archutil
and a `package.json` is included for use with npm or yarn.

`archutil` will look in a directory named `config_files` in the same folder as the `archutil` script by default. If you would like to specify a different folder to search for the config files, you can use the `-cd` or `--configs-dir` flags, i.e. `./archutil.py config -cd /path/to/config/files -d`. Alternatively, you can define a variable named `configs_dir` in `config.py` that contains a path to the configuration file directory. If the path is a relative path, it should be relative to the `config.py` script, not `archutil.py`.
For fetching and installing during initial setup, you can use

Misc features
-------------
```bash
$ [sudo] curl -L -o /usr/local/bin/archutil https://git.io/jgz3
$ [sudo] chmod +x /usr/local/bin/archutil
```

- By default, `archutil` looks for `config.py` in the same directory as the script. If you would like to change this directory, use the `-c` flag, i.e. `./archutil.py -c /path/to/config.py`.
- Note that any of the variables in `config.py` can be assigned as the output of some function. Thus, if you want to do something like customize the home directory in the paths in the `config_files` dictionary depending on the user running the script, you can write a Python function to do that
- You can define a `required_repos` variable in `config.py` that contains a list of repos that should be enabled in `/etc/pacman.conf`. Doing this won't enable these repositories, but it will remind you to enable them when installing packages on a new system.
- `archutil` supports installing packages from the AUR. Define a variable in `config.py` called `pacman` and set it to a package manager that can handle packages from the normal repositories and from the AUR, like `yaourt`. The binary specified in that variable will be used for all operations where `pacman` would normally have been used, so not all package managers will work. Also, installing packages from the AUR will be slightly slower, as `archutil` first validates that all packages exist, and currently for AUR packages it needs to run something like `yaourt -Ss package_name` for each AUR package to make sure it exists.
- `archutil` attempts to verify all packages that you're about to install actually exist before attempting to install them. This check is usually very quick, except when using a package manager other than `pacman`, as described above. In these cases, if you would like to skip this verification, you can pass the `-s` flag to the `install` subcommand. The package verification for AUR packages will be sped up in the future.
## Contributing

Please submit and comment on bug reports and feature requests.

To submit a patch:

1. Fork it (https://github.com/rxrc/vimrc/fork).
2. Create your feature branch (`git checkout -b my-new-feature`).
3. Make changes.
4. Commit your changes (`git commit -am 'Add some feature'`).
5. Push to the branch (`git push origin my-new-feature`).
6. Create a new Pull Request.

## License

archutil is licensed under the MIT license.

## Warranty

This software is provided by the copyright holders and contributors "as is" and
any express or implied warranties, including, but not limited to, the implied
warranties of merchantability and fitness for a particular purpose are
disclaimed. In no event shall the copyright holder or contributors be liable for
any direct, indirect, incidental, special, exemplary, or consequential damages
(including, but not limited to, procurement of substitute goods or services;
loss of use, data, or profits; or business interruption) however caused and on
any theory of liability, whether in contract, strict liability, or tort
(including negligence or otherwise) arising in any way out of the use of this
software, even if advised of the possibility of such damage.
500 changes: 0 additions & 500 deletions archutil.py

This file was deleted.

21 changes: 21 additions & 0 deletions archutil.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
# Non-standard repositories required to install packages.
# repos:
# - multilib

# Use a package manager other than pacman.
# pacman: aura

# Use a package manager for aur packages.
# aur: "aura -A"

# Collect categories together into sets.
sets:
main:
- archutil

# List the packages with their categories below.
packages:
archutil:
- python
- python-yaml
353 changes: 353 additions & 0 deletions bin/archutil
Original file line number Diff line number Diff line change
@@ -0,0 +1,353 @@
#!/usr/bin/python

import argparse
import os
import re
import subprocess
import sys
import yaml

try:
from yaml import CLoader as Loader, CDumper as Dumper
except ImportError:
from yaml import Loader, Dumper

# Imported in main
config = None

class Struct:
def __init__(self, **entries):
self.__dict__.update(entries)

class colors:
RED = '\033[31m'
BLUE = '\033[34m'
GREEN = '\033[32m'
YELLOW = '\033[33m'
DEFAULT = '\033[0m'


def printc(m, c):
print(c + m + colors.DEFAULT)


def print_msg(m, color=colors.DEFAULT):
printc("========== %s ==========" % m, color)


class ListHandler:
def get_listed_packages(self, packages, categories):
"""Returns a set of packages listed in `config.packages`"""
return set([p for c in categories for p in packages[c]])

def get_listed_groups(self, packages):
"""Returns a list of packages in `config.packages` that are actually
groups"""
# TODO: Clean this up by just using pacman -Sg
command = "pacman -Sg %s | awk '{print $1}' | sort -u" \
% " ".join(packages)
return subprocess.check_output(command,
shell=True, universal_newlines=True).rstrip().split('\n')

def get_installed_packages(self, groups):
"""Returns a set of installed packages"""
command = ("pacman -Qe | awk '{print $1}'"
"| grep -Fxv -f <(pacman -Qg %s"
"| awk '{print $2}')") % " ".join(groups)
packages = subprocess.check_output(command,
shell=True, universal_newlines=True,
executable="/bin/bash").rstrip().split('\n')
for i in range(0, len(packages)):
packages[i] = packages[i].split()[0]
return set(packages)

def get_differing_packages(self, categories, inverse):
packages = self.get_listed_packages(config.packages, categories)
groups = self.get_listed_groups(packages)
groups.append('base')
installed_packages = self.get_installed_packages(groups)

if not inverse:
return list(installed_packages.difference(packages))
else:
return list(packages.difference(installed_packages))

def handle(self, args):
diff = None

if args.categories == None and args.sets == None:
categories = config.packages.keys()
else:
categories = []
if args.categories != None:
categories.extend(args.categories)

if args.sets != None:
categories.extend(
set([c for s in args.sets for c in config.sets[s]]))

categories = list(set(categories))

if not args.inverse:
# Print all packages that are installed but not listed in the script
diff = self.get_differing_packages(categories, False)
else:
# Packages listed in the script but not installed
diff = self.get_differing_packages(categories, True)

diff.sort()
if args.list:
print("['" + "',\n'".join(diff) + "']")
else:
print('\n'.join(diff))

class InstallHandler:
def __init__(self, pacman, aur):
self.pacman = pacman
self.aur = aur

def check_packages_exist(self, packages, categories):
bad_packages = []
dev_null = open(os.devnull, 'w')
package_list = [p for c in categories for p in packages[c]]

all_packages = subprocess.check_output([self.pacman, '-Ssq'],
universal_newlines=True).split('\n')
missing_packages = set(package_list) - set(all_packages)

# Remove groups from missing_packages
all_groups = set(subprocess.check_output(['pacman', '-Sg'],
universal_newlines=True).split('\n'))

missing_packages -= all_groups

# Fallback to checking individual bad packages if pacman is not used.
# This is required in case packages are actually in the AUR
# TODO: Use this https://wiki.archlinux.org/index.php/AurJson
bad_packages = []
if self.aur != None:
for p in missing_packages:
retcode = subprocess.call(self.aur + ' -sq %s | grep "^%s$"'
% (p, p), shell=True, stdout=dev_null)

if retcode != 0:
bad_packages.append(p)
else:
bad_packages = missing_packages

return [set(bad_packages), set(missing_packages) - set(bad_packages)]

def check_required_repos(self):
repos = []
f = open('/etc/pacman.conf').read()
for repo in config.required_repos:
if re.search(r'\[%s\]' % repo, f, re.MULTILINE) == None:
repos.add(repo)
return repos

def update_repos(self):
dev_null = open(os.devnull, 'w')
printc('Updating package database, enter sudo password if prompted',
colors.YELLOW)
return subprocess.call(['sudo', '-S', self.pacman, '-Sy'], stdout=dev_null) == 0

# TODO: Function shouldn't need to know about test code,
# but I can't figure out any other way :(
def do_install(self, packages, categories, aur_packages, test=False):
package_list = []
for category in categories:
package_list += packages[category]

package_list = set(package_list) - aur_packages

if not test:
command = [self.pacman, '-S', '--needed']
else:
# Turn off confirmations in test mode
command = [self.pacman, '-S', '--needed', '--noconfirm']

if os.path.basename(command[0]) == 'pacman':
command.insert(0, '-S')
command.insert(0, 'sudo')

command.extend(package_list)
subprocess.check_call(command)

if self.aur != None and len(aur_packages) > 0:
command = self.aur.split()
command.extend(aur_packages)
command += ['--needed', '--noconfirm']
command.insert(0, '-S')
command.insert(0, 'sudo')

subprocess.check_call(command)

def handle(self, args):
# Make sure all required repos are available
if does_var_exist('required_repos', list):
repos = self.check_required_repos()
if len(repos) > 0:
print_msg('The following repos must be enabled before package '
'installation can continue: ' + ', '.join(repos),
colors.RED)
return

if not self.update_repos():
print_msg('Failed to update package database', colors.RED)
return
print_msg('Update successful', colors.BLUE)

# Get list of categories to install
categories = None
if args.categories == None and args.sets == None:
categories = config.packages.keys()
else:
categories = []
if args.categories != None:
categories.extend(args.categories)

if args.sets != None:
categories.extend(
set([c for s in args.sets for c in config.sets[s]]))

categories = list(set(categories))

for category in categories:
if category not in config.packages:
print_msg('Package category %s does not exist' % category,
colors.RED)
return

if not args.skip_verification:
# Make sure all packages to be installed exist
printc('Checking that all packages exist', colors.YELLOW)
(bad_packages, aur_packages) = self.check_packages_exist(config.packages, categories)
if len(bad_packages) > 0:
print_msg('The following packages could not be found in the repos '
'and must be removed before installation can continue: '
+ ', '.join(bad_packages), colors.RED)
return

print_msg('Installing packages', colors.BLUE)
self.do_install(config.packages, categories, aur_packages)
print_msg('Install complete', colors.BLUE)


def parse_arguments():
parser = argparse.ArgumentParser(description="Package management utility")
parser.add_argument('-c', '--config-path', help='Path to configy.py')
subparsers = parser.add_subparsers(dest='subcommand')

install_parser = subparsers.add_parser(
'install', help=('Installs specified package groups'))
install_parser.add_argument('-s', '--skip-verification', action='store_true',
help=("Don't check if all packages you're about "
"to install actually exist before attempting to "
"install"))
install_parser.add_argument('--categories', nargs='+',
help='Package categories to install')
install_parser.add_argument('--sets', nargs='+',
help='Category sets to install')

list_parser = subparsers.add_parser(
'list',
help="Lists installed packages not already specified in archutil.yml")
list_parser.add_argument(
'-i', '--inverse', action='store_true',
help=('Lists the inverse, i.e. all packages specified in archutil.yml '
'but not currently installed'))
list_parser.add_argument(
'--categories', nargs='+',
help='Categories to use (only works with -i argument)')
list_parser.add_argument('--sets', nargs='+',
help='Category sets to install (only works with -i argument)')
list_parser.add_argument(
'-l', '--list', action='store_true',
help='Display output as a Python list')

return parser.parse_args()


def does_var_exist(var_name, t):
return hasattr(config, var_name) and type(getattr(config, var_name)) == t


def validate_config_file():
def check_var_exists(var_name, t):
if not does_var_exist(var_name, t):
type_name = t.__name__
msg = "config must contain a %s called `%s`"
print_msg(msg % (type_name, var_name), colors.RED)
return False
return True

return (check_var_exists('packages', dict))


def get_config_file_path(args):
config_file_path = os.path.join(os.getcwd(), 'archutil.yml')

if not os.path.isfile(config_file_path):
config_file_path = '/usr/local/etc/archutil.yml'

if args.config_path != None:
if os.path.isabs(args.config_path):
config_file_path = args.config_path
else:
config_file_path = os.path.join(os.getcwd(), args.config_path)

if not os.path.isfile(config_file_path):
print_msg("%s does not exist" % config_file_path, colors.RED)
sys.exit(1)

return config_file_path

def get_pacman():
if does_var_exist('pacman', str):
return config.pacman
else:
return 'pacman'

def main():
args = parse_arguments()
config_file_path = get_config_file_path(args)

global config
config = {}
config_yaml = yaml.load(open(config_file_path, 'r'), Loader=yaml.SafeLoader)

if 'pacman' in config_yaml:
config['pacman'] = config_yaml['pacman']

if 'aur' in config_yaml:
config['aur'] = config_yaml['aur']
aur = config['aur']
else:
aur = None

if 'repos' in config_yaml:
config['required_repos'] = config_yaml['repos']

if 'sets' in config_yaml:
config['sets'] = config_yaml['sets']

config['packages'] = config_yaml['packages']

config = Struct(**config)

validate_config_file()

pacman = get_pacman();

handler = None
if args.subcommand == 'install':
handler = InstallHandler(pacman, aur)
elif args.subcommand == 'list':
handler = ListHandler()
else:
raise ValueError("Invalid subcommand")

handler.handle(args)

if __name__ == '__main__':
main()
20 changes: 0 additions & 20 deletions config.py

This file was deleted.

25 changes: 25 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@rxrc/archutil",
"version": "1.2.9",
"description": "An Arch Linux tool for listing and backing up explicitly installed packages.",
"homepage": "https://github.com/rxrc/archutil",
"bugs": "https://github.com/rxrc/archutil/issues",
"repository": "rxrc/archutil",
"license": "MIT",
"author": {
"name": "Evan Sosenko",
"email": "razorx@evansosenko.com"
},
"contributors": [
{
"name": "Gulshan Singh",
"email": "gsingh2011@gmail.com"
}
],
"files": [
"bin"
],
"scripts": {
"postversion": "git push && git push --tags"
}
}
Empty file removed test/install_ref_dir/backup_config
Empty file.
Empty file.
1 change: 0 additions & 1 deletion test/install_ref_dir/config_files/differing

This file was deleted.

1 change: 0 additions & 1 deletion test/install_ref_dir/config_files/matching

This file was deleted.

1 change: 0 additions & 1 deletion test/install_ref_dir/differing

This file was deleted.

1 change: 0 additions & 1 deletion test/install_ref_dir/differing.bak

This file was deleted.

1 change: 0 additions & 1 deletion test/install_ref_dir/matching

This file was deleted.

Empty file removed test/install_ref_dir/system_config
Empty file.
37 changes: 0 additions & 37 deletions test/setup-chroot.sh

This file was deleted.

168 changes: 0 additions & 168 deletions test/test.py

This file was deleted.

Empty file.
1 change: 0 additions & 1 deletion test/update_ref_dir/config_files/differing

This file was deleted.

1 change: 0 additions & 1 deletion test/update_ref_dir/config_files/matching

This file was deleted.

1 change: 0 additions & 1 deletion test/update_ref_dir/differing

This file was deleted.

1 change: 0 additions & 1 deletion test/update_ref_dir/matching

This file was deleted.

Empty file removed test/update_ref_dir/system_config
Empty file.