Files
ports/x.py
2026-09-30 06:32:54 +00:00

286 lines
8.7 KiB
Python

import argparse
import importlib
import os
import shutil
import sys
import typing
import hooks
import lib
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="*")
parser_vendor_src = subparsers.add_parser("vendor-src")
parser_vendor_src.add_argument("REPO_DIR")
parser_vendor_src.add_argument("VENDOR_PKGNAME")
args = argparser.parse_args()
if args.target:
lib.arch.set_target(args.target)
else:
lib.arch.set_target(lib.arch.get_target())
def load_pkgbuild(pkgname):
# Declare necessary paths
repo_root = os.getcwd()
package_dir = f"{repo_root}/packages/{pkgname}"
target_dir = f"{package_dir}/target"
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)
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)
# 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])
for i in pkginfo[lib.make._key_configure]:
composer.add_configure(i)
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._dry_run = True
load_pkgbuild(pkgname)
# 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")
def cmd_vendor_src(repo_dir, pkgname):
package_dir = f"{os.getcwd()}/packages/{pkgname}"
target_dir = f"{package_dir}/target"
lib.make._dry_run = True
load_pkgbuild(pkgname)
if lib.make._managed_source_url is None:
print(f"error: '{pkgname}' declared not managed sources")
exit(1)
os.chdir(package_dir)
from_path = lib.managed_source.create_srcpkg(
lib.make._managed_source_url,
lib.make._managed_source_postprocess,
)
filename = lib.managed_source.get_repo_filename(lib.make._managed_source_url)
to_path = f"{repo_dir}/{filename}"
shutil.copy2(from_path, to_path)
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)
elif args.subcommand == "vendor-src":
cmd_vendor_src(args.REPO_DIR, args.VENDOR_PKGNAME)
else:
print("error: no action specified", file=sys.stderr)
exit(1)