import argparse import importlib import os import shutil import sys import typing import hooks import lib.arch import lib.atombuild import lib.make import lib.packie import lib.pkgcomposer import lib.sources os.chdir(os.path.dirname(__file__)) sys.path.append(os.path.abspath("lib")) argparser = argparse.ArgumentParser( description="SemiOS source package repository helper" ) argparser.add_argument( "--target", type=str, help="Target architecture to build the package for" ) argparser.add_argument("--atombuild", action="store_true", help="Enable Atom Build") subparsers = argparser.add_subparsers(dest="subcommand") parser_build = subparsers.add_parser("build") parser_build.add_argument("BUILD_PKGNAME") parser_clean = subparsers.add_parser("clean") parser_clean.add_argument("CLEAN_PKGNAME", nargs="*") parser_clean.add_argument("--all", action="store_true") parser_clean.add_argument("--no-artifacts", action="store_true") parser_list = subparsers.add_parser("list") parser_list.add_argument("ITEM", choices=("all", "built", "new")) parser_repo_push = subparsers.add_parser("repo-push") parser_repo_push.add_argument("REPO_DIR") parser_repo_push.add_argument("REPO_PUSH_PKGNAME", nargs="*") args = argparser.parse_args() if args.target: lib.arch.set_target(args.target) else: lib.arch.set_target(lib.arch.get_target()) def run_hooks(map, arg: typing.Any = None): current_dir = os.getcwd() for n in map.keys(): if n in lib.make._blocked_hooks: continue if arg: map[n](arg) else: map[n]() os.chdir(current_dir) def cmd_build_package(package: str): try: os.chdir(f"packages/{package}") os.makedirs("target", exist_ok=True) except Exception: print(f"No such package {package}") exit(1) package_dir = os.getcwd() importlib.import_module(f"packages.{package}.pkgbuild") # Check architecture support if not lib.make._supported_arch(lib.arch.get_target()): print(f"Architecture {lib.arch.get_target()} is not supported for this package") exit(1) if os.environ.get("SEMIOS_PKGBUILD_IN_ATOMIC", "0") == "1": lib.packie.install(lib.make._builddep) # Run `pre_build` hooks run_hooks(hooks.pre_build) # Build the package if lib.make._on_build: os.chdir(lib.sources.sources_dir_name()) lib.make._on_build() else: print("on_build(): Not defined") # Run `post_build` hooks run_hooks(hooks.post_build) # Pack packages for pkgname in lib.make._pkginfo.keys(): lib.make._current_pkgname = pkgname if pkgname == lib.make._key_global: continue pkginfo = lib.make._pkginfo[pkgname] pkgver = pkginfo[lib.make._key_version] if pkginfo.get(lib.make._key_arch_any): pkgarch = "any" else: pkgarch = lib.arch.get_target() pkgfilename = f"{pkgname}={pkgver}@{pkgarch}" composer = lib.pkgcomposer.PkgComposer( f"{package_dir}/target/{pkgfilename}.pkg" ) composer.setworkdir(f"{package_dir}/target/{pkgfilename}") pkginfo[lib.make._key_on_pack](composer) # Run post_pack hooks run_hooks(hooks.post_pack, composer) manifest = { "name": pkgname, "version": pkgver, "arch": pkgarch, "description": pkginfo[lib.make._key_description], "maintainers": pkginfo[lib.make._key_maintainers], "dependencies": pkginfo[lib.make._key_dependencies], "provides": pkginfo[lib.make._key_provides], "recommendations": pkginfo[lib.make._key_recommendations], } composer.write_manifest(manifest) composer.write_links(pkginfo[lib.make._key_links]) composer.compose() # Build success with open(f"{package_dir}/target/build-ok.tag", "wt+") as file: file.write("OK") def cmd_clean_package(package: list[str]): for i in package: targetdir = f"packages/{i}/target" if not os.path.exists(targetdir): continue if args.no_artifacts: for file in os.listdir(targetdir): path = f"{targetdir}/{file}" if file.endswith(".pkg") or file == "build-ok.tag": continue if os.path.isfile(path) or os.path.islink(path): os.remove(path) else: shutil.rmtree(path) else: shutil.rmtree(targetdir) def do_list(item: str): if item == "all": for i in os.listdir("packages"): if i.startswith("."): continue yield i elif item == "built": for i in os.listdir("packages"): if i.startswith("."): continue if os.path.exists(f"packages/{i}/target/build-ok.tag"): yield i elif item == "new": for i in os.listdir("packages"): if i.startswith("."): continue try: pkgbuild_mtime = os.path.getmtime(f"packages/{i}/pkgbuild.py") target_mtime = os.path.getmtime(f"packages/{i}/target/build-ok.tag") if target_mtime < pkgbuild_mtime: yield i except Exception: yield i def cmd_list(item): for i in do_list(item): print(i) def cmd_build_atom(pkgname: str): # Declare necessary paths repo_root = os.getcwd() package_dir = f"{repo_root}/packages/{pkgname}" target_dir = f"{package_dir}/target" build_env_root = f"{target_dir}/atombuild_root" # Read `pkgbuild.py` of that package lib.make._in_atombuild = True try: os.chdir(package_dir) os.makedirs(target_dir, exist_ok=True) except Exception: print(f"No such package {pkgname}") exit(1) importlib.import_module(f"packages.{pkgname}.pkgbuild") os.chdir(repo_root) # Initialize build environment lib.atombuild.prepare_build_env(build_env_root, lib.make._builddep) lib.atombuild.copy_pkgbuild_tree(repo_root, pkgname, build_env_root) lib.atombuild.enter_build_env( build_env_root, ["./x", "--target", lib.arch.get_target(), "build", pkgname], chdir="/Atom", ) # Copy artifacts atom_target_dir = f"{build_env_root}/Atom/packages/{pkgname}/target" try: for i in os.listdir(atom_target_dir): if i.endswith(".pkg"): shutil.copy2(f"{atom_target_dir}/{i}", f"{target_dir}/{i}") except Exception: pass # Build success with open(f"{target_dir}/build-ok.tag", "wt+") as file: file.write("OK") def cmd_repo_push(repo_dir: str, pkgname: list[str]): for pkg in pkgname: targetdir = f"packages/{pkg}/target" if not os.path.exists(targetdir): print(f"error: failed to add '{pkg}': package is not built") continue for target_file in os.listdir(targetdir): if not target_file.endswith(".pkg"): continue try: lib.packie.repo_add(repo_dir, f"{targetdir}/{target_file}") except: print(f"error: failed to add '{pkg}': see the output above") if args.subcommand == "build": if args.atombuild: cmd_build_atom(args.BUILD_PKGNAME) else: cmd_build_package(args.BUILD_PKGNAME) elif args.subcommand == "clean": if args.all: pkgs = os.listdir("packages") else: pkgs = args.CLEAN_PKGNAME cmd_clean_package(pkgs) elif args.subcommand == "list": cmd_list(args.ITEM) elif args.subcommand == "repo-push": cmd_repo_push(args.REPO_DIR, args.REPO_PUSH_PKGNAME) else: print("error: no action specified", file=sys.stderr) exit(1)