From ed9d952d882ce8313dc4cb5049ca352f5b90a0c4 Mon Sep 17 00:00:00 2001 From: "Jannis M. Hoffmann" Date: Thu, 7 Nov 2024 21:16:38 +0100 Subject: improve install script and systemd-sysusers support --- script/install.py | 160 ++++++++++++++++++++++++++++++++++++++++++------ script/jwebmail.conf.in | 1 + 2 files changed, 142 insertions(+), 19 deletions(-) create mode 100644 script/jwebmail.conf.in diff --git a/script/install.py b/script/install.py index 64a8f7b..86501d1 100644 --- a/script/install.py +++ b/script/install.py @@ -1,33 +1,155 @@ #!/usr/bin/env python3 +import argparse +import os import re -import sys -from pathlib import Path +import subprocess +from pathlib import Path, PurePath -def install_service_unit(prefix): - project_path = Path(__file__).parents[1] +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--destdir", default="/", type=Path) + ap.add_argument("--confdir", type=PurePath) + ap.add_argument("--statedir", type=PurePath) + ap.add_argument("--bindir", type=PurePath) + ap.add_argument("--datadir", type=PurePath) + ap.add_argument("--unitdir", type=PurePath) + ap.add_argument("--sysusersdir", type=PurePath) + ap.add_argument("--is-systemd", action="store_true", default=None) + ap.add_argument("--no-run", action="store_true") + ap.add_argument("prefix", choices=["home", "system", "usr", "usr/local"]) - if prefix == "usr": - install_path = Path("/etc/systemd/system") - elif prefix == "usr/local": - install_path = Path("/usr/local/lib/systemd/system") + vals = ap.parse_args() + + if not vals.destdir.is_absolute(): + raise ValueError(f"destdir={destdir} must be absolute") + + if vals.is_systemd is None: + vals.is_systemd = "systemd" in str(Path("/sbin/init").resolve()) + + conf = vars(vals) + for key, val in list(conf.items()): + if val is None: + del conf[key] + + if vals.prefix == "home": + user = os.env["USER"] + confdir = conf.setdefault("confdir", PurePath(f"home/{user}/.config/jwebmail")) + statedir = conf.setdefault( + "statedir", PurePath(f"home/{user}/.local/state/jwebmail") + ) + bindir = conf.setdefault("bindir", PurePath(f"home/{user}/.local/bin")) + datadir = conf.setdefault( + "datadir", PurePath(f"home/{user}/.local/share/jwebmail") + ) + unitdir = conf.setdefault( + "unitdir", PurePath(f"home/{user}/.config/systemd/user") + ) + sysusersdir = None + + (vals.destdir / confdir).mkdir(0o755, exist_ok=True, parents=True) + (vals.destdir / statedir).mkdir(0o700, exist_ok=True) + (vals.destdir / datadir).mkdir(0o755, exist_ok=True) + elif vals.prefix == "system": + confdir = conf.setdefault("confdir", PurePath("etc/jwebmail")) + statedir = conf.setdefault("statedir", PurePath("var/jwebmail")) + bindir = conf.setdefault("bindir", PurePath("usr/bin")) + datadir = conf.setdefault("datadir", PurePath("usr/share/jwebmail")) + unitdir = conf.setdefault("unitdir", PurePath("etc/systemd/system")) + sysusersdir = conf.setdefault("sysusersdir", PurePath("etc/sysusers.d")) + + (vals.destdir / confdir).mkdir(0o755, exist_ok=True, parents=True) + (vals.destdir / statedir.parent).mkdir(0o755, exist_ok=True, parents=True) + (vals.destdir / statedir).mkdir(0o750, exist_ok=True) + (vals.destdir / datadir).mkdir(0o755, exist_ok=True, parents=True) + (vals.destdir / unitdir).mkdir(0o755, exist_ok=True, parents=True) + (vals.destdir / sysusersdir).mkdir(0o755, exist_ok=True, parents=True) + elif vals.prefix == "usr": + confdir = conf.setdefault("confdir", PurePath("etc/jwebmail")) + statedir = conf.setdefault("statedir", PurePath("var/lib/jwebmail")) + bindir = conf.setdefault("bindir", PurePath("usr/bin")) + datadir = conf.setdefault("datadir", PurePath("usr/share/jwebmail")) + unitdir = conf.setdefault("unitdir", PurePath("usr/lib/systemd/system")) + sysusersdir = conf.setdefault("sysusersdir", PurePath("usr/lib/sysusers.d")) + + (vals.destdir / confdir).mkdir(0o755, exist_ok=True, parents=True) + (vals.destdir / statedir.parent).mkdir(0o755, exist_ok=True, parents=True) + (vals.destdir / statedir).mkdir(0o750, exist_ok=True) + (vals.destdir / datadir).mkdir(0o755, exist_ok=True, parents=True) + (vals.destdir / unitdir).mkdir(0o755, exist_ok=True, parents=True) + (vals.destdir / sysusersdir).mkdir(0o755, exist_ok=True, parents=True) + elif vals.prefix == "usr/local": + confdir = conf.setdefault("confdir", PurePath("usr/local/etc/jwebmail")) + statedir = conf.setdefault("statedir", PurePath("var/local/lib/jwebmail")) + bindir = conf.setdefault("bindir", PurePath("usr/local/bin")) + datadir = conf.setdefault("datadir", PurePath("usr/local/share/jwebmail")) + unitdir = conf.setdefault("unitdir", PurePath("usr/local/lib/systemd/system")) + sysusersdir = conf.setdefault( + "sysusersdir", PurePath("usr/local/lib/sysusers.d") + ) + + (vals.destdir / confdir).mkdir(0o755, exist_ok=True, parents=True) + (vals.destdir / statedir.parent).mkdir(0o755, exist_ok=True, parents=True) + (vals.destdir / statedir).mkdir(0o750, exist_ok=True) + (vals.destdir / datadir).mkdir(0o755, exist_ok=True, parents=True) + (vals.destdir / unitdir).mkdir(0o755, exist_ok=True, parents=True) + (vals.destdir / sysusersdir).mkdir(0o755, exist_ok=True, parents=True) else: - raise Exception("first arg must be one of `usr` or `usr/local`") + raise ValueError( + "first arg must be one of `home`, `system`, `usr` or `usr/local`" + ) + + try: + if vals.is_systemd: + install_service_unit( + "script/jwebmail.service.in", + vals.destdir / unitdir, + str(vals.destdir / confdir), + str(vals.destdir / bindir), + vals.no_run, + ) + + if vals.is_systemd and vals.prefix != "home": + install_jwebmail_user( + "script/jwebmail.conf.in", + vals.destdir / sysusersdir, + str(vals.destdir / statedir), + vals.no_run, + ) + except subprocess.CalledProcessError: + os.exit("A command failed to execute. Is systemd installed? Try running with `--no-run`.") + + +def substitute_file(in_file, out_path, variables): + in_file_content = open(in_file).read() + out_file_content = re.sub( + r"@(\w+)@", lambda match: variables[match[1]], in_file_content, flags=re.ASCII + ) + open(out_path / Path(in_file).name.removesuffix(".in"), mode="w").write( + out_file_content + ) - def substitute(match): - if match[1] == "PROJECT_PATH": - return str(project_path) - else: - raise KeyError(match[1]) - service_text_in = open(project_path / "script" / "jwebmail.service.in").read() - service_text = re.sub(r"@(\w+)@", substitute, service_text_in, flags=re.ASCII) +def install_jwebmail_user(in_file, out_path, statedir, no_run): + substitute_file( + in_file, + out_path, + dict(STATEDIR=statedir), + ) + if not no_run: + subprocess.run("systemd-sysusers", check=True) - install_path.mkdir(0o755, True, True) - open(install_path / "jwebmail.service", mode="w").write(service_text) +def install_service_unit(in_file, out_path, confdir, bindir): + substitute_file( + in_file, + out_path, + dict(CONFDIR=confdir, BINDIR=bindir), + ) + if not no_run: + subprocess.run(["systemctl", "daemon-reload"], check=True) if __name__ == "__main__": - install_service_unit(sys.argv[1] if len(sys.argv) == 2 else "") + main() diff --git a/script/jwebmail.conf.in b/script/jwebmail.conf.in new file mode 100644 index 0000000..f5580af --- /dev/null +++ b/script/jwebmail.conf.in @@ -0,0 +1 @@ +u jwebmail - "greetd greeter user" @STATEDIR@ -- cgit v1.2.3