From 76b0c0ffa7626b93c563ade4163b7aa8b239372b Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Sat, 20 Dec 2025 11:10:52 +1100 Subject: [PATCH 1/9] set default preserve_buildroot value ("on-error") when creating Pool obj --- pool_bin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pool_bin b/pool_bin index fbfd182..4014428 100755 --- a/pool_bin +++ b/pool_bin @@ -101,7 +101,7 @@ def pool_get( strict: bool = False, quiet: bool = False, tree: bool = False, - preserve_buildroot: str | None = None, + preserve_buildroot: str = "on-error", source: bool = False, ) -> NoReturn: logger.debug( From e5ec8b16c6b0b80d9da85757155610c2b8dffca8 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Sat, 20 Dec 2025 15:30:20 +1100 Subject: [PATCH 2/9] add support for pool without buildroot --- pool_bin | 29 ++++++++++++++++++++++++++--- pool_lib/__init__.py | 12 +++++++++--- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/pool_bin b/pool_bin index 4014428..55d7087 100755 --- a/pool_bin +++ b/pool_bin @@ -393,10 +393,10 @@ def pool_info( pool_info(function, recursive, subpool) -def pool_init(buildroot: str) -> None: +def pool_init(buildroot: str | None) -> None: logger.debug(f"pool_init({buildroot=})") try: - Pool.init_create(os.path.abspath(buildroot)) + Pool.init_create(buildroot) except PoolError as e: if DEBUG: raise e @@ -675,7 +675,20 @@ def main() -> None: formatter_class=argparse.RawDescriptionHelpFormatter, epilog=env_vars, ) - parser_init.add_argument("buildroot", help="/path/to/build-chroot") + parser_init_conflicts = parser_init.add_mutually_exclusive_group() + parser_init_conflicts.add_argument( + "buildroot", + nargs="?", + default=None, + help="/path/to/build-chroot", + ) + parser_init_conflicts.add_argument( + "-N", + "--no-buildroot", + action="store_true", + help="create pool with no buildroot (for pool of pools or pre-built" + " packages)" + ) parser_init.set_defaults(func=pool_init) # pool-list @@ -743,6 +756,16 @@ def main() -> None: if args.cmd: func = args.func args_dict = vars(args) + if args.cmd == "init": + # argparse handles error if both buildroot and --no-buildroot, but + # to force user to make explicit choice, error if neither set + if args.buildroot is None and not args.no_buildroot: + fatal( + "pool-init requires one of /path/to/buildroot or" + " --no-buildroot" + ) + # if no_buildroot == True then buildroot is None + del args_dict["no_buildroot"] # only pass debug for pool-get if func.__name__ != "get" and "debug" in args: del args_dict["debug"] diff --git a/pool_lib/__init__.py b/pool_lib/__init__.py index ac4ed44..8a851df 100644 --- a/pool_lib/__init__.py +++ b/pool_lib/__init__.py @@ -1259,7 +1259,9 @@ def sort(self, key: Callable | None, reverse: bool = False) -> None: @classmethod def init_create( - cls: type["Pool"], buildroot: AnyPath, path: AnyPath | None = None + cls: type["Pool"], + buildroot: AnyPath | None, + path: AnyPath | None = None, ) -> "Pool": if path is None: cwd = os.getcwd() @@ -1280,7 +1282,7 @@ def init_create( if isdir(spath): raise PoolError("pool already initialized") - if not isdir(buildroot): + if buildroot is not None and not isdir(buildroot): raise PoolError(f"buildroot `{buildroot}' is not a directory") mkdir(path_stocks) @@ -1311,7 +1313,11 @@ def init_create( Git.set_gitignore(spath, ["tmp"]) - os.symlink(buildroot, path_build_root) + # if set, symlink path_build_root -> buildroot, otherwise touch + if buildroot is not None: + os.symlink(abspath(buildroot), path_build_root) + else: + open(path_build_root, "w").close() return cls(path) From 8b3d1e3375b5092adf3eddb5966f6f5014e8cf5b Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Sat, 20 Dec 2025 15:32:33 +1100 Subject: [PATCH 3/9] fix subcommand check that will never match (func.__name__ would be 'pool_get') --- pool_bin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pool_bin b/pool_bin index 55d7087..e8c7ce5 100755 --- a/pool_bin +++ b/pool_bin @@ -767,7 +767,7 @@ def main() -> None: # if no_buildroot == True then buildroot is None del args_dict["no_buildroot"] # only pass debug for pool-get - if func.__name__ != "get" and "debug" in args: + if args.cmd != "get" and "debug" in args: del args_dict["debug"] del args_dict["cmd"] del args_dict["func"] From 1126022238a405bcac2624cb915bee21ef435c1d Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Sat, 20 Dec 2025 15:33:31 +1100 Subject: [PATCH 4/9] remove errant whitespace --- pool_bin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pool_bin b/pool_bin index e8c7ce5..0b96bd5 100755 --- a/pool_bin +++ b/pool_bin @@ -464,7 +464,7 @@ def main() -> None: command = os.path.split(sys.argv[0])[-1] sys.argv[0] = PROG if command.startswith(PROG + "-"): - subcommand = command[len(PROG + "-") :] + subcommand = command[len(PROG + "-"):] sys.argv.insert(1, subcommand) env_vars = ( From 8f71bee2300007dabe19c5d530bb3a4d63524a4a Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Sat, 20 Dec 2025 16:07:23 +1100 Subject: [PATCH 5/9] if pool does not have buildroot; set PoolKernel.buildroot=None --- pool_lib/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pool_lib/__init__.py b/pool_lib/__init__.py index 8a851df..acff4a1 100644 --- a/pool_lib/__init__.py +++ b/pool_lib/__init__.py @@ -880,7 +880,12 @@ def __init__( if not exists(spath): raise PoolError(f"no pool found (POOL_DIR={self.path})") - self.buildroot = os.readlink(self.path_build_root) + self.buildroot: str | None + if islink(self.path_build_root): + self.buildroot = os.readlink(self.path_build_root) + else: + self.buildroot = None + self.pkgcache = PackageCache(self.path_pkgcache) self.stocks = Stocks( self.path_stocks, self.pkgcache, [*recursed_paths, self.path] From d9925b29f36a7d9463cf8543bd21804435baaabb Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Sat, 20 Dec 2025 16:10:57 +1100 Subject: [PATCH 6/9] Don't give stacktrace when pool CLI commands error --- pool_bin | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pool_bin b/pool_bin index 0b96bd5..cab0b0e 100755 --- a/pool_bin +++ b/pool_bin @@ -776,7 +776,10 @@ def main() -> None: fatal(f"{args.outputdir} does not exist") elif not isdir(args.outputdir): fatal(f"{args.outputdir} exists, but is not a directory") - func(**args_dict) + try: + func(**args_dict) + except PoolError as e: + fatal(e) else: fatal("Subcommand required.", parser.print_help) From dc2c18afd8f1b0e268bc22e9ec40c4ea344ad202 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Tue, 23 Dec 2025 08:16:06 +1100 Subject: [PATCH 7/9] As noted by @OnGle preserve_buildroot 'None' default reqd --- pool_bin | 2 +- pool_lib/__init__.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pool_bin b/pool_bin index cab0b0e..e3749df 100755 --- a/pool_bin +++ b/pool_bin @@ -101,7 +101,7 @@ def pool_get( strict: bool = False, quiet: bool = False, tree: bool = False, - preserve_buildroot: str = "on-error", + preserve_buildroot: str | None = None, source: bool = False, ) -> NoReturn: logger.debug( diff --git a/pool_lib/__init__.py b/pool_lib/__init__.py index acff4a1..89febdd 100644 --- a/pool_lib/__init__.py +++ b/pool_lib/__init__.py @@ -1327,7 +1327,9 @@ def init_create( return cls(path) def __init__( - self, path: AnyPath | None = None, preserve_buildroot: str = "on-error" + self, + path: AnyPath | None = None, + preserve_buildroot: str | None = "on-error", ) -> None: kernel = PoolKernel(path, preserve_buildroot=preserve_buildroot) if kernel.drop_privileges(pretend=True): From f96785abf3d17c627a773def0cb6e825478d9184 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Tue, 23 Dec 2025 08:28:26 +1100 Subject: [PATCH 8/9] rename 'set_deckdebuild_env()' -> read_pkg_deckdebuild_env()' Change function name to reflect what it does. --- pool_lib/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pool_lib/__init__.py b/pool_lib/__init__.py index 89febdd..9c0b69c 100644 --- a/pool_lib/__init__.py +++ b/pool_lib/__init__.py @@ -110,7 +110,7 @@ def parse_package_filename(filename: str) -> tuple[str, str]: return name, version -def set_deckdebuild_env(filename: str) -> dict[str, str]: +def read_pkg_deckdebuild_env(filename: str) -> dict[str, str]: """Read 'DECKDEBUILD_*' env vars from file. Return dict of 'DECKDEBUILD_*' values. Values are read from repo env file @@ -1037,7 +1037,9 @@ def _build_package_source( if source: args.append("--build-source") # read DECKDEBUILD_ENV if it exists, but existing env takes precidence - build_env = set_deckdebuild_env(join(source_path, "DECKDEBUILD_ENV")) + build_env = read_pkg_deckdebuild_env( + join(source_path, "DECKDEBUILD_ENV") + ) with in_dir(source_path): command = [ "/usr/bin/deckdebuild", From dc327eb5e83228947544b4423c340d1ffa5dbfba Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Tue, 23 Dec 2025 08:37:48 +1100 Subject: [PATCH 9/9] Error if trying to build pkg in pool without buildroot --- pool_lib/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pool_lib/__init__.py b/pool_lib/__init__.py index 9c0b69c..ea06925 100644 --- a/pool_lib/__init__.py +++ b/pool_lib/__init__.py @@ -1019,6 +1019,11 @@ def resolve(self, unresolved: RS) -> RS: def _build_package_source( self, source_path: str, name: str, version: str, source: bool = False ) -> None: + if self.buildroot is None: + raise PoolError( + "Cannot build a package in a pool without a buildroot" + " configured" + ) build_outputdir = tempfile.mkdtemp( dir=self.path_tmp, prefix=f"{name}-{version}." )