From f03c7f6e1d95727569afcf96ea3ef4d8594cd6e5 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 7 Apr 2023 15:32:56 +0200 Subject: [PATCH] Add PathExists= match It's also useful to be able to match against stuff that isn't the current configuration. Let's add a PathExists= match that is satisfied when the given path exists. This will be useful in systemd where we conditionally build a kernel if mkosi.kernel/ exists in the top level repo directory. With this setting, we can only install the necessary packages to build the kernel if the mkosi.kernel/ path actually exists. --- mkosi.md | 6 ++++++ mkosi/config.py | 56 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/mkosi.md b/mkosi.md index 6d9309566..f9f9e4741 100644 --- a/mkosi.md +++ b/mkosi.md @@ -226,6 +226,12 @@ a boolean argument: either "1", "yes", or "true" to enable, or "0", is used and no distribution has been explicitly configured yet, the host distribution and release are used. +`PathExists=` + +: This condition is satisfied if the given path exists. Relative paths are + interpreted relative to the parent directory of the config file that the + condition is read from. + ### [Distribution] Section `Distribution=`, `--distribution=`, `-d` diff --git a/mkosi/config.py b/mkosi/config.py index 4597c2406..82d7ce6d2 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -224,6 +224,10 @@ def config_make_path_parser(required: bool) -> ConfigParseCallback: return config_parse_path +def match_path_exists(path: Path, value: str) -> bool: + return path.parent.joinpath(value).exists() + + @dataclasses.dataclass(frozen=True) class MkosiConfigSetting: dest: str @@ -240,6 +244,12 @@ class MkosiConfigSetting: object.__setattr__(self, 'name', ''.join(x.capitalize() for x in self.dest.split('_') if x)) +@dataclasses.dataclass(frozen=True) +class MkosiMatch: + name: str + match: Callable[[Path, str], bool] + + class CustomHelpFormatter(argparse.HelpFormatter): def _format_action_invocation(self, action: argparse.Action) -> str: if not action.option_strings or action.nargs == 0: @@ -690,8 +700,16 @@ class MkosiConfigParser: ), ) + MATCHES = ( + MkosiMatch( + name="PathExists", + match=match_path_exists, + ), + ) + def __init__(self) -> None: - self.lookup = {s.name: s for s in self.SETTINGS} + self.settings_lookup = {s.name: s for s in self.SETTINGS} + self.match_lookup = {m.name: m for m in self.MATCHES} def parse_config(self, path: Path, namespace: argparse.Namespace) -> None: extras = path.is_dir() @@ -714,32 +732,34 @@ class MkosiConfigParser: if "Match" in parser.sections(): for k, v in parser.items("Match"): - if not (s := self.lookup.get(k)): - die(f"Unknown setting {k}") + if (s := self.settings_lookup.get(k)): + if not (match := s.match): + die(f"{k} cannot be used in [Match]") - if not (match := s.match): - die(f"{k} cannot be used in [Match]") + # If we encounter a setting in [Match] that has not been explicitly configured yet, we assign + # it it's default value first so that we can [Match] on default values for settings. + if s.dest not in namespace: + if s.default_factory: + default = s.default_factory(namespace) + elif s.default is None: + default = s.parse(s.dest, None, namespace) + else: + default = s.default - # If we encounter a setting in [Match] that has not been explicitly configured yet, we assign - # it it's default value first so that we can [Match] on default values for settings. - if s.dest not in namespace: - if s.default_factory: - default = s.default_factory(namespace) - elif s.default is None: - default = s.parse(s.dest, None, namespace) - else: - default = s.default + setattr(namespace, s.dest, default) - setattr(namespace, s.dest, default) + if not match(s.dest, v, namespace): + return - if not match(s.dest, v, namespace): - return + elif (m := self.match_lookup.get(k)): + if not m.match(path, v): + return parser.remove_section("Match") for section in parser.sections(): for k, v in parser.items(section): - if not (s := self.lookup.get(k)): + if not (s := self.settings_lookup.get(k)): die(f"Unknown setting {k}") setattr(namespace, s.dest, s.parse(s.dest, v, namespace)) -- 2.47.2