summaryrefslogtreecommitdiff
path: root/hiccup.py
diff options
context:
space:
mode:
authorseth <[email protected]>2022-08-21 13:14:00 -0400
committerseth <[email protected]>2022-08-21 13:15:45 -0400
commita615f6cc4901a05f7fe72a55d005280119cb792e (patch)
tree0f3ddc4ac0a27e3a0077e0b79082df17a4e6e5b9 /hiccup.py
parenta2ff6e94b6ba21818613611cb3fed15e56f4894d (diff)
refactor and (try to) follow PEP518
Diffstat (limited to 'hiccup.py')
-rwxr-xr-xhiccup.py170
1 files changed, 170 insertions, 0 deletions
diff --git a/hiccup.py b/hiccup.py
new file mode 100755
index 0000000..b3f2120
--- /dev/null
+++ b/hiccup.py
@@ -0,0 +1,170 @@
+#!/usr/bin/env python3
+import argparse
+import json
+import subprocess # nosec:b404
+import os
+
+CONFIG_FILE = os.path.join(os.environ["XDG_CONFIG_HOME"], "hiccup/config.json")
+OS_RELEASE_PATH = "/etc/os-release"
+
+
+class DistroNotSupportedError(Exception):
+ def __init__(self, name):
+ self.message = "{} isn't supported yet".format(name)
+ super().__init__(self.message)
+
+
+class Distro:
+ def __init__(self, id: str, config_file: os.path):
+ try:
+ # read and store commands from config file
+ with open(config_file) as file:
+ data = json.load(file)
+ self.__system_update_cmds = data["system_update_cmds"]
+ self.__extra_cmds = data["extra_cmds"]
+ self.__clean_cmds = data["clean_cmds"]
+ self.__shell_plugin_cmds = data["shell_plugin_cmds"]
+ self.__other_cmds = data["other_cmds"]
+ except OSError:
+ raise OSError("no config file found!")
+ except json.JSONDecodeError:
+ raise json.JSONDecodeError("unable to parse json")
+
+ self.id = id
+
+ # get commands specific to current distro
+ if self.is_supported():
+ self.update_cmd = self.get_update_cmd()
+ if self.has_clean_cmd():
+ self.clean_cmd = self.get_clean_cmd()
+ if self.has_extra_cmd():
+ self.extra_cmd = self.get_extra_cmd()
+ else:
+ raise DistroNotSupportedError(self.id)
+
+ def __get_cmd(self, dct: dict):
+ return dct[self.id]
+
+ # wrapper for subprocess.run that allows for easy privlage escalation,
+ # silencing, and variable shells
+ def __sys_cmd(self, cmd: str, shell="bash", silent=False, sudo=False):
+ args = list()
+ if silent:
+ cmd += " > /dev/null 2>&1"
+ if sudo:
+ args += ["/usr/bin/sudo"]
+
+ args += [shell, "-c", cmd]
+
+ return subprocess.run(args, check=True) # nosec:B603
+
+ # iterate through dict of commands, optionally allow for keys to
+ # determine the shell the command is run though
+ def __run_items(self, msg: str, dct: dict, name_as_shell=False):
+ shell = "bash"
+ for name, cmd in dct.items():
+ print(msg.format(name))
+
+ if name_as_shell:
+ shell = name
+ self.__sys_cmd(cmd, shell=shell, silent=True) # nosec:B604
+
+ def is_supported(self):
+ return self.id in self.__system_update_cmds
+
+ def has_clean_cmd(self):
+ return self.id in self.__clean_cmds
+
+ def has_extra_cmd(self):
+ return self.id in self.__extra_cmds
+
+ def get_update_cmd(self):
+ return self.__get_cmd(self.__system_update_cmds)
+
+ def get_extra_cmd(self):
+ return self.__get_cmd(self.__extra_cmds)
+
+ def get_clean_cmd(self):
+ return self.__get_cmd(self.__clean_cmds)
+
+ def update_system(self):
+ self.__sys_cmd(self.update_cmd, sudo=True)
+ if self.has_extra_cmd():
+ self.__sys_cmd(self.extra_cmd)
+
+ def cleanup_system(self):
+ if self.has_clean_cmd():
+ print("cleaning up system...")
+ return self.__sys_cmd(self.clean_cmd, sudo=True)
+ print("no cleanup command found for {}".format(self.id))
+
+ def update_shell_plugins(self):
+ msg = "updating {} plugins..."
+ return self.__run_items(msg, self.__shell_plugin_cmds, name_as_shell=True)
+
+ def update_other(self):
+ msg = "updating {}..."
+ return self.__run_items(msg, self.__other_cmds)
+
+ def update_all(self):
+ self.update_system()
+ self.update_shell_plugins()
+ self.update_other()
+ self.cleanup_system()
+
+
+# reads id from an os-release file
+def get_distro_id(filename: os.path):
+ with open(filename) as file:
+ for line in file.readlines():
+ k, v = line.strip().split("=")
+ if k == "ID":
+ return v
+
+
+def run():
+ try:
+ current_distro = get_distro_id(OS_RELEASE_PATH)
+ except DistroNotSupportedError:
+ pass
+ distro = Distro(current_distro, CONFIG_FILE)
+
+ parser = argparse.ArgumentParser(
+ description="a python script to help keep you up to date"
+ )
+ parser.add_argument(
+ "--cleanonly",
+ "-c",
+ action="store_true",
+ default=False,
+ dest="clean_only",
+ help="cleanup unneeded dependencies",
+ )
+ parser.add_argument(
+ "--systemonly",
+ "-s",
+ action="store_true",
+ default=False,
+ dest="system_only",
+ help="only update through the system's package manager",
+ )
+ args = parser.parse_args()
+
+ if args.clean_only:
+ return distro.cleanup_system()
+ if args.system_only:
+ return distro.update_system()
+
+ return distro.update_all()
+
+
+if __name__ == "__main__":
+ if os.geteuid() == 0:
+ print("please don't run this as root :(")
+ exit(1)
+ try:
+ run()
+ print("done!")
+ except Exception as e:
+ print(repr(e))
+ exit(2)