return result
+def config_parse_profile(value: Optional[str], old: Optional[int] = None) -> Optional[str]:
+ if not value:
+ return None
+
+ if not is_valid_filename(value):
+ die(f"{value!r} is not a valid profile",
+ hint="Profile= or --profile= requires a name with no path components.")
+
+ return value
+
+
@dataclasses.dataclass(frozen=True)
class MkosiConfigSetting:
dest: str
access the value from state.
"""
+ profile: Optional[str]
include: tuple[str, ...]
presets: tuple[str, ...]
dependencies: tuple[str, ...]
parse=config_make_list_parser(delimiter=",", reset=False, parse=make_path_parser()),
help="Include configuration from the specified file or directory",
),
+ MkosiConfigSetting(
+ dest="profile",
+ section="Config",
+ help="Build the specified profile",
+ parse=config_parse_profile,
+ match=config_make_string_matcher(),
+ ),
MkosiConfigSetting(
dest="presets",
long="--preset",
return triggered is not False
- def parse_config(path: Path, namespace: argparse.Namespace, defaults: argparse.Namespace) -> bool:
+ def parse_config(
+ path: Path,
+ namespace: argparse.Namespace,
+ defaults: argparse.Namespace,
+ profiles: bool = False,
+ ) -> bool:
s: Optional[MkosiConfigSetting] # Make mypy happy
extras = path.is_dir()
with parse_new_includes(namespace, defaults):
setattr(ns, s.dest, s.parse(v, getattr(ns, s.dest, None)))
+ if profiles:
+ finalize_default(SETTINGS_LOOKUP_BY_DEST["profile"], namespace, defaults)
+ profile = getattr(namespace, "profile")
+ immutable_settings.add("Profile")
+
+ if profile:
+ for p in (profile, f"{profile}.conf"):
+ p = Path("mkosi.profiles") / p
+ if p.exists():
+ break
+ else:
+ die(f"Profile '{profile}' not found in mkosi.profiles/")
+
+ setattr(namespace, "profile", profile)
+
+ with chdir(p if p.is_dir() else Path.cwd()):
+ parse_config(p if p.is_file() else Path("."), namespace, defaults)
+
if extras and (path.parent / "mkosi.conf.d").exists():
for p in sorted((path.parent / "mkosi.conf.d").iterdir()):
if p.is_dir() or p.suffix == ".conf":
include = ()
if args.directory is not None:
- parse_config(Path("."), namespace, defaults)
+ parse_config(Path("."), namespace, defaults, profiles=True)
finalize_default(SETTINGS_LOOKUP_BY_DEST["presets"], namespace, defaults)
include = getattr(namespace, "presets")
{bold(f"PRESET: {config.preset or 'default'}")}
{bold("CONFIG")}:
+ Profile: {none_to_none(config.profile)}
Include: {line_join_list(config.include)}
{bold("PRESET")}:
### [Match] Section.
+`Profile=`
+
+: Matches against the configured profile.
+
`Distribution=`
: Matches against the configured distribution.
| Matcher | Globs | Rich Comparisons | Default |
|-------------------|-------|------------------|-------------------------|
+| `Profile=` | no | no | match fails |
| `Distribution=` | no | no | match host distribution |
| `Release=` | no | no | match host release |
| `Architecture=` | no | no | match host architecture |
### [Config] Section
+`Profile=`, `--profile=`
+
+: Select the given profile. A profile is a configuration file or
+ directory in the `mkosi.profiles/` directory. When selected, this
+ configuration file or directory is included after parsing the
+ `mkosi.conf` file, but before any `mkosi.conf.d/*.conf` drop in
+ configuration.
+
`Include=`, `--include=`
: Include extra configuration from the given file or directory. The
assert config.split_artifacts is False
+def test_profiles(tmp_path: Path) -> None:
+ d = tmp_path
+
+ (d / "mkosi.profiles").mkdir()
+ (d / "mkosi.profiles/profile.conf").write_text(
+ """\
+ [Distribution]
+ Distribution=fedora
+
+ [Host]
+ QemuKvm=yes
+ """
+ )
+
+ (d / "mkosi.conf").write_text(
+ """\
+ [Config]
+ Profile=profile
+ """
+ )
+
+ (d / "mkosi.conf.d").mkdir()
+ (d / "mkosi.conf.d/abc.conf").write_text(
+ """\
+ [Distribution]
+ Distribution=debian
+ """
+ )
+
+ with chdir(d):
+ _, [config] = parse_config()
+
+ assert config.profile == "profile"
+ # mkosi.conf.d/ should override the profile
+ assert config.distribution == Distribution.debian
+ assert config.qemu_kvm == ConfigFeature.enabled
+
+
def test_parse_load_verb(tmp_path: Path) -> None:
with chdir(tmp_path):
assert parse_config(["build"])[0].verb == Verb.build