#!/usr/bin/env python3.11 import os import pickle import subprocess import sys import tempfile ERIS_PATH = os.path.realpath(os.path.join(os.path.dirname(__file__), "..")) def cmd(command): subprocess.run(command, shell=True, check=True) def all_paths(path): for entry in os.scandir(path): if entry.is_dir(follow_symlinks=False): yield from all_paths(entry.path) else: yield entry.path def relative_paths(root_path, paths): root_len = len(root_path) for path in paths: yield "." + path[root_len:] def make_sub_container(src_root, dest_root, paths): for path in paths: dest_path = os.path.join(dest_root, path) os.makedirs(os.path.dirname(dest_path), exist_ok=True) os.link(os.path.join(src_root, path), dest_path) def filter_paths(paths, exclusions): return [path for path in paths if all(excluded not in path for excluded in exclusions)] def run_in_container(container, command): option = "--directory" if os.path.isdir(container) else "--image" cmd(f"sudo systemd-nspawn --quiet --chdir=/eris --overlay={ERIS_PATH}:" f'/eris {option}={container} /bin/bash --login -c "{command}"') def build_ubuntu(): cmd("sudo debootstrap --components=main,restricted,universe,multiverse " "jammy ubuntu.part http://au.archive.ubuntu.com/ubuntu/") run_in_container("ubuntu.part", "ln -sf /lib/systemd/resolv.conf /etc/resolv.conf") os.rename("ubuntu.part", "ubuntu") def make_ubuntu_base(): if os.path.exists("base_paths"): with open("base_paths", "rb") as file_: base_paths = pickle.load(file_) else: build_ubuntu() base_paths = relative_paths("ubuntu", all_paths("ubuntu")) base_paths = filter_paths(base_paths, ["python3"]) with open("base_paths", "wb") as file_: pickle.dump(base_paths, file_) return base_paths def make_app_dir(app_dir, new_paths): os.mkdir(app_dir) make_sub_container("ubuntu", app_dir, new_paths) cmd(f"cp {ERIS_PATH}/packaging/appimage/* {app_dir}") def cleanup_app_dir(app_dir): cmd(f"rm -rf {app_dir}/usr/share/go*") cmd(f"rm -rf {app_dir}/usr/lib/go*") cmd(f"rm -rf {app_dir}/root") def make_appimage(app_dir): cmd("wget --continue https://github.com/AppImage/AppImageKit/releases/" "download/13/appimagetool-x86_64.AppImage") cmd("chmod +x appimagetool-x86_64.AppImage") cmd("ARCH=x86_64 ./appimagetool-x86_64.AppImage --comp xz " + app_dir) def main(work_path): assert os.getuid() == 0 and os.getgid() == 0, "Need to be root." os.chdir(work_path) base_paths = make_ubuntu_base() run_in_container("ubuntu", "./install") post_install_paths = relative_paths("ubuntu", all_paths("ubuntu")) new_paths = set(post_install_paths) - set(base_paths) new_paths = filter_paths(new_paths, ["/var/cache/apt/archives", "lto1"]) app_dir = "eris.AppDir" if os.path.exists(app_dir): cmd("sudo rm -rf " + app_dir) make_app_dir(app_dir, new_paths) cleanup_app_dir(app_dir) make_appimage(app_dir) if __name__ == "__main__": work_path = tempfile.mkdtemp(prefix="make-appimage-") if len(sys.argv) == 1 else sys.argv[1] main(work_path)