From 93e94b63436cfc3b2ff02a8ef56f9dd11f3a1804 Mon Sep 17 00:00:00 2001 From: Georges Discry Date: Thu, 20 Apr 2023 22:09:58 +0200 Subject: [PATCH] Apply path expansion when parsing When the `extra_search_paths` configuration was introduced, it would perform path expansions with the environment variables (using $) and the home directories (starting with ~). Home directories would not be expanded when mkosi was run with sudo or pkexec. Instead, `$SUDO_HOME` could be used but only when run with sudo or pkexec. However, those expansions were not applied to other paths in the configuration and were broken with the rewrite of the configuration loading, as the parser would check if the paths exist before expanding. Those expansions are now handled directly in the parser and are performed before validation. Environment variables expansion is enabled for all paths and home directory expansion is enabled for all paths on the host. Furthermore, home directory expansion is always available, with `~` expanding to the user's home directory when sudo or pkexec are used (and not `/root`), replacing the need for `$SUDO_HOME`. --- mkosi/__init__.py | 27 --------------------------- mkosi/config.py | 25 ++++++++++++++++++++----- 2 files changed, 20 insertions(+), 32 deletions(-) diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 36f3635bb..e9bdf0998 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -15,7 +15,6 @@ import os import platform import resource import shutil -import string import subprocess import sys import tempfile @@ -1105,8 +1104,6 @@ def load_args(args: argparse.Namespace) -> MkosiConfig: find_image_version(args) - args.extra_search_paths = expand_paths(args.extra_search_paths) - if args.cmdline and args.verb not in MKOSI_COMMANDS_CMDLINE: die(f"Parameters after verb are only accepted for {list_to_string(verb.name for verb in MKOSI_COMMANDS_CMDLINE)}.") @@ -2335,30 +2332,6 @@ def bump_image_version(config: MkosiConfig) -> None: Path("mkosi.version").write_text(new_version + "\n") -def expand_paths(paths: Sequence[str]) -> list[Path]: - if not paths: - return [] - - environ = os.environ.copy() - # Add a fake SUDO_HOME variable to allow non-root users specify - # paths in their home when using mkosi via sudo. - sudo_user = os.getenv("SUDO_USER") - if sudo_user and "SUDO_HOME" not in environ: - environ["SUDO_HOME"] = os.path.expanduser(f"~{sudo_user}") - - # No os.path.expandvars because it treats unset variables as empty. - expanded = [] - for path in paths: - if not sudo_user: - path = os.path.expanduser(path) - try: - expanded += [Path(string.Template(str(path)).substitute(environ))] - except KeyError: - # Skip path if it uses a variable not defined. - pass - return expanded - - @contextlib.contextmanager def prepend_to_environ_path(paths: Sequence[Path]) -> Iterator[None]: if not paths: diff --git a/mkosi/config.py b/mkosi/config.py index 9be1f54c9..8b059cfc4 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -4,7 +4,7 @@ import dataclasses import enum import fnmatch import functools -import os +import os.path import platform import sys import textwrap @@ -19,6 +19,7 @@ from mkosi.backend import ( OutputFormat, Verb, chdir, + current_user, detect_distribution, flatten, ) @@ -45,9 +46,19 @@ def parse_boolean(s: str) -> bool: die(f"Invalid boolean literal: {s!r}") -def parse_path(value: str, *, required: bool, absolute: bool = True) -> Path: +def parse_path(value: str, *, required: bool, absolute: bool = True, expanduser: bool = True, expandvars: bool = True) -> Path: + if expandvars: + value = os.path.expandvars(value) + path = Path(value) + if expanduser: + user = current_user() + if path.is_relative_to("~") and not user.is_running_user(): + path = user.home / path.relative_to("~") + else: + path = path.expanduser() + if required and not path.exists(): die(f"{value} does not exist") @@ -61,7 +72,7 @@ def parse_source_target_paths(value: str) -> tuple[Path, Optional[Path]]: src, _, target = value.partition(':') src_path = parse_path(src, required=True) if target: - target_path = parse_path(target, required=False, absolute=False) + target_path = parse_path(target, required=False, absolute=False, expanduser=False) if not target_path.is_absolute(): die("Target path must be absolute") else: @@ -213,15 +224,17 @@ def config_make_list_parser(delimiter: str, parse: Callable[[str], Any] = str) - return config_parse_list -def make_path_parser(*, required: bool, absolute: bool = True) -> Callable[[str], Path]: +def make_path_parser(*, required: bool, absolute: bool = True, expanduser: bool = True, expandvars: bool = True) -> Callable[[str], Path]: return functools.partial( parse_path, required=required, absolute=absolute, + expanduser=expanduser, + expandvars=expandvars, ) -def config_make_path_parser(*, required: bool, absolute: bool = True) -> ConfigParseCallback: +def config_make_path_parser(*, required: bool, absolute: bool = True, expanduser: bool = True, expandvars: bool = True) -> ConfigParseCallback: def config_parse_path(dest: str, value: Optional[str], namespace: argparse.Namespace) -> Optional[Path]: if dest in namespace: return getattr(namespace, dest) # type: ignore @@ -231,6 +244,8 @@ def config_make_path_parser(*, required: bool, absolute: bool = True) -> ConfigP value, required=required, absolute=absolute, + expanduser=expanduser, + expandvars=expandvars, ) return None -- 2.47.2