Compare commits
9 Commits
v1.4.1
...
5601ea442a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5601ea442a | ||
|
|
5ff15013d7 | ||
|
|
6ccc1c1490 | ||
|
|
8ead3472dd | ||
|
|
422ac8b837 | ||
|
|
ea84c1b14e | ||
|
|
71a4e7e725 | ||
|
|
fb737ef290 | ||
|
|
2963a43754 |
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -27,3 +27,9 @@ jobs:
|
|||||||
|
|
||||||
test-virgin-root:
|
test-virgin-root:
|
||||||
uses: ./.github/workflows/test-virgin-root.yml
|
uses: ./.github/workflows/test-virgin-root.yml
|
||||||
|
|
||||||
|
codesniffer-shellcheck:
|
||||||
|
uses: ./.github/workflows/codesniffer-shellcheck.yml
|
||||||
|
|
||||||
|
codesniffer-ruff:
|
||||||
|
uses: ./.github/workflows/codesniffer-ruff.yml
|
||||||
|
|||||||
23
.github/workflows/codesniffer-ruff.yml
vendored
Normal file
23
.github/workflows/codesniffer-ruff.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
name: Ruff (Python code sniffer)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
codesniffer-ruff:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.12"
|
||||||
|
|
||||||
|
- name: Install ruff
|
||||||
|
run: pip install ruff
|
||||||
|
|
||||||
|
- name: Run ruff
|
||||||
|
run: |
|
||||||
|
ruff check src tests
|
||||||
14
.github/workflows/codesniffer-shellcheck.yml
vendored
Normal file
14
.github/workflows/codesniffer-shellcheck.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
name: ShellCheck
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
codesniffer-shellcheck:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install ShellCheck
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y shellcheck
|
||||||
|
- name: Run ShellCheck
|
||||||
|
run: shellcheck -x $(find scripts -type f -name '*.sh' -print)
|
||||||
8
.github/workflows/mark-stable.yml
vendored
8
.github/workflows/mark-stable.yml
vendored
@@ -29,8 +29,16 @@ jobs:
|
|||||||
test-virgin-root:
|
test-virgin-root:
|
||||||
uses: ./.github/workflows/test-virgin-root.yml
|
uses: ./.github/workflows/test-virgin-root.yml
|
||||||
|
|
||||||
|
codesniffer-shellcheck:
|
||||||
|
uses: ./.github/workflows/codesniffer-shellcheck.yml
|
||||||
|
|
||||||
|
codesniffer-ruff:
|
||||||
|
uses: ./.github/workflows/codesniffer-ruff.yml
|
||||||
|
|
||||||
mark-stable:
|
mark-stable:
|
||||||
needs:
|
needs:
|
||||||
|
- codesniffer-shellcheck
|
||||||
|
- codesniffer-ruff
|
||||||
- test-unit
|
- test-unit
|
||||||
- test-integration
|
- test-integration
|
||||||
- test-env-nix
|
- test-env-nix
|
||||||
|
|||||||
51
CHANGELOG.md
51
CHANGELOG.md
@@ -1,11 +1,11 @@
|
|||||||
## [1.4.1] - 2025-12-12
|
## [1.4.1] - 2025-12-12
|
||||||
|
|
||||||
* Fixed (#1) stable release container publishing
|
* Fixed stable release container publishing
|
||||||
|
|
||||||
|
|
||||||
## [1.4.0] - 2025-12-12
|
## [1.4.0] - 2025-12-12
|
||||||
|
|
||||||
* **Docker Container Building**
|
**Docker Container Building**
|
||||||
|
|
||||||
* New official container images are automatically published on each release.
|
* New official container images are automatically published on each release.
|
||||||
* Images are available per distribution and as a default Arch-based image.
|
* Images are available per distribution and as a default Arch-based image.
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
## [1.3.0] - 2025-12-12
|
## [1.3.0] - 2025-12-12
|
||||||
|
|
||||||
* **Minor release – Stability & CI hardening**
|
**Stability & CI hardening**
|
||||||
|
|
||||||
* Stabilized Nix resolution and global symlink handling across Arch, CentOS, Debian, and Ubuntu
|
* Stabilized Nix resolution and global symlink handling across Arch, CentOS, Debian, and Ubuntu
|
||||||
* Ensured Nix works reliably in CI, sudo, login, and non-login shells without overriding distro-managed paths
|
* Ensured Nix works reliably in CI, sudo, login, and non-login shells without overriding distro-managed paths
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
## [1.2.1] - 2025-12-12
|
## [1.2.1] - 2025-12-12
|
||||||
|
|
||||||
* **Changed**
|
**Changed**
|
||||||
|
|
||||||
* Split container tests into *virtualenv* and *Nix flake* environments to clearly separate Python and Nix responsibilities.
|
* Split container tests into *virtualenv* and *Nix flake* environments to clearly separate Python and Nix responsibilities.
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
## [1.2.0] - 2025-12-12
|
## [1.2.0] - 2025-12-12
|
||||||
|
|
||||||
* **Release workflow overhaul**
|
**Release workflow overhaul**
|
||||||
|
|
||||||
* Introduced a fully structured release workflow with clear phases and safeguards
|
* Introduced a fully structured release workflow with clear phases and safeguards
|
||||||
* Added preview-first releases with explicit confirmation before execution
|
* Added preview-first releases with explicit confirmation before execution
|
||||||
@@ -65,7 +65,8 @@
|
|||||||
|
|
||||||
## [1.0.0] - 2025-12-11
|
## [1.0.0] - 2025-12-11
|
||||||
|
|
||||||
* **1.0.0 – Official Stable Release 🎉**
|
**Official Stable Release 🎉**
|
||||||
|
|
||||||
*First stable release of PKGMGR, the multi-distro development and package workflow manager.*
|
*First stable release of PKGMGR, the multi-distro development and package workflow manager.*
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -158,7 +159,7 @@ PKGMGR 1.0.0 unifies repository management, build tooling, release automation an
|
|||||||
|
|
||||||
## [0.9.1] - 2025-12-10
|
## [0.9.1] - 2025-12-10
|
||||||
|
|
||||||
* * Refactored installer: new `venv-create.sh`, cleaner root/user setup flow, updated README with architecture map.
|
* Refactored installer: new `venv-create.sh`, cleaner root/user setup flow, updated README with architecture map.
|
||||||
* Split virgin tests into root/user workflows; stabilized Nix installer across distros; improved test scripts with dynamic distro selection and isolated Nix stores.
|
* Split virgin tests into root/user workflows; stabilized Nix installer across distros; improved test scripts with dynamic distro selection and isolated Nix stores.
|
||||||
* Fixed repository directory resolution; improved `pkgmgr path` and `pkgmgr shell`; added full unit/E2E coverage.
|
* Fixed repository directory resolution; improved `pkgmgr path` and `pkgmgr shell`; added full unit/E2E coverage.
|
||||||
* Removed deprecated files and updated `.gitignore`.
|
* Removed deprecated files and updated `.gitignore`.
|
||||||
@@ -253,47 +254,45 @@ PKGMGR 1.0.0 unifies repository management, build tooling, release automation an
|
|||||||
|
|
||||||
## [0.7.1] - 2025-12-09
|
## [0.7.1] - 2025-12-09
|
||||||
|
|
||||||
* Fix floating 'latest' tag logic: dereference annotated target (vX.Y.Z^{}), add tag message to avoid Git errors, ensure best-effort update without blocking releases, and update unit tests (see ChatGPT conversation: https://chatgpt.com/share/69383024-efa4-800f-a875-129b81fa40ff).
|
* Fix floating 'latest' tag logic
|
||||||
|
* dereference annotated target (vX.Y.Z^{})
|
||||||
|
* add tag message to avoid Git errors
|
||||||
|
* ensure best-effort update without blocking releases
|
||||||
|
|
||||||
## [0.7.0] - 2025-12-09
|
## [0.7.0] - 2025-12-09
|
||||||
|
|
||||||
* Add Git helpers for branch sync and floating 'latest' tag in the release workflow, ensure main/master are updated from origin before tagging, and extend unit/e2e tests including 'pkgmgr release --help' coverage (see ChatGPT conversation: https://chatgpt.com/share/69383024-efa4-800f-a875-129b81fa40ff)
|
* Add Git helpers for branch sync and floating 'latest' tag in the release workflow
|
||||||
|
* ensure main/master are updated from origin before tagging
|
||||||
|
|
||||||
## [0.6.0] - 2025-12-09
|
## [0.6.0] - 2025-12-09
|
||||||
|
|
||||||
* Expose DISTROS and BASE_IMAGE_* variables as exported Makefile environment variables so all build and test commands can consume them dynamically. By exporting these values, every Make target (e.g., build, build-no-cache, build-missing, test-container, test-unit, test-e2e) and every delegated script in scripts/build/ and scripts/test/ now receives a consistent view of the supported distributions and their base container images. This change removes duplicated definitions across scripts, ensures reproducible builds, and allows build tooling to react automatically when new distros or base images are added to the Makefile.
|
* Consistent view of the supported distributions and their base container images.
|
||||||
|
|
||||||
|
|
||||||
## [0.5.1] - 2025-12-09
|
## [0.5.1] - 2025-12-09
|
||||||
|
|
||||||
* Refine pkgmgr release CLI close wiring and integration tests for --close flag (ChatGPT: https://chatgpt.com/share/69376b4e-8440-800f-9d06-535ec1d7a40e)
|
* Refine pkgmgr release CLI close wiring and integration tests for --close flag
|
||||||
|
|
||||||
|
|
||||||
## [0.5.0] - 2025-12-09
|
## [0.5.0] - 2025-12-09
|
||||||
|
|
||||||
* Add pkgmgr branch close subcommand, extend CLI parser wiring, and add unit tests for branch handling and version version-selection logic (see ChatGPT conversation: https://chatgpt.com/share/693762a3-9ea8-800f-a640-bc78170953d1)
|
* Add pkgmgr branch close subcommand, extend CLI parser wiring
|
||||||
|
|
||||||
|
|
||||||
## [0.4.3] - 2025-12-09
|
## [0.4.3] - 2025-12-09
|
||||||
|
|
||||||
* Implement current-directory repository selection for release and proxy commands, unify selection semantics across CLI layers, extend release workflow with --close, integrate branch closing logic, fix wiring for get_repo_identifier/get_repo_dir, update packaging files (PKGBUILD, spec, flake.nix, pyproject), and add comprehensive unit/e2e tests for release and branch commands (see ChatGPT conversation: https://chatgpt.com/share/69375cfe-9e00-800f-bd65-1bd5937e1696)
|
* Implement current-directory repository selection for release and proxy commands, unify selection semantics across CLI layers, extend release workflow with --close, integrate branch closing logic, fix wiring for get_repo_identifier/get_repo_dir, update packaging files (PKGBUILD, spec, flake.nix, pyproject)
|
||||||
|
|
||||||
|
|
||||||
## [0.4.2] - 2025-12-09
|
## [0.4.2] - 2025-12-09
|
||||||
|
|
||||||
* Wire pkgmgr release CLI to new helper and add unit tests (see ChatGPT conversation: https://chatgpt.com/share/69374f09-c760-800f-92e4-5b44a4510b62)
|
* Wire pkgmgr release CLI to new helpe
|
||||||
|
|
||||||
|
|
||||||
## [0.4.1] - 2025-12-08
|
## [0.4.1] - 2025-12-08
|
||||||
|
|
||||||
* Add branch close subcommand and integrate release close/editor flow (ChatGPT: https://chatgpt.com/share/69374f09-c760-800f-92e4-5b44a4510b62)
|
* Add branch close subcommand and integrate release close/editor flow
|
||||||
|
|
||||||
|
|
||||||
## [0.4.0] - 2025-12-08
|
## [0.4.0] - 2025-12-08
|
||||||
|
|
||||||
* Add branch closing helper and --close flag to release command, including CLI wiring and tests (see https://chatgpt.com/share/69374aec-74ec-800f-bde3-5d91dfdb9b91)
|
* Add branch closing helper and --close flag to release command
|
||||||
|
|
||||||
## [0.3.0] - 2025-12-08
|
## [0.3.0] - 2025-12-08
|
||||||
|
|
||||||
@@ -304,13 +303,10 @@ PKGMGR 1.0.0 unifies repository management, build tooling, release automation an
|
|||||||
- New config update logic + default YAML sync
|
- New config update logic + default YAML sync
|
||||||
- Improved proxy command handling
|
- Improved proxy command handling
|
||||||
- Full CLI routing refactor
|
- Full CLI routing refactor
|
||||||
- Expanded E2E tests for list, proxy, and selection logic
|
|
||||||
Konversation: https://chatgpt.com/share/693745c3-b8d8-800f-aa29-c8481a2ffae1
|
|
||||||
|
|
||||||
## [0.2.0] - 2025-12-08
|
## [0.2.0] - 2025-12-08
|
||||||
|
|
||||||
* Add preview-first release workflow and extended packaging support (see ChatGPT conversation: https://chatgpt.com/share/693722b4-af9c-800f-bccc-8a4036e99630)
|
* Add preview-first release workflow and extended packaging support
|
||||||
|
|
||||||
|
|
||||||
## [0.1.0] - 2025-12-08
|
## [0.1.0] - 2025-12-08
|
||||||
|
|
||||||
@@ -319,5 +315,4 @@ Konversation: https://chatgpt.com/share/693745c3-b8d8-800f-aa29-c8481a2ffae1
|
|||||||
|
|
||||||
## [0.1.0] - 2025-12-08
|
## [0.1.0] - 2025-12-08
|
||||||
|
|
||||||
* Implement unified release helper with preview mode, multi-packaging version bumps, and new integration/unit tests (see ChatGPT conversation 2025-12-08: https://chatgpt.com/share/693722b4-af9c-800f-bccc-8a4036e99630)
|
* Implement unified release helper with preview mode, multi-packaging version bumps
|
||||||
|
|
||||||
167
README.md
167
README.md
@@ -25,52 +25,37 @@ together into repeatable development workflows.
|
|||||||
|
|
||||||
Traditional distro package managers like `apt`, `pacman` or `dnf` focus on a
|
Traditional distro package managers like `apt`, `pacman` or `dnf` focus on a
|
||||||
single operating system. PKGMGR instead focuses on **your repositories and
|
single operating system. PKGMGR instead focuses on **your repositories and
|
||||||
development lifecycle**:
|
development lifecycle**. It provides one configuration for all repositories,
|
||||||
|
one unified CLI to interact with them, and a Nix-based foundation that keeps
|
||||||
|
tooling reproducible across distributions.
|
||||||
|
|
||||||
* one configuration for all your repos,
|
Native package managers are still used where they make sense. PKGMGR coordinates
|
||||||
* one CLI to interact with them,
|
the surrounding development, build and release workflows in a consistent way.
|
||||||
* one Nix-based layer to keep tooling reproducible across distros.
|
|
||||||
|
|
||||||
You keep using your native package manager where it makes sense – PKGMGR
|
In addition, PKGMGR provides Docker images that can serve as a **reproducible
|
||||||
coordinates the *development and release flow* around it.
|
system baseline**. These images bundle the complete PKGMGR toolchain and are
|
||||||
|
designed to be reused as a stable execution environment across machines,
|
||||||
|
pipelines and teams. This approach is specifically used within
|
||||||
|
[**Infinito.Nexus**](https://s.infinito.nexus/code) to make complex systems
|
||||||
|
distribution-independent while remaining fully reproducible.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Features 🚀
|
## Features 🚀
|
||||||
|
|
||||||
### Multi-distro development & packaging
|
PKGMGR enables multi-distro development and packaging by managing multiple
|
||||||
|
repositories from a single configuration file. It drives complete release
|
||||||
|
pipelines across Linux distributions using Nix flakes, Python build metadata,
|
||||||
|
native OS packages such as Arch, Debian and RPM formats, and additional ecosystem
|
||||||
|
integrations like Ansible.
|
||||||
|
|
||||||
* Manage **many repositories at once** from a single `config/config.yaml`.
|
All functionality is exposed through a unified `pkgmgr` command-line interface
|
||||||
* Drive full **release pipelines** across Linux distributions using:
|
that works identically on every supported distribution. It combines repository
|
||||||
|
management, Git operations, Docker and Compose orchestration, as well as
|
||||||
|
versioning, release and changelog workflows. Many commands support a preview
|
||||||
|
mode, allowing you to inspect the underlying actions before they are executed.
|
||||||
|
|
||||||
* Nix flakes (`flake.nix`)
|
---
|
||||||
* PyPI style builds (`pyproject.toml`)
|
|
||||||
* OS packages (PKGBUILD, Debian control/changelog, RPM spec)
|
|
||||||
* Ansible Galaxy metadata and more.
|
|
||||||
|
|
||||||
### Rich CLI for daily work
|
|
||||||
|
|
||||||
All commands are exposed via the `pkgmgr` CLI and are available on every distro:
|
|
||||||
|
|
||||||
* **Repository management**
|
|
||||||
|
|
||||||
* `clone`, `update`, `install`, `delete`, `deinstall`, `path`, `list`, `config`
|
|
||||||
* **Git proxies**
|
|
||||||
|
|
||||||
* `pull`, `push`, `status`, `diff`, `add`, `show`, `checkout`,
|
|
||||||
`reset`, `revert`, `rebase`, `commit`, `branch`
|
|
||||||
* **Docker & Compose orchestration**
|
|
||||||
|
|
||||||
* `build`, `up`, `down`, `exec`, `ps`, `start`, `stop`, `restart`
|
|
||||||
* **Release toolchain**
|
|
||||||
|
|
||||||
* `version`, `release`, `changelog`, `make`
|
|
||||||
* **Mirror & workflow helpers**
|
|
||||||
|
|
||||||
* `mirror` (list/diff/merge/setup), `shell`, `terminal`, `code`, `explore`
|
|
||||||
|
|
||||||
Many of these commands support `--preview` mode so you can inspect the
|
|
||||||
underlying Git or Docker calls without executing them.
|
|
||||||
|
|
||||||
### Full development workflows
|
### Full development workflows
|
||||||
|
|
||||||
@@ -83,10 +68,6 @@ versioning features it can drive **end-to-end workflows**:
|
|||||||
4. Build distro-specific packages.
|
4. Build distro-specific packages.
|
||||||
5. Keep all mirrors and working copies in sync.
|
5. Keep all mirrors and working copies in sync.
|
||||||
|
|
||||||
The extensive E2E tests (`tests/e2e/`) and GitHub Actions workflows (including
|
|
||||||
“virgin user” and “virgin root” Arch tests) validate these flows across
|
|
||||||
different Linux environments.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Architecture & Setup Map 🗺️
|
## Architecture & Setup Map 🗺️
|
||||||
@@ -99,25 +80,26 @@ The following diagram gives a full overview of:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
**Diagram status:** 12 December 2025
|
**Diagram status:** 12 December 2025
|
||||||
|
|
||||||
**Always-up-to-date version:** [https://s.veen.world/pkgmgrmp](https://s.veen.world/pkgmgrmp)
|
**Always-up-to-date version:** [https://s.veen.world/pkgmgrmp](https://s.veen.world/pkgmgrmp)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Perfekt, dann hier die **noch kompaktere und korrekt differenzierte Version**, die **nur** zwischen
|
|
||||||
**`make setup`** und **`make setup-venv`** unterscheidet und exakt deinem Verhalten entspricht.
|
|
||||||
|
|
||||||
README-ready, ohne Over-Engineering.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Installation ⚙️
|
## Installation ⚙️
|
||||||
|
|
||||||
PKGMGR can be installed using `make`.
|
PKGMGR can be installed using `make`.
|
||||||
The setup mode defines **which runtime layers are prepared**.
|
The setup mode defines **which runtime layers are prepared**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Download
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/kevinveenbirkenbach/package-manager.git
|
||||||
|
cd package-manager
|
||||||
|
```
|
||||||
|
|
||||||
### Dependency installation (optional)
|
### Dependency installation (optional)
|
||||||
|
|
||||||
System dependencies required **before running any *make* commands** are installed via:
|
System dependencies required **before running any *make* commands** are installed via:
|
||||||
@@ -128,8 +110,13 @@ scripts/installation/dependencies.sh
|
|||||||
|
|
||||||
The script detects and normalizes the OS and installs the required **system-level dependencies** accordingly.
|
The script detects and normalizes the OS and installs the required **system-level dependencies** accordingly.
|
||||||
|
|
||||||
|
### Install
|
||||||
|
|
||||||
---
|
```bash
|
||||||
|
git clone https://github.com/kevinveenbirkenbach/package-manager.git
|
||||||
|
cd package-manager
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
### Setup modes
|
### Setup modes
|
||||||
|
|
||||||
@@ -138,17 +125,8 @@ The script detects and normalizes the OS and installs the required **system-leve
|
|||||||
| **make setup** | Python venv **and** Nix | Full development & CI |
|
| **make setup** | Python venv **and** Nix | Full development & CI |
|
||||||
| **make setup-venv** | Python venv only | Local user setup |
|
| **make setup-venv** | Python venv only | Local user setup |
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Install & setup
|
##### Full setup (venv + Nix)
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/kevinveenbirkenbach/package-manager.git
|
|
||||||
cd package-manager
|
|
||||||
make install
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Full setup (venv + Nix)
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make setup
|
make setup
|
||||||
@@ -156,7 +134,7 @@ make setup
|
|||||||
|
|
||||||
Use this for CI, servers, containers and full development workflows.
|
Use this for CI, servers, containers and full development workflows.
|
||||||
|
|
||||||
#### Venv-only setup
|
##### Venv-only setup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make setup-venv
|
make setup-venv
|
||||||
@@ -167,38 +145,77 @@ Use this if you want PKGMGR isolated without Nix integration.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Run without installation (Nix)
|
Alles klar 🙂
|
||||||
|
Hier ist der **RUN-Abschnitt ohne Gedankenstriche**, klar nach **Nix, Docker und venv** getrennt:
|
||||||
|
|
||||||
Run PKGMGR directly via Nix Flakes.
|
---
|
||||||
|
|
||||||
|
## Run PKGMGR 🧰
|
||||||
|
|
||||||
|
PKGMGR can be executed in different environments.
|
||||||
|
All modes expose the same CLI and commands.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Run via Nix (no installation)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nix run github:kevinveenbirkenbach/package-manager#pkgmgr -- --help
|
nix run github:kevinveenbirkenbach/package-manager#pkgmgr -- --help
|
||||||
```
|
```
|
||||||
|
|
||||||
Example:
|
---
|
||||||
|
|
||||||
```bash
|
### Run via Docker 🐳
|
||||||
nix run github:kevinveenbirkenbach/package-manager#pkgmgr -- version pkgmgr
|
|
||||||
```
|
|
||||||
|
|
||||||
Notes:
|
PKGMGR can be executed **inside Docker containers** for CI, testing and isolated
|
||||||
|
workflows.
|
||||||
|
---
|
||||||
|
|
||||||
* full flake URL required
|
#### Container types
|
||||||
* `--` separates Nix and PKGMGR arguments
|
|
||||||
* can be used alongside any setup mode
|
Two container types are available.
|
||||||
|
|
||||||
|
|
||||||
|
| Image type | Contains | Typical use |
|
||||||
|
| ---------- | ----------------------------- | ----------------------- |
|
||||||
|
| **Virgin** | Base OS + system dependencies | Clean test environments |
|
||||||
|
| **Stable** | PKGMGR + Nix (flakes enabled) | Ready-to-use workflows |
|
||||||
|
|
||||||
|
Example images:
|
||||||
|
|
||||||
|
* Virgin: `pkgmgr-arch-virgin`
|
||||||
|
* Stable: `ghcr.io/kevinveenbirkenbach/pkgmgr:stable`
|
||||||
|
|
||||||
|
|
||||||
|
Use **virgin images** for isolated test runs,
|
||||||
|
use the **stable image** for fast, reproducible execution.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Usage 🧰
|
#### Run examples
|
||||||
|
|
||||||
After installation, the main entry point is:
|
```bash
|
||||||
|
docker run --rm -it \
|
||||||
|
-v "$PWD":/src \
|
||||||
|
-w /src \
|
||||||
|
ghcr.io/kevinveenbirkenbach/pkgmgr:stable \
|
||||||
|
pkgmgr --help
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Run via virtual environment (venv)
|
||||||
|
|
||||||
|
After activating the venv:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pkgmgr --help
|
pkgmgr --help
|
||||||
```
|
```
|
||||||
|
|
||||||
This prints a list of all available subcommands.
|
---
|
||||||
The help for each command is available via:
|
|
||||||
|
This allows you to choose between zero install execution using Nix, fully prebuilt
|
||||||
|
Docker environments or local isolated venv setups with identical command behavior.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ It is invoked during package installation (Arch/Debian/Fedora scriptlets) and ca
|
|||||||
|
|
||||||
The entry point sources small, focused modules from *scripts/nix/lib/*:
|
The entry point sources small, focused modules from *scripts/nix/lib/*:
|
||||||
|
|
||||||
- *config.sh* — configuration defaults (installer URL, retry timing)
|
- *bootstrap_config.sh* — configuration defaults (installer URL, retry timing)
|
||||||
- *detect.sh* — container detection helpers
|
- *detect.sh* — container detection helpers
|
||||||
- *path.sh* — PATH adjustments and `nix` binary resolution helpers
|
- *path.sh* — PATH adjustments and `nix` binary resolution helpers
|
||||||
- *symlinks.sh* — user/global symlink helpers for stable `nix` discovery
|
- *symlinks.sh* — user/global symlink helpers for stable `nix` discovery
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# shellcheck source=lib/config.sh
|
# shellcheck source=lib/bootstrap_config.sh
|
||||||
# shellcheck source=lib/detect.sh
|
# shellcheck source=lib/detect.sh
|
||||||
# shellcheck source=lib/path.sh
|
# shellcheck source=lib/path.sh
|
||||||
# shellcheck source=lib/symlinks.sh
|
# shellcheck source=lib/symlinks.sh
|
||||||
# shellcheck source=lib/users.sh
|
# shellcheck source=lib/users.sh
|
||||||
# shellcheck source=lib/install.sh
|
# shellcheck source=lib/install.sh
|
||||||
|
# shellcheck source=lib/nix_conf_file.sh
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
source "${SCRIPT_DIR}/lib/config.sh"
|
source "${SCRIPT_DIR}/lib/bootstrap_config.sh"
|
||||||
source "${SCRIPT_DIR}/lib/detect.sh"
|
source "${SCRIPT_DIR}/lib/detect.sh"
|
||||||
source "${SCRIPT_DIR}/lib/path.sh"
|
source "${SCRIPT_DIR}/lib/path.sh"
|
||||||
source "${SCRIPT_DIR}/lib/symlinks.sh"
|
source "${SCRIPT_DIR}/lib/symlinks.sh"
|
||||||
source "${SCRIPT_DIR}/lib/users.sh"
|
source "${SCRIPT_DIR}/lib/users.sh"
|
||||||
source "${SCRIPT_DIR}/lib/install.sh"
|
source "${SCRIPT_DIR}/lib/install.sh"
|
||||||
|
source "${SCRIPT_DIR}/lib/nix_conf_file.sh"
|
||||||
|
|
||||||
echo "[init-nix] Starting Nix initialization..."
|
echo "[init-nix] Starting Nix initialization..."
|
||||||
|
|
||||||
@@ -26,6 +28,7 @@ main() {
|
|||||||
ensure_nix_on_path
|
ensure_nix_on_path
|
||||||
|
|
||||||
if [[ "${EUID:-0}" -eq 0 ]]; then
|
if [[ "${EUID:-0}" -eq 0 ]]; then
|
||||||
|
nixconf_ensure_experimental_features
|
||||||
ensure_global_nix_symlinks "$(resolve_nix_bin 2>/dev/null || true)"
|
ensure_global_nix_symlinks "$(resolve_nix_bin 2>/dev/null || true)"
|
||||||
else
|
else
|
||||||
ensure_user_nix_symlink "$(resolve_nix_bin 2>/dev/null || true)"
|
ensure_user_nix_symlink "$(resolve_nix_bin 2>/dev/null || true)"
|
||||||
@@ -106,6 +109,10 @@ main() {
|
|||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
ensure_nix_on_path
|
ensure_nix_on_path
|
||||||
|
|
||||||
|
if [[ "${EUID:-0}" -eq 0 ]]; then
|
||||||
|
nixconf_ensure_experimental_features
|
||||||
|
fi
|
||||||
|
|
||||||
local nix_bin_post
|
local nix_bin_post
|
||||||
nix_bin_post="$(resolve_nix_bin 2>/dev/null || true)"
|
nix_bin_post="$(resolve_nix_bin 2>/dev/null || true)"
|
||||||
|
|
||||||
|
|||||||
55
scripts/nix/lib/nix_conf_file.sh
Normal file
55
scripts/nix/lib/nix_conf_file.sh
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Prevent double-sourcing
|
||||||
|
if [[ -n "${PKGMGR_NIX_CONF_FILE_SH:-}" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
PKGMGR_NIX_CONF_FILE_SH=1
|
||||||
|
|
||||||
|
nixconf_file_path() {
|
||||||
|
echo "/etc/nix/nix.conf"
|
||||||
|
}
|
||||||
|
|
||||||
|
nixconf_ensure_experimental_features() {
|
||||||
|
local nix_conf want
|
||||||
|
nix_conf="$(nixconf_file_path)"
|
||||||
|
want="experimental-features = nix-command flakes"
|
||||||
|
|
||||||
|
mkdir -p /etc/nix
|
||||||
|
|
||||||
|
if [[ ! -f "${nix_conf}" ]]; then
|
||||||
|
echo "[nix-conf] Creating ${nix_conf} with: ${want}"
|
||||||
|
printf "%s\n" "${want}" >"${nix_conf}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -qE '^\s*experimental-features\s*=' "${nix_conf}"; then
|
||||||
|
if grep -qE '^\s*experimental-features\s*=.*\bnix-command\b' "${nix_conf}" \
|
||||||
|
&& grep -qE '^\s*experimental-features\s*=.*\bflakes\b' "${nix_conf}"; then
|
||||||
|
echo "[nix-conf] experimental-features already correct"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[nix-conf] Extending experimental-features in ${nix_conf}"
|
||||||
|
|
||||||
|
local current
|
||||||
|
current="$(grep -E '^\s*experimental-features\s*=' "${nix_conf}" | head -n1 | cut -d= -f2-)"
|
||||||
|
current="$(echo "${current}" | xargs)" # trim
|
||||||
|
|
||||||
|
# Build a merged feature string without duplicates (simple token set)
|
||||||
|
local merged="nix-command flakes"
|
||||||
|
local token
|
||||||
|
for token in ${current}; do
|
||||||
|
if [[ " ${merged} " != *" ${token} "* ]]; then
|
||||||
|
merged="${merged} ${token}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
sed -i "s|^\s*experimental-features\s*=.*|experimental-features = ${merged}|" "${nix_conf}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[nix-conf] Appending to ${nix_conf}: ${want}"
|
||||||
|
printf "\n%s\n" "${want}" >>"${nix_conf}"
|
||||||
|
}
|
||||||
@@ -45,7 +45,7 @@ def config_init(
|
|||||||
# Announce where we will write the result
|
# Announce where we will write the result
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
print("============================================================")
|
print("============================================================")
|
||||||
print(f"[INIT] Writing user configuration to:")
|
print("[INIT] Writing user configuration to:")
|
||||||
print(f" {user_config_path}")
|
print(f" {user_config_path}")
|
||||||
print("============================================================")
|
print("============================================================")
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ def config_init(
|
|||||||
defaults_config["directories"]["repositories"]
|
defaults_config["directories"]["repositories"]
|
||||||
)
|
)
|
||||||
|
|
||||||
print(f"[INIT] Scanning repository base directory:")
|
print("[INIT] Scanning repository base directory:")
|
||||||
print(f" {repositories_base_dir}")
|
print(f" {repositories_base_dir}")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ def config_init(
|
|||||||
if new_entries:
|
if new_entries:
|
||||||
user_config.setdefault("repositories", []).extend(new_entries)
|
user_config.setdefault("repositories", []).extend(new_entries)
|
||||||
save_user_config(user_config, user_config_path)
|
save_user_config(user_config, user_config_path)
|
||||||
print(f"[SAVE] Wrote user configuration to:")
|
print("[SAVE] Wrote user configuration to:")
|
||||||
print(f" {user_config_path}")
|
print(f" {user_config_path}")
|
||||||
else:
|
else:
|
||||||
print("[INFO] No new repositories were added.")
|
print("[INFO] No new repositories were added.")
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ def _ensure_repo_dir(
|
|||||||
if not os.path.exists(repo_dir):
|
if not os.path.exists(repo_dir):
|
||||||
print(
|
print(
|
||||||
f"Repository directory '{repo_dir}' does not exist. "
|
f"Repository directory '{repo_dir}' does not exist. "
|
||||||
f"Cloning it now..."
|
"Cloning it now..."
|
||||||
)
|
)
|
||||||
clone_repos(
|
clone_repos(
|
||||||
[repo],
|
[repo],
|
||||||
@@ -87,7 +87,7 @@ def _ensure_repo_dir(
|
|||||||
if not os.path.exists(repo_dir):
|
if not os.path.exists(repo_dir):
|
||||||
print(
|
print(
|
||||||
f"Cloning failed for repository {identifier}. "
|
f"Cloning failed for repository {identifier}. "
|
||||||
f"Skipping installation."
|
"Skipping installation."
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class MakefileInstaller(BaseInstaller):
|
|||||||
if not ctx.quiet:
|
if not ctx.quiet:
|
||||||
print(
|
print(
|
||||||
f"[pkgmgr] Running 'make install' in {ctx.repo_dir} "
|
f"[pkgmgr] Running 'make install' in {ctx.repo_dir} "
|
||||||
f"(MakefileInstaller)"
|
"(MakefileInstaller)"
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd = "make install"
|
cmd = "make install"
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ class InstallationPipeline:
|
|||||||
# so we skip this installer entirely.
|
# so we skip this installer entirely.
|
||||||
if not quiet:
|
if not quiet:
|
||||||
print(
|
print(
|
||||||
f"[pkgmgr] Skipping installer "
|
"[pkgmgr] Skipping installer "
|
||||||
f"{installer.__class__.__name__} for {identifier} – "
|
f"{installer.__class__.__name__} for {identifier} – "
|
||||||
f"CLI already provided by layer {state.layer.value!r}."
|
f"CLI already provided by layer {state.layer.value!r}."
|
||||||
)
|
)
|
||||||
@@ -171,7 +171,7 @@ class InstallationPipeline:
|
|||||||
# need to run another installer on top of it.
|
# need to run another installer on top of it.
|
||||||
if not quiet:
|
if not quiet:
|
||||||
print(
|
print(
|
||||||
f"[pkgmgr] Skipping installer "
|
"[pkgmgr] Skipping installer "
|
||||||
f"{installer.__class__.__name__} for {identifier} – "
|
f"{installer.__class__.__name__} for {identifier} – "
|
||||||
f"layer {installer_layer.value!r} is already loaded."
|
f"layer {installer_layer.value!r} is already loaded."
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ def ensure_origin_remote(
|
|||||||
current = current_origin_url(repo_dir)
|
current = current_origin_url(repo_dir)
|
||||||
if current == url or not url:
|
if current == url or not url:
|
||||||
print(
|
print(
|
||||||
f"[INFO] 'origin' already points to "
|
"[INFO] 'origin' already points to "
|
||||||
f"{current or '<unknown>'} (no change needed)."
|
f"{current or '<unknown>'} (no change needed)."
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ def update_spec_version(
|
|||||||
|
|
||||||
if preview:
|
if preview:
|
||||||
print(
|
print(
|
||||||
f"[PREVIEW] Would update spec file "
|
"[PREVIEW] Would update spec file "
|
||||||
f"{os.path.basename(spec_path)} to Version: {new_version}, Release: 1..."
|
f"{os.path.basename(spec_path)} to Version: {new_version}, Release: 1..."
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from pkgmgr.actions.branch import close_branch
|
from pkgmgr.actions.branch import close_branch
|
||||||
from pkgmgr.core.git import get_current_branch, GitError
|
from pkgmgr.core.git import get_current_branch, GitError
|
||||||
|
|||||||
@@ -272,7 +272,7 @@ def list_repositories(
|
|||||||
f"{'STATUS'.ljust(status_width)} "
|
f"{'STATUS'.ljust(status_width)} "
|
||||||
f"{'CATEGORIES'.ljust(cat_width)} "
|
f"{'CATEGORIES'.ljust(cat_width)} "
|
||||||
f"{'TAGS'.ljust(tag_width)} "
|
f"{'TAGS'.ljust(tag_width)} "
|
||||||
f"DIR"
|
"DIR"
|
||||||
f"{RESET}"
|
f"{RESET}"
|
||||||
)
|
)
|
||||||
print(header)
|
print(header)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ PROXY_COMMANDS: Dict[str, List[str]] = {
|
|||||||
"reset",
|
"reset",
|
||||||
"revert",
|
"revert",
|
||||||
"rebase",
|
"rebase",
|
||||||
|
"status",
|
||||||
"commit",
|
"commit",
|
||||||
],
|
],
|
||||||
"docker": [
|
"docker": [
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
from typing import Optional
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
from typing import Optional, List, Dict, Any
|
from typing import Optional, List, Dict, Any
|
||||||
@@ -201,8 +200,8 @@ def resolve_command_for_repo(
|
|||||||
print(
|
print(
|
||||||
f"[INFO] Repository '{repo_identifier}' appears to be a Python "
|
f"[INFO] Repository '{repo_identifier}' appears to be a Python "
|
||||||
f"package at '{python_package_root}' but no CLI entry point was "
|
f"package at '{python_package_root}' but no CLI entry point was "
|
||||||
f"found (PATH, Nix, main.sh/main.py). Treating it as a "
|
"found (PATH, Nix, main.sh/main.py). Treating it as a "
|
||||||
f"library-only repository with no command."
|
"library-only repository with no command."
|
||||||
)
|
)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
from typing import Optional
|
|
||||||
# pkgmgr/run_command.py
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from typing import List, Optional, Union
|
from typing import List, Optional, Union
|
||||||
|
|||||||
Reference in New Issue
Block a user