258 lines
7.7 KiB
Python
258 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],
|
|
"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)
|