Skip to content

_shared

Shared helpers to remove boilerplate duplicated across package manager backends.

Each manager still performs its own shutil.which(...) / sudo_non_interactive_ok() checks locally rather than through these helpers, so that unit tests can keep patching those functions at their own module path; these helpers only centralize the repetitive result construction that follows such a check.

command_details(res)

Join a finished command's stdout/stderr into a single details blob.

Source code in src/personal_os_setup/tasks/managers/_shared.py
def command_details(res: CommandResult) -> str:
    """Join a finished command's stdout/stderr into a single details blob."""
    return (res.stdout + "\n" + res.stderr).strip()

format_failed_command(res)

Render a failed command's argv and output as human-readable details text.

Source code in src/personal_os_setup/tasks/managers/_shared.py
def format_failed_command(res: CommandResult) -> str:
    """Render a failed command's argv and output as human-readable details text."""
    lines = [f"$ {join_argv(res.argv)}"]
    if res.stdout.strip():
        lines.append(res.stdout.strip())
    if res.stderr.strip():
        lines.append(res.stderr.strip())
    return "\n".join(lines).strip()

missing_executable_install_result(exe, hint='')

Build the failure InstallResult for an install whose required executable is missing.

Source code in src/personal_os_setup/tasks/managers/_shared.py
def missing_executable_install_result(exe: str, hint: str = "") -> InstallResult:
    """Build the failure `InstallResult` for an install whose required executable is missing."""
    details = f"`{exe}` not found on PATH." + (f" {hint}" if hint else "")
    return InstallResult(ok=False, summary=f"{exe} not found on PATH", details=details)

missing_executable_task_result(action, exe, hint='')

Build the failure TaskResult for an action whose required executable is missing.

Source code in src/personal_os_setup/tasks/managers/_shared.py
def missing_executable_task_result(action: str, exe: str, hint: str = "") -> TaskResult:
    """Build the failure `TaskResult` for an action whose required executable is missing."""
    details = f"`{exe}` not found on PATH." + (f" {hint}" if hint else "")
    return TaskResult(ok=False, summary=f"{action}: failed", details=details)

sudo_required_install_result(package)

Build the failure InstallResult for an install that needs passwordless sudo.

Source code in src/personal_os_setup/tasks/managers/_shared.py
def sudo_required_install_result(package: str) -> InstallResult:
    """Build the failure `InstallResult` for an install that needs passwordless sudo."""
    return InstallResult(
        ok=False,
        summary=f"Failed to install {package} (sudo password required — run an "
        f"interactive sudo command first to cache credentials)",
        details=sudo_required_details(),
    )

sudo_required_task_result(action)

Build the failure TaskResult for an action that needs passwordless sudo.

Source code in src/personal_os_setup/tasks/managers/_shared.py
def sudo_required_task_result(action: str) -> TaskResult:
    """Build the failure `TaskResult` for an action that needs passwordless sudo."""
    return TaskResult(
        ok=False,
        summary=f"{action}: failed (sudo password required — run an interactive sudo "
        f"command first to cache credentials)",
        details=sudo_required_details(),
    )

winget_list_shows_installed(winget, package)

Return whether winget list output indicates package is installed.

Source code in src/personal_os_setup/tasks/managers/_shared.py
def winget_list_shows_installed(winget: str, package: str) -> bool:
    """Return whether `winget list` output indicates `package` is installed."""
    res = run([winget, "list", "-e", "--id", package], check=False)
    text = (res.stdout + "\n" + res.stderr).lower()
    if "no installed package" in text or "no package found" in text:
        return False
    return package.lower() in text and res.returncode == 0

winget_path()

Return the path to winget, or None if it's not on PATH.

Shared by the winget and msstore backends, both of which shell out to winget.

Source code in src/personal_os_setup/tasks/managers/_shared.py
def winget_path() -> str | None:
    """Return the path to `winget`, or `None` if it's not on PATH.

    Shared by the `winget` and `msstore` backends, both of which shell out to `winget`.
    """
    return shutil.which("winget")