@@ -0,0 +1,5 @@
|
||||
/packages/*/target
|
||||
__pycache__
|
||||
/.vscode
|
||||
/.idea
|
||||
/.zed
|
||||
@@ -0,0 +1,9 @@
|
||||
from typing import Callable, TypeAlias
|
||||
|
||||
from . import autostrip
|
||||
|
||||
PostBuild: TypeAlias = Callable[[], None]
|
||||
|
||||
post_build: dict[str, PostBuild] = {
|
||||
"autostrip": autostrip.autostrip,
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
def autostrip():
|
||||
pass
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import os
|
||||
|
||||
from . import packie
|
||||
|
||||
all: dict[str, dict[str, str]] = {
|
||||
"aarch64-semios-linux": {},
|
||||
}
|
||||
_target: str = packie.host_arch()
|
||||
|
||||
|
||||
def get_target():
|
||||
return _target
|
||||
|
||||
|
||||
def set_target(arch: str):
|
||||
global _target
|
||||
_target = arch
|
||||
for key, val in all[_target]:
|
||||
os.environ[key] = val
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from . import make as libmake
|
||||
from . import pkgcomposer
|
||||
|
||||
|
||||
def configure(rem: list[str] = []):
|
||||
subprocess.run(["./configure"] + rem, check=True)
|
||||
|
||||
|
||||
def make(rem: list[str] = []):
|
||||
subprocess.run(["make", f"-j{os.cpu_count()}"] + rem, check=True)
|
||||
|
||||
|
||||
def make_install(rem: list[str] | None = None, chdir: bool = True):
|
||||
default_rem = ["DESTDIR=" + os.getcwd() + "/../cpp_install"]
|
||||
subprocess.run(["make", "install"] + (rem or default_rem), check=True)
|
||||
if rem is None and chdir:
|
||||
os.chdir("../cpp_install")
|
||||
|
||||
|
||||
def _do_auto_pack(pc: pkgcomposer.PkgComposer, srcdir: str, dstdir: str, filter):
|
||||
pc.makedir(srcdir)
|
||||
with os.scandir(srcdir) as entries:
|
||||
for ent in entries:
|
||||
if filter(ent):
|
||||
if ent.is_dir(follow_symlinks=False):
|
||||
pc.makedir(f"{dstdir}/{ent.name}")
|
||||
else:
|
||||
pc.addfile(ent.path, f"{dstdir}/{ent.name}")
|
||||
|
||||
|
||||
def _autopack_filter_lib(ent) -> bool:
|
||||
if ent.name.endswith(".o") or ent.name.endswith(".a"):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _autopack_filter_bin(ent) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
def _autopack_filter_dev(ent):
|
||||
if ".so" in ent.name:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _auto_pack(profiles: list[str], pc: pkgcomposer.PkgComposer):
|
||||
if "lib" in profiles:
|
||||
_do_auto_pack(pc, "lib", "lib", _autopack_filter_lib)
|
||||
if "bin" in profiles:
|
||||
_do_auto_pack(pc, "bin", "bin", _autopack_filter_bin)
|
||||
_do_auto_pack(pc, "sbin", "bin", _autopack_filter_bin)
|
||||
if "dev" in profiles:
|
||||
_do_auto_pack(pc, "lib", "lib", _autopack_filter_dev)
|
||||
_do_auto_pack(pc, "include", "include", _autopack_filter_dev)
|
||||
|
||||
|
||||
def use_auto_pack(profiles: list[str]):
|
||||
libmake.on_pack(lambda pc: _auto_pack(profiles, pc))
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
import typing
|
||||
|
||||
from . import pkgcomposer, sources
|
||||
|
||||
_key_global = "@global"
|
||||
_key_version = "version"
|
||||
_key_description = "description"
|
||||
_key_on_pack = "on_pack"
|
||||
_key_arch_any = "arch_any"
|
||||
|
||||
_current_pkgname: str = _key_global
|
||||
_pkginfo: dict[str, dict[str, typing.Any]] = {
|
||||
_key_global: {},
|
||||
}
|
||||
_supported_arch: typing.Callable[[str], bool] = lambda x: True
|
||||
_on_build: typing.Callable[[], None] | None = None
|
||||
|
||||
_blocked_hooks: list[str] = []
|
||||
|
||||
|
||||
def package(s: str):
|
||||
global _current_pkgname
|
||||
_current_pkgname = s
|
||||
_pkginfo[s] = _pkginfo[_key_global].copy()
|
||||
|
||||
|
||||
def version(s: str):
|
||||
_pkginfo[_current_pkgname][_key_version] = s
|
||||
|
||||
|
||||
def description(s: str):
|
||||
_pkginfo[_current_pkgname][_key_description] = s
|
||||
|
||||
|
||||
def arch_any():
|
||||
_pkginfo[_current_pkgname][_key_arch_any] = True
|
||||
|
||||
|
||||
def supported_arch(s: list[str] | typing.Callable[[str], bool]):
|
||||
global _supported_arch
|
||||
if isinstance(s, list):
|
||||
_supported_arch = lambda arch: arch in s
|
||||
else:
|
||||
_supported_arch = s
|
||||
|
||||
|
||||
def on_build(func: typing.Callable[[], None]):
|
||||
global _on_build
|
||||
_on_build = func
|
||||
|
||||
|
||||
def on_pack(func: typing.Callable[[pkgcomposer.PkgComposer], None]):
|
||||
_pkginfo[_current_pkgname][_key_on_pack] = func
|
||||
|
||||
|
||||
def block_hook(hook: str):
|
||||
_blocked_hooks.append(hook)
|
||||
|
||||
|
||||
def source_url(url: str):
|
||||
sources.source_url(url)
|
||||
@@ -0,0 +1,11 @@
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
PACKIE_EXEC = os.getenv("PACKIE", "packie")
|
||||
|
||||
def host_arch() -> str:
|
||||
result = subprocess.run(
|
||||
[PACKIE_EXEC, "print", "profile.host_arch"],
|
||||
check=True, capture_output=True,
|
||||
)
|
||||
return result.stdout.decode().strip()
|
||||
@@ -0,0 +1,39 @@
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
if sys.version_info >= (3, 14):
|
||||
_archive_format = "zstdtar"
|
||||
_archive_suffix = ".tar.zst"
|
||||
else:
|
||||
_archive_format = "gztar"
|
||||
_archive_suffix = ".tar.gz"
|
||||
|
||||
|
||||
class PkgComposer:
|
||||
def __init__(self, pkgfile: str):
|
||||
self.pkgfile = pkgfile
|
||||
|
||||
def setworkdir(self, workdir: str):
|
||||
self.workdir = workdir
|
||||
shutil.rmtree(workdir, ignore_errors=True)
|
||||
os.mkdir(workdir)
|
||||
os.mkdir(f"{workdir}/bundle")
|
||||
|
||||
def write_manifest(self, manifest: dict):
|
||||
with open(self.workdir + "/PkgManifest.json", "w") as f:
|
||||
json.dump(manifest, f, indent=4)
|
||||
|
||||
def compose(self):
|
||||
shutil.make_archive(self.pkgfile, _archive_format, self.workdir)
|
||||
shutil.move(self.pkgfile + _archive_suffix, self.pkgfile)
|
||||
|
||||
def makedir(self, name: str):
|
||||
os.mkdir(f"{self.workdir}/bundle/{name}")
|
||||
|
||||
def addfile(self, src: str, dst: str):
|
||||
shutil.copy2(src, f"{self.workdir}/bundle/{dst}", follow_symlinks=False)
|
||||
|
||||
def add_dir(self, src: str, dst: str, merge: bool = False):
|
||||
shutil.copytree(src, f"{self.workdir}/bundle/{dst}", dirs_exist_ok=merge)
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
import os
|
||||
import sys
|
||||
import tarfile
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
|
||||
def filename(url):
|
||||
parsed = urllib.parse.urlparse(url)
|
||||
path = parsed.path
|
||||
filename = os.path.basename(path)
|
||||
|
||||
if not filename:
|
||||
raise ValueError("No filename found in URL")
|
||||
|
||||
return filename
|
||||
|
||||
|
||||
def download(url, output):
|
||||
last_percent = -1
|
||||
|
||||
def report_progress(percent):
|
||||
nonlocal last_percent
|
||||
if percent != last_percent:
|
||||
if last_percent >= 0:
|
||||
sys.stdout.write("\b" * len(str(last_percent)))
|
||||
sys.stdout.write(str(percent))
|
||||
sys.stdout.flush()
|
||||
last_percent = percent
|
||||
|
||||
try:
|
||||
req = urllib.request.Request(url, method="GET")
|
||||
req.add_header(
|
||||
"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
||||
)
|
||||
|
||||
with urllib.request.urlopen(req) as response:
|
||||
total_size = response.length
|
||||
if total_size is None or total_size <= 0:
|
||||
print("Downloading...")
|
||||
with open(output, "wb") as f:
|
||||
while True:
|
||||
chunk = response.read(8192)
|
||||
if not chunk:
|
||||
break
|
||||
f.write(chunk)
|
||||
print("Download completed: " + output)
|
||||
return output
|
||||
|
||||
sys.stdout.write("downloading... 0%")
|
||||
sys.stdout.flush()
|
||||
|
||||
with open(output, "wb") as f:
|
||||
downloaded = 0
|
||||
block_size = 8192
|
||||
|
||||
while True:
|
||||
chunk = response.read(block_size)
|
||||
if not chunk:
|
||||
break
|
||||
f.write(chunk)
|
||||
downloaded += len(chunk)
|
||||
percent = int(downloaded * 100 / total_size)
|
||||
report_progress(percent)
|
||||
|
||||
if last_percent != 100:
|
||||
report_progress(100)
|
||||
|
||||
sys.stdout.write("\n")
|
||||
|
||||
print("Download completed: " + output)
|
||||
return output
|
||||
|
||||
except Exception as e:
|
||||
if os.path.exists(output):
|
||||
os.remove(output)
|
||||
raise Exception("Download failed: " + str(e))
|
||||
|
||||
|
||||
def tar_common_root(tar: tarfile.TarFile) -> str | None:
|
||||
root = None
|
||||
for member in tar.getmembers():
|
||||
this_root = member.path.split("/")[0]
|
||||
if root is None:
|
||||
root = this_root
|
||||
if this_root != root:
|
||||
return None
|
||||
return root
|
||||
|
||||
|
||||
def sources_dir_name() -> str:
|
||||
with open("./target/sources.tag") as file:
|
||||
return file.read()
|
||||
|
||||
|
||||
def source_url(url: str):
|
||||
if os.path.exists("./target/sources.tag"):
|
||||
return
|
||||
download_path = f"./target/{filename(url)}"
|
||||
download(url, download_path)
|
||||
|
||||
with tarfile.open(download_path, "r") as tar:
|
||||
common_root = tar_common_root(tar)
|
||||
extract_dir = "./target"
|
||||
sources_dir = f"./target/{common_root}"
|
||||
if common_root in ["", ".", "None"]:
|
||||
extract_dir = "./target/sources"
|
||||
sources_dir = "./target/sources"
|
||||
tar.extractall(extract_dir)
|
||||
with open("./target/sources.tag", "wt+") as file:
|
||||
file.write(sources_dir)
|
||||
@@ -0,0 +1,21 @@
|
||||
from lib.cpp import *
|
||||
from lib.make import *
|
||||
|
||||
source_url("https://gitea.semilabs.org/semios/semi-libc/archive/v1.2.5.tar.gz")
|
||||
version("1.2.5")
|
||||
|
||||
|
||||
def build():
|
||||
configure(["--prefix=/"])
|
||||
make()
|
||||
make_install()
|
||||
|
||||
|
||||
on_build(build)
|
||||
|
||||
|
||||
package("semi-libc")
|
||||
use_auto_pack(["lib"])
|
||||
|
||||
package("semi-libc-dev")
|
||||
use_auto_pack(["dev"])
|
||||
@@ -0,0 +1,102 @@
|
||||
import argparse
|
||||
import importlib
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
import hooks
|
||||
import lib.arch
|
||||
import lib.make
|
||||
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("--build", type=str, help="Package to build")
|
||||
argparser.add_argument("--clean", type=str, help="Package to clean")
|
||||
args = argparser.parse_args()
|
||||
|
||||
if args.target:
|
||||
lib.arch.set_target(args.target)
|
||||
else:
|
||||
lib.arch.set_target(lib.arch.get_target())
|
||||
|
||||
|
||||
def run_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)
|
||||
|
||||
# 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
|
||||
for n in hooks.post_build.keys():
|
||||
if n in lib.make._blocked_hooks:
|
||||
continue
|
||||
hooks.post_build[n]()
|
||||
|
||||
# Pack packages
|
||||
for pkgname in lib.make._pkginfo.keys():
|
||||
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)
|
||||
|
||||
manifest = {
|
||||
"name": pkgname,
|
||||
"version": pkgver,
|
||||
"arch": pkgarch,
|
||||
}
|
||||
composer.write_manifest(manifest)
|
||||
composer.compose()
|
||||
|
||||
|
||||
def run_clean_package(package: str):
|
||||
try:
|
||||
shutil.rmtree(f"packages/{package}/target")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
if args.build:
|
||||
run_build_package(args.build)
|
||||
if args.clean:
|
||||
run_clean_package(args.clean)
|
||||
Reference in New Issue
Block a user