Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| #!/usr/bin/env python3 | |
| import sys | |
| import os | |
| import subprocess | |
| import argparse | |
| P = argparse.ArgumentParser(description="declarative apt") | |
| P.add_argument("path", type=str, help="Path to requirements file") | |
| P.add_argument("--act", default=False, action='store_true', | |
| help="Actually do install and remove packages") | |
| assert __name__ == "__main__" | |
| TO_INSTALL = set() | |
| TO_REMOVE = set() | |
| DEB_LINES = set() | |
| ALL_GREEN = True | |
| def register(line): | |
| if line.startswith("R "): | |
| TO_REMOVE.add(line[2:]) | |
| elif line.startswith("DEB "): | |
| DEB_LINES.add(line[4:]) | |
| else: | |
| TO_INSTALL.add(line) | |
| # Read configuration | |
| ARGS = P.parse_args() | |
| with open(ARGS.path) as fh: | |
| for line in fh: | |
| i = line.find("#") | |
| if i >= 0: | |
| line = line[:i] | |
| if not line: | |
| continue | |
| register(line.strip()) | |
| # Should update sources? | |
| _SOURCE_PATH="/etc/apt/sources.list.d/requirements.list" | |
| deb_lines_current = set() | |
| if os.path.exists(_SOURCE_PATH): | |
| with open(_SOURCE_PATH) as fh: | |
| for line in fh: | |
| if not line.startswith("deb"): | |
| continue | |
| deb_lines_current.add(line[4:].strip()) | |
| if DEB_LINES.difference(deb_lines_current): | |
| if ARGS.act: | |
| with open(_SOURCE_PATH, "w") as fh: | |
| for l in sorted(DEB_LINES): | |
| fh.write("deb ") | |
| fh.write(l) | |
| fh.write("\n") | |
| else: | |
| print("For /etc/apt/sources.list.d/requirements.list") | |
| for l in sorted(DEB_LINES): | |
| print(l) | |
| print() | |
| def error(msg): | |
| global ALL_GREEN | |
| ALL_GREEN = False | |
| print("Error:", msg) | |
| both = TO_INSTALL.intersection(TO_REMOVE) | |
| if both: | |
| error("remove AND install? "+" ".join(both)) | |
| exit(1) | |
| def precheck(pkgs, short_cmd, op): | |
| op = op + " " | |
| pkgs = " ".join(pkgs) | |
| cmd = "apt-get %s -s -y %s" % (short_cmd, pkgs) | |
| try: | |
| output = subprocess.check_output(cmd.split()) | |
| except subprocess.CalledProcessError: | |
| error(cmd) | |
| return | |
| for line in output.decode("utf8").split("\n"): | |
| if line.startswith(op): | |
| pkg = line.split()[1] | |
| yield pkg | |
| # Check removals | |
| removals = set(precheck(TO_REMOVE, "remove", "Remv")) | |
| for pkg in removals: | |
| if pkg in TO_INSTALL: | |
| error("Would remove '%s', which shall be installed" % pkg) | |
| # Check installs | |
| installs = set(precheck(TO_INSTALL, "install", "Inst")) | |
| for pkg in installs: | |
| if pkg in TO_REMOVE: | |
| error("Would install '%s', which shall be removed" % pkg) | |
| removals = removals.intersection(TO_REMOVE) | |
| installs = installs.intersection(TO_INSTALL) | |
| if ALL_GREEN: | |
| if (removals): | |
| cmd = "apt-get remove " + " ".join(removals) | |
| print(cmd) | |
| if ARGS.act: | |
| os.system("sudo %s -y"%cmd) | |
| if (installs): | |
| cmd = "apt-get install " + " ".join(installs) | |
| print(cmd) | |
| if ARGS.act: | |
| os.system("sudo %s -y "%cmd) | |
| else: | |
| exit(1) |