From: Joerg Behrmann Date: Fri, 21 Apr 2023 20:54:26 +0000 (+0200) Subject: Make InvokingUser just a namespace for functions X-Git-Tag: v15~199^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4eac4ce2b51d1ef43c5cf25aae9224e2529b2464;p=thirdparty%2Fmkosi.git Make InvokingUser just a namespace for functions The sequence of calls to the underlying functions remains the same, but it's shorter and there are no intermediate dataclass instance constructed. --- diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 929141bc5..a99b86fd1 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -44,10 +44,10 @@ from mkosi.types import PathString from mkosi.util import ( Compression, Distribution, + InvokingUser, ManifestFormat, OutputFormat, Verb, - current_user, flatten, format_rlimit, patch_file, @@ -1722,7 +1722,7 @@ def run_shell(config: MkosiConfig) -> None: cmdline += ["--"] cmdline += config.cmdline - uid = current_user().uid + uid = InvokingUser.uid() if config.output_format == OutputFormat.directory: acl_toggle_remove(config, config.output, uid, allow=False) @@ -2065,7 +2065,7 @@ def bump_image_version(config: MkosiConfig) -> None: def expand_specifier(s: str) -> str: - return s.replace("%u", current_user().name) + return s.replace("%u", InvokingUser.name()) def needs_build(config: Union[argparse.Namespace, MkosiConfig]) -> bool: diff --git a/mkosi/config.py b/mkosi/config.py index eb086f2eb..a24f2f69c 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -23,11 +23,11 @@ from mkosi.run import run from mkosi.util import ( Compression, Distribution, + InvokingUser, ManifestFormat, OutputFormat, Verb, chdir, - current_user, detect_distribution, flatten, is_apt_distribution, @@ -64,11 +64,9 @@ def parse_path(value: str, *, required: bool, absolute: bool = True, expanduser: 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 path.is_relative_to("~") and not InvokingUser.is_running_user(): + path = InvokingUser.home() / path.relative_to("~") + path = path.expanduser() if required and not path.exists(): die(f"{value} does not exist") diff --git a/mkosi/run.py b/mkosi/run.py index aaa0b0135..32853070a 100644 --- a/mkosi/run.py +++ b/mkosi/run.py @@ -17,7 +17,7 @@ from typing import Any, Callable, Mapping, Optional, Sequence, Type, TypeVar from mkosi.log import ARG_DEBUG, ARG_DEBUG_SHELL, die from mkosi.types import _FILE, CompletedProcess, PathString, Popen -from mkosi.util import current_user +from mkosi.util import InvokingUser CLONE_NEWNS = 0x00020000 CLONE_NEWUSER = 0x10000000 @@ -69,8 +69,7 @@ def become_root() -> tuple[int, int]: The function returns the UID-GID pair of the invoking user in the namespace (65436, 65436). """ if os.getuid() == 0: - user = current_user() - return user.uid, user.gid + return InvokingUser.uid_gid() subuid = read_subrange(Path("/etc/subuid")) subgid = read_subrange(Path("/etc/subgid")) diff --git a/mkosi/util.py b/mkosi/util.py index 5caeb6644..dedf5728d 100644 --- a/mkosi/util.py +++ b/mkosi/util.py @@ -2,7 +2,6 @@ import ast import contextlib -import dataclasses import enum import functools import getpass @@ -221,49 +220,36 @@ def flatten(lists: Iterable[Iterable[T]]) -> list[T]: return list(itertools.chain.from_iterable(lists)) -@dataclasses.dataclass class InvokingUser: - _pw: Optional[pwd.struct_passwd] = None + @staticmethod + def _uid_from_env() -> Optional[str]: + return os.getenv("SUDO_UID") or os.getenv("PKEXEC_UID") @classmethod - def for_uid(cls, uid: int) -> "InvokingUser": - return cls(pwd.getpwuid(uid)) - - @property - def uid(self) -> int: - if self._pw is not None: - return self._pw.pw_uid - return os.getuid() - - @property - def gid(self) -> int: - if self._pw is not None: - return self._pw.pw_gid - return os.getgid() - - @property - def name(self) -> str: - if self._pw is not None: - return self._pw.pw_name - return getpass.getuser() + def uid(cls) -> int: + return int(cls._uid_from_env() or os.getuid()) - @property - def home(self) -> Path: - if self._pw is not None: - return Path(self._pw.pw_dir) - return Path.home() + @classmethod + def uid_gid(cls) -> tuple[int, int]: + if uid := cls._uid_from_env: + gid = int(os.getenv("SUDO_GID") or pwd.getpwuid(uid).pw_gid) + return uid, gid + return os.getuid(), os.getgid() - def is_running_user(self) -> bool: - if self._pw is not None: - return self._pw.pw_uid == os.getuid() - return True + @classmethod + def name(cls) -> str: + if uid := cls._uid_from_env(): + return pwd.getpwuid(uid).pw_name + return getpass.getuser() + @classmethod + def home(cls) -> Path: + home = os.getenv("SUDO_HOME") or os.getenv("HOME") or pwd.getpwuid(cls.uid()).pw_dir + return Path(home) -def current_user() -> InvokingUser: - uid = os.getenv("SUDO_UID") or os.getenv("PKEXEC_UID") - if uid: - return InvokingUser.for_uid(int(uid)) - return InvokingUser() + @classmethod + def is_running_user(cls) -> bool: + return cls.uid() == os.getuid() @contextlib.contextmanager