Files
2026-08-17 17:43:54 +08:00

259 lines
7.7 KiB
Python

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)