Refine installer layering and Python/Nix integration
- Introduce explicit CLI layer model (os-packages, nix, python, makefile)
and central InstallationPipeline to orchestrate installers.
- Move installer orchestration out of install_repos() into
pkgmgr.actions.repository.install.pipeline, using layer precedence and
capability tracking.
- Add pkgmgr.actions.repository.install.layers to classify commands into
layers and compare priorities.
- Rework PythonInstaller to always use isolated environments:
PKGMGR_PIP override → active venv → per-repo venv under ~/.venvs/<identifier>,
avoiding system Python and PEP 668 conflicts.
- Adjust NixFlakeInstaller to install flake outputs based on repository
identity: pkgmgr/package-manager → pkgmgr (mandatory) + default (optional),
all other repos → default (mandatory).
- Tighten MakefileInstaller behaviour, add global
PKGMGR_DISABLE_MAKEFILE_INSTALLER switch, and simplify install target
detection.
- Rewrite resolve_command_for_repo() with explicit Repository typing,
better Python package detection, Nix/PATH resolution, and a
library-only fallback instead of raising on missing CLI.
- Update flake.nix devShell to provide python3 with pip and add pip as a
propagated build input.
- Remove deprecated/wip repository entries from config defaults and drop
the unused config/wip.yml.
https://chatgpt.com/share/69399157-86d8-800f-9935-1a820893e908
2025-12-10 16:26:23 +01:00
|
|
|
"""
|
|
|
|
|
CLI layer model for the pkgmgr installation pipeline.
|
|
|
|
|
|
|
|
|
|
We treat CLI entry points as coming from one of four conceptual layers:
|
|
|
|
|
|
|
|
|
|
- os-packages : system package managers (pacman/apt/dnf/…)
|
|
|
|
|
- nix : Nix flake / nix profile
|
|
|
|
|
- python : pip / virtualenv / user-local scripts
|
|
|
|
|
- makefile : repo-local Makefile / scripts inside the repo
|
|
|
|
|
|
|
|
|
|
The layer order defines precedence: higher layers "own" the CLI and
|
|
|
|
|
lower layers will not be executed once a higher-priority CLI exists.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
from enum import Enum
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CliLayer(str, Enum):
|
|
|
|
|
OS_PACKAGES = "os-packages"
|
|
|
|
|
NIX = "nix"
|
|
|
|
|
PYTHON = "python"
|
|
|
|
|
MAKEFILE = "makefile"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Highest priority first
|
|
|
|
|
CLI_LAYERS: list[CliLayer] = [
|
|
|
|
|
CliLayer.OS_PACKAGES,
|
|
|
|
|
CliLayer.NIX,
|
|
|
|
|
CliLayer.PYTHON,
|
|
|
|
|
CliLayer.MAKEFILE,
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
style: modernise typing and clean up lint findings
Repository-wide mechanical cleanup so `ruff check src tests` has a chance
of passing; no behavioural changes.
- Add `from __future__ import annotations` where PEP 604 unions are used.
This has to come first: pyproject declares requires-python >= 3.9, where
`X | None` is not evaluable at runtime unless annotations are stringified.
- Replace typing.List/Dict/Tuple/Set with the builtin generics and
Optional[X] with X | None, then drop the imports that became unused.
The four actions/*/__init__.py files needed this by hand because ruff
leaves unused imports in __init__.py alone (possible re-exports).
- Strip shebangs from 72 importable modules. None of them are executable
or invoked directly; the entry points are console_scripts and runpy.
- Flatten nested `with` blocks, collapse needless-bool returns, and apply
the remaining mechanical ruff fixes (PIE810, FLY002, PERF102, FURB192,
RUF059, I001).
- Pass check=False explicitly to the four subprocess.run() calls that
inspect returncode themselves. That is the existing default.
Two rewrites are visible to mocks, so their tests move with them:
subprocess.run(stdout=PIPE, stderr=PIPE) became capture_output=True, and
open(path, "r", ...) lost the redundant mode.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 16:47:13 +02:00
|
|
|
def layer_priority(layer: CliLayer | None) -> int:
|
Refine installer layering and Python/Nix integration
- Introduce explicit CLI layer model (os-packages, nix, python, makefile)
and central InstallationPipeline to orchestrate installers.
- Move installer orchestration out of install_repos() into
pkgmgr.actions.repository.install.pipeline, using layer precedence and
capability tracking.
- Add pkgmgr.actions.repository.install.layers to classify commands into
layers and compare priorities.
- Rework PythonInstaller to always use isolated environments:
PKGMGR_PIP override → active venv → per-repo venv under ~/.venvs/<identifier>,
avoiding system Python and PEP 668 conflicts.
- Adjust NixFlakeInstaller to install flake outputs based on repository
identity: pkgmgr/package-manager → pkgmgr (mandatory) + default (optional),
all other repos → default (mandatory).
- Tighten MakefileInstaller behaviour, add global
PKGMGR_DISABLE_MAKEFILE_INSTALLER switch, and simplify install target
detection.
- Rewrite resolve_command_for_repo() with explicit Repository typing,
better Python package detection, Nix/PATH resolution, and a
library-only fallback instead of raising on missing CLI.
- Update flake.nix devShell to provide python3 with pip and add pip as a
propagated build input.
- Remove deprecated/wip repository entries from config defaults and drop
the unused config/wip.yml.
https://chatgpt.com/share/69399157-86d8-800f-9935-1a820893e908
2025-12-10 16:26:23 +01:00
|
|
|
"""
|
|
|
|
|
Return a numeric priority index for a given layer.
|
|
|
|
|
|
|
|
|
|
Lower index → higher priority.
|
|
|
|
|
Unknown / None → very low priority.
|
|
|
|
|
"""
|
|
|
|
|
if layer is None:
|
|
|
|
|
return len(CLI_LAYERS)
|
|
|
|
|
try:
|
|
|
|
|
return CLI_LAYERS.index(layer)
|
|
|
|
|
except ValueError:
|
|
|
|
|
return len(CLI_LAYERS)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def classify_command_layer(command: str, repo_dir: str) -> CliLayer:
|
|
|
|
|
"""
|
|
|
|
|
Heuristically classify a resolved command path into a CLI layer.
|
|
|
|
|
|
|
|
|
|
Rules (best effort):
|
|
|
|
|
|
|
|
|
|
- /usr/... or /bin/... → os-packages
|
|
|
|
|
- /nix/store/... or ~/.nix-profile → nix
|
|
|
|
|
- ~/.local/bin/... → python
|
|
|
|
|
- inside repo_dir → makefile
|
|
|
|
|
- everything else → python (user/venv scripts, etc.)
|
|
|
|
|
"""
|
|
|
|
|
command_abs = os.path.abspath(os.path.expanduser(command))
|
|
|
|
|
repo_abs = os.path.abspath(repo_dir)
|
|
|
|
|
home = os.path.expanduser("~")
|
|
|
|
|
|
|
|
|
|
# OS package managers
|
style: modernise typing and clean up lint findings
Repository-wide mechanical cleanup so `ruff check src tests` has a chance
of passing; no behavioural changes.
- Add `from __future__ import annotations` where PEP 604 unions are used.
This has to come first: pyproject declares requires-python >= 3.9, where
`X | None` is not evaluable at runtime unless annotations are stringified.
- Replace typing.List/Dict/Tuple/Set with the builtin generics and
Optional[X] with X | None, then drop the imports that became unused.
The four actions/*/__init__.py files needed this by hand because ruff
leaves unused imports in __init__.py alone (possible re-exports).
- Strip shebangs from 72 importable modules. None of them are executable
or invoked directly; the entry points are console_scripts and runpy.
- Flatten nested `with` blocks, collapse needless-bool returns, and apply
the remaining mechanical ruff fixes (PIE810, FLY002, PERF102, FURB192,
RUF059, I001).
- Pass check=False explicitly to the four subprocess.run() calls that
inspect returncode themselves. That is the existing default.
Two rewrites are visible to mocks, so their tests move with them:
subprocess.run(stdout=PIPE, stderr=PIPE) became capture_output=True, and
open(path, "r", ...) lost the redundant mode.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 16:47:13 +02:00
|
|
|
if command_abs.startswith(("/usr/", "/bin/")):
|
Refine installer layering and Python/Nix integration
- Introduce explicit CLI layer model (os-packages, nix, python, makefile)
and central InstallationPipeline to orchestrate installers.
- Move installer orchestration out of install_repos() into
pkgmgr.actions.repository.install.pipeline, using layer precedence and
capability tracking.
- Add pkgmgr.actions.repository.install.layers to classify commands into
layers and compare priorities.
- Rework PythonInstaller to always use isolated environments:
PKGMGR_PIP override → active venv → per-repo venv under ~/.venvs/<identifier>,
avoiding system Python and PEP 668 conflicts.
- Adjust NixFlakeInstaller to install flake outputs based on repository
identity: pkgmgr/package-manager → pkgmgr (mandatory) + default (optional),
all other repos → default (mandatory).
- Tighten MakefileInstaller behaviour, add global
PKGMGR_DISABLE_MAKEFILE_INSTALLER switch, and simplify install target
detection.
- Rewrite resolve_command_for_repo() with explicit Repository typing,
better Python package detection, Nix/PATH resolution, and a
library-only fallback instead of raising on missing CLI.
- Update flake.nix devShell to provide python3 with pip and add pip as a
propagated build input.
- Remove deprecated/wip repository entries from config defaults and drop
the unused config/wip.yml.
https://chatgpt.com/share/69399157-86d8-800f-9935-1a820893e908
2025-12-10 16:26:23 +01:00
|
|
|
return CliLayer.OS_PACKAGES
|
|
|
|
|
|
|
|
|
|
# Nix store / profile
|
style: modernise typing and clean up lint findings
Repository-wide mechanical cleanup so `ruff check src tests` has a chance
of passing; no behavioural changes.
- Add `from __future__ import annotations` where PEP 604 unions are used.
This has to come first: pyproject declares requires-python >= 3.9, where
`X | None` is not evaluable at runtime unless annotations are stringified.
- Replace typing.List/Dict/Tuple/Set with the builtin generics and
Optional[X] with X | None, then drop the imports that became unused.
The four actions/*/__init__.py files needed this by hand because ruff
leaves unused imports in __init__.py alone (possible re-exports).
- Strip shebangs from 72 importable modules. None of them are executable
or invoked directly; the entry points are console_scripts and runpy.
- Flatten nested `with` blocks, collapse needless-bool returns, and apply
the remaining mechanical ruff fixes (PIE810, FLY002, PERF102, FURB192,
RUF059, I001).
- Pass check=False explicitly to the four subprocess.run() calls that
inspect returncode themselves. That is the existing default.
Two rewrites are visible to mocks, so their tests move with them:
subprocess.run(stdout=PIPE, stderr=PIPE) became capture_output=True, and
open(path, "r", ...) lost the redundant mode.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 16:47:13 +02:00
|
|
|
if command_abs.startswith(("/nix/store/", os.path.join(home, ".nix-profile"))):
|
Refine installer layering and Python/Nix integration
- Introduce explicit CLI layer model (os-packages, nix, python, makefile)
and central InstallationPipeline to orchestrate installers.
- Move installer orchestration out of install_repos() into
pkgmgr.actions.repository.install.pipeline, using layer precedence and
capability tracking.
- Add pkgmgr.actions.repository.install.layers to classify commands into
layers and compare priorities.
- Rework PythonInstaller to always use isolated environments:
PKGMGR_PIP override → active venv → per-repo venv under ~/.venvs/<identifier>,
avoiding system Python and PEP 668 conflicts.
- Adjust NixFlakeInstaller to install flake outputs based on repository
identity: pkgmgr/package-manager → pkgmgr (mandatory) + default (optional),
all other repos → default (mandatory).
- Tighten MakefileInstaller behaviour, add global
PKGMGR_DISABLE_MAKEFILE_INSTALLER switch, and simplify install target
detection.
- Rewrite resolve_command_for_repo() with explicit Repository typing,
better Python package detection, Nix/PATH resolution, and a
library-only fallback instead of raising on missing CLI.
- Update flake.nix devShell to provide python3 with pip and add pip as a
propagated build input.
- Remove deprecated/wip repository entries from config defaults and drop
the unused config/wip.yml.
https://chatgpt.com/share/69399157-86d8-800f-9935-1a820893e908
2025-12-10 16:26:23 +01:00
|
|
|
return CliLayer.NIX
|
|
|
|
|
|
|
|
|
|
# User-local bin
|
|
|
|
|
if command_abs.startswith(os.path.join(home, ".local", "bin")):
|
|
|
|
|
return CliLayer.PYTHON
|
|
|
|
|
|
|
|
|
|
# Inside the repository → usually a Makefile/script
|
|
|
|
|
if command_abs.startswith(repo_abs):
|
|
|
|
|
return CliLayer.MAKEFILE
|
|
|
|
|
|
|
|
|
|
# Fallback: treat as Python-style/user-level script
|
|
|
|
|
return CliLayer.PYTHON
|