diff --git a/hooks/autostrip.py b/hooks/autostrip.py index 8f93261..19deb12 100644 --- a/hooks/autostrip.py +++ b/hooks/autostrip.py @@ -1,6 +1,8 @@ import os import stat import subprocess +import tempfile +import shutil from lib import common @@ -13,6 +15,8 @@ def _is_elf(filepath): def autostrip(composer): + processed_inodes = {} + for ent in common.treedir(composer.workdir): if not ent.is_file(follow_symlinks=False): continue @@ -20,7 +24,36 @@ def autostrip(composer): continue if not _is_elf(ent.path): continue - oldperm = stat.S_IMODE(os.stat(ent.path).st_mode) - os.chmod(ent.path, 0o777) - subprocess.run([strip, ent.path], check=True) - os.chmod(ent.path, oldperm) + + stat_info = os.stat(ent.path) + inode_key = (stat_info.st_dev, stat_info.st_ino) + if inode_key in processed_inodes: + continue + processed_inodes[inode_key] = True + + oldperm = stat.S_IMODE(stat_info.st_mode) + + try: + with tempfile.NamedTemporaryFile(mode='wb', delete=False) as tmp_file: + tmp_path = tmp_file.name + shutil.copy2(ent.path, tmp_path) + os.chmod(tmp_path, 0o777) + + subprocess.run([strip, tmp_path], check=True) + + with open(tmp_path, 'rb') as tmp_file: + stripped_data = tmp_file.read() + + with open(ent.path, 'r+b') as original_file: + original_file.truncate(0) + original_file.write(stripped_data) + original_file.flush() + os.fsync(original_file.fileno()) + + os.chmod(ent.path, oldperm) + os.unlink(tmp_path) + + except Exception as e: + if 'tmp_path' in locals() and os.path.exists(tmp_path): + os.unlink(tmp_path) + raise RuntimeError(f"Failed to strip {ent.path}: {e}") from e diff --git a/lib/atombuild.py b/lib/atombuild.py index 86f9796..d75108c 100644 --- a/lib/atombuild.py +++ b/lib/atombuild.py @@ -13,8 +13,11 @@ BASE_REQUIREMENTS = [ # Packages for running `semios-packages` scripts "python", "packie", - "patch", "zstd", + "libarchive-tools", + # Packages for building packages that require patching + "patch", + # Packages for downloading various formats of tarballs "libz-ng", "liblzma", "libbzip2", @@ -92,32 +95,20 @@ def enter_build_env(root: str, cmd: list[str], chdir: str = "/"): subprocess.run( [ "bwrap", - "--bind", - root, - "/", + "--bind", root, "/", "--unshare-pid", "--unshare-user", - "--uid", - "0", - "--gid", - "0", - "--dev", - "/dev", - "--bind", - "/sys", - "/sys", - "--proc", - "/proc", + "--uid", "0", + "--gid", "0", + "--dev", "/dev", + "--bind", "/sys", "/sys", + "--proc", "/proc", "--clearenv", - "--setenv", - "HOME", - "/home/root", - "--setenv", - "PATH", - "/bin", - "--setenv", - "SEMIOS_PKGBUILD_IN_ATOMIC", - "1", + "--setenv", "HOME", "/home/root", + "--setenv", "PATH", "/bin", + "--setenv", "SEMIOS_PKGBUILD_IN_ATOMIC", "1", + "--setenv", "USER", "root", + "--setenv", "LOGNAME", "root", "--chdir", chdir, ] diff --git a/lib/pkgcomposer.py b/lib/pkgcomposer.py index 28aace4..0de456e 100644 --- a/lib/pkgcomposer.py +++ b/lib/pkgcomposer.py @@ -4,17 +4,10 @@ import shutil import subprocess 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 + self.pkgfile = os.path.abspath(pkgfile) def setworkdir(self, workdir: str): self.workdir = workdir @@ -33,8 +26,16 @@ class PkgComposer: f.write("\n") def compose(self): - shutil.make_archive(self.pkgfile, _archive_format, self.workdir) - shutil.move(self.pkgfile + _archive_suffix, self.pkgfile) + subprocess.run( + [ + "tar", "cpf", f"{self.pkgfile}.tar", + "-C", self.workdir, + "--numeric-owner", + ".", + ], + check=True, + ) + subprocess.run(["zstd", "--rm", "-f", f"{self.pkgfile}.tar", "-o", self.pkgfile], check=True) def makedir(self, name: str): os.mkdir(f"{self.workdir}/bundle/{name}")