@@ -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