pthbs_genpkgpy

Template engine for producing packages for pthbs written using Python and Jinja
git clone https://ccx.te2000.cz/git/pthbs_genpkgpy
Log | Files | Refs | README

commit 2457481a7ebee7bf69b149d3632af2c3c7b3bd62
parent ff2f68d689487276ee746194af022a6b90942068
Author: Jan Pobrislo <ccx@te2000.cz>
Date:   Mon, 15 Dec 2025 02:49:16 +0000

Handle hashes/paths for namedenvs correctly

Diffstat:
Mgenpkg.py | 51+++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 41 insertions(+), 10 deletions(-)

diff --git a/genpkg.py b/genpkg.py @@ -114,12 +114,35 @@ def _skip_package(*args, **kwargs): raise SkipPackageException(*args, **kwargs) -def to_install_name(name, hash): +def to_install_name(name, pkg_hash, env_hash=None): rootname = name.split(":")[0] if rootname.endswith('.environment'): - return "env.%s" % (hash,) + if env_hash is None: + raise RuntimeError("can't derive namedenv hash without data") + return "env." + env_hash else: - return "%s.%s" % (rootname, hash) + return "%s.%s" % (rootname, pkg_hash) + + +def parse_package_deps(script_data): + lines = script_data.split(b'\n') + assert lines[0].startswith(b"#!") + for line in lines[1:]: + if line == b'': + return + elif line.startswith(b'#@'): + pass + elif line.startswith(b'#+'): + yield line[2:] + else: + raise ValueError(line) + + +def package_env_hash(script_data): + deps = sorted(d + b'\n' for d in parse_package_deps(script_data)) + if not deps: + return None + return hashlib.sha256(b''.join(deps)).hexdigest() class Main: @@ -157,6 +180,7 @@ class Main: self.env.globals["setitem"] = operator.setitem self.env.filters["shesc"] = lambda s: "'%s'" % s.replace("'", r"'\''") self.package_hashes = {} + self.package_buildenv_hashes = {} self.rendering = [] self.deps = {} @@ -197,16 +221,22 @@ class Main: return hashlib.sha256(envlist.encode()).hexdigest() def pkg_sha256(self, name): + return self.pkg_sha256_env_sha256(name)[0] + + def pkg_sha256_env_sha256(self, name): current = self.rendering[-1] if current not in self.deps: self.deps[current] = set((name,)) else: self.deps[current].add(name) - return self._pkg_sha256(name) + return self._pkg_sha256_env_sha256(name) + + def _pkg_sha256(self, name, *args, **kwargs): + return self._pkg_sha256_env_sha256(name, *args, **kwargs)[0] - def _pkg_sha256(self, name, error_on_skip=True): + def _pkg_sha256_env_sha256(self, name, error_on_skip=True): if name in self.package_hashes: - return self.package_hashes[name] + return (self.package_hashes[name], self.package_buildenv_hashes[name]) if name in self.rendering: raise RuntimeError("circular dependency: %r", self.rendering) @@ -231,6 +261,7 @@ class Main: out_path.unlink() raise self.package_hashes[name] = hashlib.sha256(data).hexdigest() + self.package_buildenv_hashes[name] = package_env_hash(data) lastname = self.rendering.pop() assert name == lastname @@ -243,10 +274,10 @@ class Main: tmp_path.write_bytes(data) tmp_path.replace(out_path) - return self.package_hashes[name] + return (self.package_hashes[name], self.package_buildenv_hashes[name]) def pkg_install_name(self, name): - return to_install_name(name, self.pkg_sha256(name)) + return to_install_name(name, *self.pkg_sha256_env_sha256(name)) def pkg_install_dir(self, name): return os.path.join( @@ -277,7 +308,7 @@ class Main: print("digraph G {") for pkgname in self.list_packages(): try: - pkghash = self._pkg_sha256(pkgname, False) + fullname = to_install_name(pkgname, *self._pkg_sha256_env_sha256(pkgname, False)) except SkipPackageException as e: print("// [SKIPPED: %s] %s" % (pkgname, e)) continue @@ -287,7 +318,7 @@ class Main: % ( pkgname, "note" if pkgname.endswith('.environment') else "box", - to_install_name(pkgname, pkghash), + fullname, ) ) for dep in sorted(self.deps.get(pkgname, ())):