From: Daan De Meyer Date: Wed, 5 Mar 2025 14:15:07 +0000 (+0100) Subject: Sort packages during parsing X-Git-Tag: v26~328^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=60f65e2c72e4d8cb0392cbb289312ef73fa499db;p=thirdparty%2Fmkosi.git Sort packages during parsing --- diff --git a/mkosi/config.py b/mkosi/config.py index 112f5edfc..152b75715 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -1060,12 +1060,23 @@ def config_make_enum_matcher(type: type[SE]) -> ConfigMatchCallback[SE]: return config_match_enum +def package_sort_key(package: str) -> tuple[int, str]: + """Sorts packages: normal first, paths second, conditional third""" + + if package.startswith("("): + return 2, package + elif package.startswith("/"): + return 1, package + return 0, package + + def config_make_list_parser( *, delimiter: Optional[str] = None, parse: Callable[[str], T] = str, # type: ignore # see mypy#3737 unescape: bool = False, reset: bool = True, + key: Optional[Callable[[T], Any]] = None, ) -> ConfigParseCallback[list[T]]: def config_parse_list(value: Optional[str], old: Optional[list[T]]) -> Optional[list[T]]: new = old.copy() if old else [] @@ -1090,7 +1101,12 @@ def config_make_list_parser( if reset and len(values) == 1 and values[0] == "": return None - return new + [parse(v) for v in values if v] + new += [parse(v) for v in values if v] + + if key: + new.sort(key=key) + + return new return config_parse_list @@ -2719,7 +2735,7 @@ SETTINGS: list[ConfigSetting[Any]] = [ long="--package", metavar="PACKAGE", section="Content", - parse=config_make_list_parser(delimiter=","), + parse=config_make_list_parser(delimiter=",", key=package_sort_key), help="Add an additional package to the OS image", ), ConfigSetting( @@ -2727,7 +2743,7 @@ SETTINGS: list[ConfigSetting[Any]] = [ long="--build-package", metavar="PACKAGE", section="Content", - parse=config_make_list_parser(delimiter=","), + parse=config_make_list_parser(delimiter=",", key=package_sort_key), help="Additional packages needed for build scripts", ), ConfigSetting( @@ -2735,7 +2751,7 @@ SETTINGS: list[ConfigSetting[Any]] = [ long="--volatile-package", metavar="PACKAGE", section="Content", - parse=config_make_list_parser(delimiter=","), + parse=config_make_list_parser(delimiter=",", key=package_sort_key), help="Packages to install after executing build scripts", ), ConfigSetting( diff --git a/mkosi/distributions/arch.py b/mkosi/distributions/arch.py index cd9a81f50..382742c25 100644 --- a/mkosi/distributions/arch.py +++ b/mkosi/distributions/arch.py @@ -12,7 +12,6 @@ from mkosi.distributions import DistributionInstaller, PackageType from mkosi.installer import PackageManager from mkosi.installer.pacman import Pacman, PacmanRepository from mkosi.log import complete_step, die -from mkosi.util import sort_packages class Installer(DistributionInstaller): @@ -70,7 +69,7 @@ class Installer(DistributionInstaller): Pacman.invoke( context, "--sync", - ["--needed", "--assume-installed", "initramfs", *sort_packages(packages)], + ["--needed", "--assume-installed", "initramfs", *packages], apivfs=apivfs, ) diff --git a/mkosi/distributions/opensuse.py b/mkosi/distributions/opensuse.py index 17c6c253b..7ecc38020 100644 --- a/mkosi/distributions/opensuse.py +++ b/mkosi/distributions/opensuse.py @@ -16,7 +16,6 @@ from mkosi.installer.zypper import Zypper from mkosi.log import die from mkosi.mounts import finalize_certificate_mounts from mkosi.run import run -from mkosi.util import sort_packages class Installer(DistributionInstaller): @@ -70,17 +69,17 @@ class Installer(DistributionInstaller): [ "--download", "in-advance", "--recommends" if context.config.with_recommends else "--no-recommends", - *sort_packages(packages), + *packages, ], apivfs=apivfs, ) # fmt: skip else: - Dnf.invoke(context, "install", sort_packages(packages), apivfs=apivfs) + Dnf.invoke(context, "install", packages, apivfs=apivfs) @classmethod def remove_packages(cls, context: Context, packages: Sequence[str]) -> None: if context.config.find_binary("zypper"): - Zypper.invoke(context, "remove", ["--clean-deps", *sort_packages(packages)], apivfs=True) + Zypper.invoke(context, "remove", ["--clean-deps", *packages], apivfs=True) else: Dnf.invoke(context, "remove", packages, apivfs=True) diff --git a/mkosi/util.py b/mkosi/util.py index b21ed689e..fe8c8006e 100644 --- a/mkosi/util.py +++ b/mkosi/util.py @@ -99,13 +99,6 @@ def format_rlimit(rlimit: int) -> str: return f"{soft}:{hard}" -def sort_packages(packages: Iterable[str]) -> list[str]: - """Sorts packages: normal first, paths second, conditional third""" - - m = {"(": 2, "/": 1} - return sorted(packages, key=lambda name: (m.get(name[0], 0), name)) - - def flatten(lists: Iterable[Iterable[T]]) -> list[T]: """Flatten a sequence of sequences into a single list.""" return list(itertools.chain.from_iterable(lists)) diff --git a/tests/test_config.py b/tests/test_config.py index 46c32c12e..d822da9fc 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -100,8 +100,8 @@ def test_parse_config(tmp_path: Path) -> None: Architecture=arm64 Repositories=epel,epel-next - [Content] - Packages=abc + [Config] + Profiles=abc [Build] Environment=MY_KEY=MY_VALUE @@ -120,7 +120,7 @@ def test_parse_config(tmp_path: Path) -> None: assert config.distribution == Distribution.ubuntu assert config.architecture == Architecture.arm64 - assert config.packages == ["abc"] + assert config.profiles == ["abc"] assert config.output_format == OutputFormat.cpio assert config.image_id == "base" @@ -163,8 +163,8 @@ def test_parse_config(tmp_path: Path) -> None: [Distribution] Distribution=debian - [Content] - Packages=qed + [Config] + Profiles=qed def [Output] @@ -175,13 +175,13 @@ def test_parse_config(tmp_path: Path) -> None: ) with chdir(d): - _, [config] = parse_config(["--package", "last"]) + _, [config] = parse_config(["--profile", "last"]) # Setting a value explicitly in a dropin should override the default from mkosi.conf. assert config.distribution == Distribution.debian # Lists should be merged by appending the new values to the existing values. Any values from the CLI # should be appended to the values from the configuration files. - assert config.packages == ["abc", "qed", "def", "last"] + assert config.profiles == ["abc", "qed", "def", "last"] assert config.output_format == OutputFormat.cpio assert config.image_id == "00-dropin" assert config.image_version == "0" @@ -329,7 +329,7 @@ def test_parse_includes_once(tmp_path: Path) -> None: with chdir(d): _, [config] = parse_config(["--include", "abc.conf", "--include", "abc.conf"]) - assert config.build_packages == ["def", "abc"] + assert config.build_packages == ["abc", "def"] (d / "mkosi.images").mkdir()