Compare commits

..

17 Commits

Author SHA1 Message Date
Kevin Veen-Birkenbach
eeda944b73 ci: migrate tests to reusable workflows and introduce stable-tag pipeline
- convert all test workflows to reusable workflow_call
- add central CI workflow for branches and PRs
- add mark-stable workflow triggered on main pushes
- ensure stable tag updates only after all tests succeed
- remove duplicated triggers from test workflows
`

https://chatgpt.com/share/693aa4a6-7460-800f-ba47-cfc15b1b2236
2025-12-11 13:04:44 +01:00
Kevin Veen-Birkenbach
52cfbebba4 ci: make mark-stable robust for workflow_run
- fetch workflow_run runs without head_sha filter
- match by workflow name and head_sha in jq
- keep tagging logic and permissions unchanged

https://chatgpt.com/share/693aa4a6-7460-800f-ba47-cfc15b1b2236
2025-12-11 12:46:42 +01:00
Kevin Veen-Birkenbach
f4385807f1 e2e: disable Nix sandbox for cross-distro flake build test
- Update test_nix_build_pkgmgr.py to invoke
    nix --option sandbox false build .#pkgmgr -L
  to avoid sandbox/permission issues in Debian and Ubuntu containers.
- Keeps the test logic identical across all distros while ensuring
  consistent flake build behaviour during E2E runs.

https://chatgpt.com/share/693aa33f-4e3c-800f-86ec-99c38a07eacb
2025-12-11 12:45:04 +01:00
Kevin Veen-Birkenbach
e9e083c9dd ci: finalize mark-stable workflow fixes
- use correct GitHub API path (/repos/.../actions/runs)
- resolve repository via workflow_run.repository.full_name
- improve logging and safe no-tag exits
- ensure correct token handling and tag update logic

https://chatgpt.com/share/693aa4a6-7460-800f-ba47-cfc15b1b2236
2025-12-11 12:38:12 +01:00
Kevin Veen-Birkenbach
3218b2b39f ci: fix mark-stable workflow for workflow_run events
- use workflow_run.repository.full_name for gh API queries
- expose GITHUB_TOKEN as GH_TOKEN for the GitHub CLI
- improve log messages and keep tag skipped when checks are missing or failing
2025-12-11 12:26:29 +01:00
Kevin Veen-Birkenbach
ba296a79c9 ci: fix mark-stable permissions and ignore Nix result symlink
https://chatgpt.com/share/693aa4a6-7460-800f-ba47-cfc15b1b2236
2025-12-11 12:16:34 +01:00
Kevin Veen-Birkenbach
62e05e2f5b ci: tag commit as stable after full test matrix
- add mark-stable workflow that runs on workflow_run for all test pipelines
- use GitHub API to ensure all required workflows succeeded before moving the 'stable' tag
- add Nix flake.lock to pin nixpkgs for reproducible builds

https://chatgpt.com/share/693aa4a6-7460-800f-ba47-cfc15b1b2236
2025-12-11 12:01:21 +01:00
Kevin Veen-Birkenbach
77d8b68ba5 Add E2E Nix flake build test across all distro containers
- Introduce tests/e2e/test_nix_build_pkgmgr.py to inspect the Nix environment
  and build the pkgmgr flake inside the container started by test-e2e.sh
- Run the same commands in every distro container: nix --version, sandbox
  config, id, and nix build .#pkgmgr -L
- Print stdout/stderr and assert the flake build succeeds for easier
  cross-distro Nix debugging

https://chatgpt.com/share/693aa33f-4e3c-800f-86ec-99c38a07eacb
2025-12-11 11:55:43 +01:00
Kevin Veen-Birkenbach
bb0a801396 Fix Git safe.directory handling in E2E containers
- Mark /src and /src/.git as safe to satisfy newer Git ownership checks
- Add '*' as safe.directory for ephemeral test containers to avoid Nix flake failures

https://chatgpt.com/share/693a9e1f-1cc8-800f-9df4-90813cbb6bd5
2025-12-11 11:33:51 +01:00
Kevin Veen-Birkenbach
ee968efc4b Harden E2E test runner and fix Git safe.directory in containers
- Quote Nix store/cache volumes and distro image name in docker run
- Use strict bash flags (set -euo pipefail) inside test container
- Print distro ID robustly with fallback
- Configure /src as Git safe.directory when git is available

https://chatgpt.com/share/693a9c0e-59ec-800f-83a1-eec31bd76962
2025-12-11 11:25:11 +01:00
Kevin Veen-Birkenbach
644b2b8fa0 Align Nix Python environment and add lazy CLI import
- Switch flake package and dev shell to Python 3.11 to match pyproject
- Ensure the python-with-deps environment is preferred on PATH in nix develop
- Introduce a lightweight pkgmgr __init__ with lazy loading of pkgmgr.cli
- Avoid pulling in CLI/config dependencies on plain `import pkgmgr`, fixing
  unit test imports and PyYAML availability in the Nix test containers

https://chatgpt.com/share/693a9723-27ac-800f-a6c2-c1bcc91b7dff
2025-12-11 11:04:12 +01:00
Kevin Veen-Birkenbach
0f74907f82 flake.nix: switch to generic python3 and remove side-effects from pkgmgr package root
- Replace hardcoded python311 references with generic python3 to avoid minor
  version pinning and ensure consistent interpreter selection across systems.
- Use python.pkgs instead of python311Packages in the build pipeline.
- Update devShell to use python3.withPackages, including pip and pyyaml.
- Add Python version echo in shellHook for improved debugging.
- Remove cli re-export from src/pkgmgr/__init__.py to eliminate heavy
  side-effects during import and prevent premature config loading in tests.
2025-12-11 10:30:19 +01:00
Kevin Veen-Birkenbach
5a8b1b11de arch packaging: exclude assets from PKGBUILD rsync
Exclude the assets/ directory from the PKGBUILD rsync step to avoid
permission issues (e.g. map.png) when building the Arch package in
Docker as aur_builder.

https://chatgpt.com/share/693a8c25-4464-800f-8d5e-5c4579d78b52
2025-12-11 10:17:14 +01:00
Kevin Veen-Birkenbach
389ec40163 Refine Nix dev shell, ensure PyYAML availability, fix Python invocation, and
expose pkgmgr.cli for Python 3.13 compatibility

- Add `.nix-dev-installed` to .gitignore
- Improve flake.nix:
  * unify pkgs/pyPkgs definitions
  * provide python311.withPackages including pip + PyYAML
  * remove unused pkgmgrPkg reference from devShell
  * fix PYTHONPATH export and devShell help message
- Update unit/integration test scripts to use `python3 -m unittest`
- Add top-level pkgmgr.__init__ exposing `cli` attribute for
  pkgutil.resolve_name compatibility under Python 3.13+
2025-12-11 09:33:55 +01:00
Kevin Veen-Birkenbach
1d03055491 Removed ignore files 2025-12-11 09:07:18 +01:00
Kevin Veen-Birkenbach
7775c6d974 Refine packaging layout and Arch build paths
* Move Arch-specific ignore rules into `packaging/arch/.gitignore` and simplify top-level `.gitignore`/`.dockerignore`.
* Update Arch `PKGBUILD` to sync from the project root and drop `packaging/` from the installed tree.
* Fix OS-specific `package.sh` helpers to resolve the new `packaging/*` locations correctly for Arch, Debian/Ubuntu, Fedora, and CentOS.
2025-12-11 09:04:17 +01:00
Kevin Veen-Birkenbach
a24a819511 Restructure repo layout, wiring src/ and packaging for local and distro builds
- Add dev runner main.py that prefers local src/ over installed pkgmgr
- Move Arch/Debian/Fedora packaging files under packaging/* and update build scripts
- Adjust .gitignore/.dockerignore for new packaging paths and src/source/
- Improve config defaults discovery to support src/ layout and installed packages
- Update architecture diagram and add TODO overview for TAGS/MIRROR/SIGNING_KEY

https://chatgpt.com/share/693a76a0-e408-800f-9939-868524cbef4d
2025-12-11 08:45:07 +01:00
105 changed files with 438 additions and 103 deletions

View File

@@ -25,7 +25,5 @@ venv/
.DS_Store .DS_Store
Thumbs.db Thumbs.db
# Arch pkg artifacts # Logs
*.pkg.tar.*
*.log *.log
package-manager-*

26
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: CI
on:
push:
branches-ignore:
- main
pull_request:
jobs:
test-unit:
uses: ./.github/workflows/test-unit.yml
test-integration:
uses: ./.github/workflows/test-integration.yml
test-container:
uses: ./.github/workflows/test-container.yml
test-e2e:
uses: ./.github/workflows/test-e2e.yml
test-virgin-user:
uses: ./.github/workflows/test-virgin-user.yml
test-virgin-root:
uses: ./.github/workflows/test-virgin-root.yml

64
.github/workflows/mark-stable.yml vendored Normal file
View File

@@ -0,0 +1,64 @@
name: Mark stable commit
on:
push:
branches:
- main
jobs:
test-unit:
uses: ./.github/workflows/test-unit.yml
test-integration:
uses: ./.github/workflows/test-integration.yml
test-container:
uses: ./.github/workflows/test-container.yml
test-e2e:
uses: ./.github/workflows/test-e2e.yml
test-virgin-user:
uses: ./.github/workflows/test-virgin-user.yml
test-virgin-root:
uses: ./.github/workflows/test-virgin-root.yml
mark-stable:
needs:
- test-unit
- test-integration
- test-container
- test-e2e
- test-virgin-user
- test-virgin-root
runs-on: ubuntu-latest
permissions:
contents: write # to move the tag
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Move 'stable' tag to this commit
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
echo "Tagging commit $GITHUB_SHA as stable…"
# delete local tag if exists
git tag -d stable 2>/dev/null || true
# delete remote tag if exists
git push origin :refs/tags/stable || true
# create new tag on this commit
git tag stable "$GITHUB_SHA"
git push origin stable
echo "✅ Stable tag updated."

View File

@@ -1,13 +1,7 @@
name: Test OS Containers name: Test OS Containers
on: on:
push: workflow_call:
branches:
- main
- master
- develop
- "*"
pull_request:
jobs: jobs:
test-container: test-container:

View File

@@ -1,13 +1,7 @@
name: Test End-To-End name: Test End-To-End
on: on:
push: workflow_call:
branches:
- main
- master
- develop
- "*"
pull_request:
jobs: jobs:
test-e2e: test-e2e:

View File

@@ -1,13 +1,7 @@
name: Test Code Integration name: Test Code Integration
on: on:
push: workflow_call:
branches:
- main
- master
- develop
- "*"
pull_request:
jobs: jobs:
test-integration: test-integration:

View File

@@ -1,13 +1,7 @@
name: Test Units name: Test Units
on: on:
push: workflow_call:
branches:
- main
- master
- develop
- "*"
pull_request:
jobs: jobs:
test-unit: test-unit:

View File

@@ -1,13 +1,7 @@
name: Test Virgin Root name: Test Virgin Root
on: on:
push: workflow_call:
branches:
- main
- master
- develop
- "*"
pull_request:
jobs: jobs:
test-virgin-root: test-virgin-root:

View File

@@ -1,13 +1,7 @@
name: Test Virgin User name: Test Virgin User
on: on:
push: workflow_call:
branches:
- main
- master
- develop
- "*"
pull_request:
jobs: jobs:
test-virgin-user: test-virgin-user:

12
.gitignore vendored
View File

@@ -14,17 +14,8 @@ venv/
dist/ dist/
build/* build/*
*.egg-info/ *.egg-info/
pkg
src/source
package-manager-* package-manager-*
# debian
debian/package-manager/
debian/debhelper-build-stamp
debian/files
debian/.debhelper/
debian/package-manager.substvars
# Editor files # Editor files
.vscode/ .vscode/
.idea/ .idea/
@@ -35,6 +26,9 @@ Thumbs.db
# Nix Cache to speed up tests # Nix Cache to speed up tests
.nix/ .nix/
.nix-dev-installed
# Ignore logs # Ignore logs
*.log *.log
result

View File

@@ -31,7 +31,7 @@ installation layers, and setup controller flow:
![PKGMGR Architecture](assets/map.png) ![PKGMGR Architecture](assets/map.png)
**Diagram status:** *Stand: 10. Dezember 2025* **Diagram status:** *Stand: 11. Dezember 2025*
**Always-up-to-date version:** https://s.veen.world/pkgmgrmp **Always-up-to-date version:** https://s.veen.world/pkgmgrmp
## Installation ⚙️ ## Installation ⚙️

7
TODO.md Normal file
View File

@@ -0,0 +1,7 @@
# to-dos
For the following checkout the implementation map:
- Implement TAGS
- Implement MIRROR
- Implement SIGNING_KEY

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

27
flake.lock generated Normal file
View File

@@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1765186076,
"narHash": "sha256-hM20uyap1a0M9d344I692r+ik4gTMyj60cQWO+hAYP8=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "addf7cf5f383a3101ecfba091b98d0a1263dc9b8",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

View File

@@ -26,6 +26,11 @@
packages = forAllSystems (system: packages = forAllSystems (system:
let let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
# Single source of truth for pkgmgr: Python 3.11
# - Matches pyproject.toml: requires-python = ">=3.11"
# - Uses python311Packages so that PyYAML etc. are available
python = pkgs.python311;
pyPkgs = pkgs.python311Packages; pyPkgs = pkgs.python311Packages;
in in
rec { rec {
@@ -45,7 +50,7 @@
pyPkgs.wheel pyPkgs.wheel
]; ];
# Runtime dependencies (matches [project.dependencies]) # Runtime dependencies (matches [project.dependencies] in pyproject.toml)
propagatedBuildInputs = [ propagatedBuildInputs = [
pyPkgs.pyyaml pyPkgs.pyyaml
pyPkgs.pip pyPkgs.pip
@@ -55,6 +60,7 @@
pythonImportsCheck = [ "pkgmgr" ]; pythonImportsCheck = [ "pkgmgr" ];
}; };
default = pkgmgr; default = pkgmgr;
} }
); );
@@ -65,29 +71,42 @@
devShells = forAllSystems (system: devShells = forAllSystems (system:
let let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
pkgmgrPkg = self.packages.${system}.pkgmgr;
ansiblePkg = ansiblePkg =
if pkgs ? ansible-core then pkgs.ansible-core if pkgs ? ansible-core then pkgs.ansible-core
else pkgs.ansible; else pkgs.ansible;
# Python 3 + pip für alles, was "python3 -m pip" macht # Use the same Python version as the package (3.11)
pythonWithPip = pkgs.python3.withPackages (ps: [ python = pkgs.python311;
pythonWithDeps = python.withPackages (ps: [
ps.pip ps.pip
ps.pyyaml
]); ]);
in in
{ {
default = pkgs.mkShell { default = pkgs.mkShell {
buildInputs = [ buildInputs = [
pythonWithPip pythonWithDeps
pkgmgrPkg
pkgs.git pkgs.git
ansiblePkg ansiblePkg
]; ];
shellHook = '' shellHook = ''
# Ensure our Python with dependencies is preferred on PATH
export PATH=${pythonWithDeps}/bin:$PATH
# Ensure src/ layout is importable:
# pkgmgr lives in ./src/pkgmgr
export PYTHONPATH="$PWD/src:${PYTHONPATH:-}"
# Also add repo root in case tools/tests rely on it
export PYTHONPATH="$PWD:$PYTHONPATH"
echo "Entered pkgmgr development shell for ${system}" echo "Entered pkgmgr development shell for ${system}"
echo "pkgmgr CLI is available via the flake build" echo "Python used in this shell:"
python --version
echo "pkgmgr CLI (from source) is available via:"
echo " python -m pkgmgr.cli --help"
''; '';
}; };
} }

View File

@@ -1,4 +1,12 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import sys
from pathlib import Path
# Ensure local src/ overrides installed package
ROOT = Path(__file__).resolve().parent
SRC = ROOT / "src"
if SRC.is_dir():
sys.path.insert(0, str(SRC))
from pkgmgr.cli import main from pkgmgr.cli import main

6
packaging/arch/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
# Arch pkg artifacts
*.pkg.tar.*
*.log
package-manager-*
src/
pkg/

View File

@@ -15,7 +15,7 @@ makedepends=('rsync')
install=${pkgname}.install install=${pkgname}.install
# Local source checkout — avoids the tarball requirement. # Local source checkout — avoids the tarball requirement.
# This assumes you build the package from inside the main project repository. # We build from the project root (two levels above packaging/arch/).
source=() source=()
sha256sums=() sha256sums=()
@@ -24,12 +24,18 @@ _srcdir_name="source"
prepare() { prepare() {
mkdir -p "$srcdir/$_srcdir_name" mkdir -p "$srcdir/$_srcdir_name"
local project_root
project_root="$(cd "$startdir/../.." && pwd)"
rsync -a \ rsync -a \
--exclude=".git" \ --exclude=".git" \
--exclude=".github" \ --exclude=".github" \
--exclude="pkg" \ --exclude="pkg" \
--exclude="srcpkg" \ --exclude="srcpkg" \
"$startdir/" "$srcdir/$_srcdir_name/" --exclude="packaging" \
--exclude="assets" \
"$project_root/" "$srcdir/$_srcdir_name/"
} }
build() { build() {
@@ -62,7 +68,8 @@ package() {
"$pkgdir/usr/lib/package-manager/PKGBUILD" \ "$pkgdir/usr/lib/package-manager/PKGBUILD" \
"$pkgdir/usr/lib/package-manager/Dockerfile" \ "$pkgdir/usr/lib/package-manager/Dockerfile" \
"$pkgdir/usr/lib/package-manager/debian" \ "$pkgdir/usr/lib/package-manager/debian" \
"$pkgdir/usr/lib/package-manager/packaging" \
"$pkgdir/usr/lib/package-manager/.gitignore" \ "$pkgdir/usr/lib/package-manager/.gitignore" \
"$pkgdir/usr/lib/package-manager/__pycache__" \ "$pkgdir/usr/lib/package-manager/__pycache__" \
"$pkgdir/usr/lib/package-manager/.gitkeep" "$pkgdir/usr/lib/package-manager/.gitkeep" || true
} }

6
packaging/debian/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
# debian
package-manager/
debhelper-build-stamp
files
.debhelper/
package-manager.substvars

View File

@@ -39,13 +39,13 @@ pkgmgr = "pkgmgr.cli:main"
# ----------------------------- # -----------------------------
# setuptools configuration # setuptools configuration
# ----------------------------- # -----------------------------
# We use find_packages(), not a fixed list, # Source layout: all packages live under "src/"
# and explicitly include pkgmgr* and config* [tool.setuptools]
package-dir = { "" = "src", "config" = "config" }
[tool.setuptools.packages.find] [tool.setuptools.packages.find]
where = ["."] where = ["src", "."]
include = ["pkgmgr*", "config*"] include = ["pkgmgr*", "config*"]
# Ensure defaults.yaml is shipped inside wheels & nix builds
[tool.setuptools.package-data] [tool.setuptools.package-data]
"config" = ["defaults.yaml"] "config" = ["defaults.yaml"]

View File

@@ -3,10 +3,21 @@ set -euo pipefail
echo "[arch/package] Building Arch package (makepkg --nodeps)..." echo "[arch/package] Building Arch package (makepkg --nodeps)..."
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
PKG_DIR="${PROJECT_ROOT}/packaging/arch"
if [[ ! -f "${PKG_DIR}/PKGBUILD" ]]; then
echo "[arch/package] ERROR: PKGBUILD not found in ${PKG_DIR}"
exit 1
fi
cd "${PKG_DIR}"
if id aur_builder >/dev/null 2>&1; then if id aur_builder >/dev/null 2>&1; then
echo "[arch/package] Using 'aur_builder' user for makepkg..." echo "[arch/package] Using 'aur_builder' user for makepkg..."
chown -R aur_builder:aur_builder "$(pwd)" chown -R aur_builder:aur_builder "${PKG_DIR}"
su aur_builder -c "cd '$(pwd)' && rm -f package-manager-*.pkg.tar.* && makepkg --noconfirm --clean --nodeps" su aur_builder -c "cd '${PKG_DIR}' && rm -f package-manager-*.pkg.tar.* && makepkg --noconfirm --clean --nodeps"
else else
echo "[arch/package] WARNING: user 'aur_builder' not found, running makepkg as current user..." echo "[arch/package] WARNING: user 'aur_builder' not found, running makepkg as current user..."
rm -f package-manager-*.pkg.tar.* rm -f package-manager-*.pkg.tar.*

View File

@@ -4,8 +4,17 @@ set -euo pipefail
echo "[centos/package] Setting up rpmbuild directories..." echo "[centos/package] Setting up rpmbuild directories..."
mkdir -p /root/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS} mkdir -p /root/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
SPEC_PATH="${PROJECT_ROOT}/packaging/fedora/package-manager.spec"
if [[ ! -f "${SPEC_PATH}" ]]; then
echo "[centos/package] ERROR: SPEC file not found: ${SPEC_PATH}"
exit 1
fi
echo "[centos/package] Extracting version from package-manager.spec..." echo "[centos/package] Extracting version from package-manager.spec..."
version="$(grep -E '^Version:' package-manager.spec | awk '{print $2}')" version="$(grep -E '^Version:' "${SPEC_PATH}" | awk '{print $2}')"
if [[ -z "${version}" ]]; then if [[ -z "${version}" ]]; then
echo "ERROR: Version missing!" echo "ERROR: Version missing!"
exit 1 exit 1
@@ -15,13 +24,13 @@ srcdir="package-manager-${version}"
echo "[centos/package] Preparing source tree: ${srcdir}" echo "[centos/package] Preparing source tree: ${srcdir}"
rm -rf "/tmp/${srcdir}" rm -rf "/tmp/${srcdir}"
mkdir -p "/tmp/${srcdir}" mkdir -p "/tmp/${srcdir}"
cp -a . "/tmp/${srcdir}/" cp -a "${PROJECT_ROOT}/." "/tmp/${srcdir}/"
echo "[centos/package] Creating source tarball..." echo "[centos/package] Creating source tarball..."
tar czf "/root/rpmbuild/SOURCES/${srcdir}.tar.gz" -C /tmp "${srcdir}" tar czf "/root/rpmbuild/SOURCES/${srcdir}.tar.gz" -C /tmp "${srcdir}"
echo "[centos/package] Copying SPEC..." echo "[centos/package] Copying SPEC..."
cp package-manager.spec /root/rpmbuild/SPECS/ cp "${SPEC_PATH}" /root/rpmbuild/SPECS/
echo "[centos/package] Running rpmbuild..." echo "[centos/package] Running rpmbuild..."
cd /root/rpmbuild/SPECS cd /root/rpmbuild/SPECS

View File

@@ -3,6 +3,25 @@ set -euo pipefail
echo "[debian/package] Building Debian package..." echo "[debian/package] Building Debian package..."
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
BUILD_ROOT="/tmp/package-manager-debian-build"
rm -rf "${BUILD_ROOT}"
mkdir -p "${BUILD_ROOT}"
echo "[debian/package] Syncing project sources to ${BUILD_ROOT}..."
rsync -a \
--exclude 'packaging/debian' \
"${PROJECT_ROOT}/" "${BUILD_ROOT}/"
echo "[debian/package] Overlaying debian/ metadata from packaging/debian..."
mkdir -p "${BUILD_ROOT}/debian"
cp -a "${PROJECT_ROOT}/packaging/debian/." "${BUILD_ROOT}/debian/"
cd "${BUILD_ROOT}"
echo "[debian/package] Running dpkg-buildpackage..."
dpkg-buildpackage -us -uc -b dpkg-buildpackage -us -uc -b
echo "[debian/package] Installing generated DEB package..." echo "[debian/package] Installing generated DEB package..."

View File

@@ -4,8 +4,17 @@ set -euo pipefail
echo "[fedora/package] Setting up rpmbuild directories..." echo "[fedora/package] Setting up rpmbuild directories..."
mkdir -p /root/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS} mkdir -p /root/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
SPEC_PATH="${PROJECT_ROOT}/packaging/fedora/package-manager.spec"
if [[ ! -f "${SPEC_PATH}" ]]; then
echo "[fedora/package] ERROR: SPEC file not found: ${SPEC_PATH}"
exit 1
fi
echo "[fedora/package] Extracting version from package-manager.spec..." echo "[fedora/package] Extracting version from package-manager.spec..."
version="$(grep -E '^Version:' package-manager.spec | awk '{print $2}')" version="$(grep -E '^Version:' "${SPEC_PATH}" | awk '{print $2}')"
if [[ -z "${version}" ]]; then if [[ -z "${version}" ]]; then
echo "ERROR: Version missing!" echo "ERROR: Version missing!"
exit 1 exit 1
@@ -15,13 +24,13 @@ srcdir="package-manager-${version}"
echo "[fedora/package] Preparing source tree: ${srcdir}" echo "[fedora/package] Preparing source tree: ${srcdir}"
rm -rf "/tmp/${srcdir}" rm -rf "/tmp/${srcdir}"
mkdir -p "/tmp/${srcdir}" mkdir -p "/tmp/${srcdir}"
cp -a . "/tmp/${srcdir}/" cp -a "${PROJECT_ROOT}/." "/tmp/${srcdir}/"
echo "[fedora/package] Creating source tarball..." echo "[fedora/package] Creating source tarball..."
tar czf "/root/rpmbuild/SOURCES/${srcdir}.tar.gz" -C /tmp "${srcdir}" tar czf "/root/rpmbuild/SOURCES/${srcdir}.tar.gz" -C /tmp "${srcdir}"
echo "[fedora/package] Copying SPEC..." echo "[fedora/package] Copying SPEC..."
cp package-manager.spec /root/rpmbuild/SPECS/ cp "${SPEC_PATH}" /root/rpmbuild/SPECS/
echo "[fedora/package] Running rpmbuild..." echo "[fedora/package] Running rpmbuild..."
cd /root/rpmbuild/SPECS cd /root/rpmbuild/SPECS

View File

@@ -3,6 +3,25 @@ set -euo pipefail
echo "[ubuntu/package] Building Ubuntu (Debian-style) package..." echo "[ubuntu/package] Building Ubuntu (Debian-style) package..."
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
BUILD_ROOT="/tmp/package-manager-ubuntu-build"
rm -rf "${BUILD_ROOT}"
mkdir -p "${BUILD_ROOT}"
echo "[ubuntu/package] Syncing project sources to ${BUILD_ROOT}..."
rsync -a \
--exclude 'packaging/debian' \
"${PROJECT_ROOT}/" "${BUILD_ROOT}/"
echo "[ubuntu/package] Overlaying debian/ metadata from packaging/debian..."
mkdir -p "${BUILD_ROOT}/debian"
cp -a "${PROJECT_ROOT}/packaging/debian/." "${BUILD_ROOT}/debian/"
cd "${BUILD_ROOT}"
echo "[ubuntu/package] Running dpkg-buildpackage..."
dpkg-buildpackage -us -uc -b dpkg-buildpackage -us -uc -b
echo "[ubuntu/package] Installing generated DEB package..." echo "[ubuntu/package] Installing generated DEB package..."

View File

@@ -10,24 +10,24 @@ for distro in $DISTROS; do
docker run --rm \ docker run --rm \
-v "$(pwd):/src" \ -v "$(pwd):/src" \
-v pkgmgr_nix_store_${distro}:/nix \ -v "pkgmgr_nix_store_${distro}:/nix" \
-v "pkgmgr_nix_cache_${distro}:/root/.cache/nix" \ -v "pkgmgr_nix_cache_${distro}:/root/.cache/nix" \
-e PKGMGR_DEV=1 \ -e PKGMGR_DEV=1 \
-e TEST_PATTERN="${TEST_PATTERN}" \ -e TEST_PATTERN="${TEST_PATTERN}" \
--workdir /src \ --workdir /src \
--entrypoint bash \ --entrypoint bash \
"package-manager-test-$distro" \ "package-manager-test-${distro}" \
-c ' -c '
set -e set -euo pipefail
# Load distro info # Load distro info
if [ -f /etc/os-release ]; then if [ -f /etc/os-release ]; then
. /etc/os-release . /etc/os-release
fi fi
echo "Running tests inside distro: $ID" echo "Running tests inside distro: ${ID:-unknown}"
# Load nix environment if available # Load Nix environment if available
if [ -f "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh" ]; then if [ -f "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh" ]; then
. "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh" . "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh"
fi fi
@@ -43,8 +43,18 @@ for distro in $DISTROS; do
exit 1 exit 1
} }
# Mark the mounted repository as safe to avoid Git ownership errors # Mark the mounted repository as safe to avoid Git ownership errors.
# Newer Git (e.g. on Ubuntu) complains about the gitdir (/src/.git),
# older versions about the worktree (/src). Nix turns "." into the
# flake input "git+file:///src", which then uses Git under the hood.
if command -v git >/dev/null 2>&1; then
# Worktree path
git config --global --add safe.directory /src || true git config --global --add safe.directory /src || true
# Gitdir path shown in the "dubious ownership" error
git config --global --add safe.directory /src/.git || true
# Ephemeral CI containers: allow all paths as a last resort
git config --global --add safe.directory '*' || true
fi
# Run the E2E tests inside the Nix development shell # Run the E2E tests inside the Nix development shell
nix develop .#default --no-write-lock-file -c \ nix develop .#default --no-write-lock-file -c \

View File

@@ -20,7 +20,7 @@ docker run --rm \
set -e; set -e;
git config --global --add safe.directory /src || true; git config --global --add safe.directory /src || true;
nix develop .#default --no-write-lock-file -c \ nix develop .#default --no-write-lock-file -c \
python -m unittest discover \ python3 -m unittest discover \
-s tests/integration \ -s tests/integration \
-t /src \ -t /src \
-p "$TEST_PATTERN"; -p "$TEST_PATTERN";

View File

@@ -20,7 +20,7 @@ docker run --rm \
set -e; set -e;
git config --global --add safe.directory /src || true; git config --global --add safe.directory /src || true;
nix develop .#default --no-write-lock-file -c \ nix develop .#default --no-write-lock-file -c \
python -m unittest discover \ python3 -m unittest discover \
-s tests/unit \ -s tests/unit \
-t /src \ -t /src \
-p "$TEST_PATTERN"; -p "$TEST_PATTERN";

36
src/pkgmgr/__init__.py Normal file
View File

@@ -0,0 +1,36 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Top-level pkgmgr package.
We deliberately avoid importing heavy submodules (like the CLI)
on import to keep unit tests fast and to not require optional
dependencies (like PyYAML) unless they are actually used.
Accessing ``pkgmgr.cli`` will load the CLI module lazily via
``__getattr__``. This keeps patterns like
from pkgmgr import cli
working as expected in tests and entry points.
"""
from __future__ import annotations
from importlib import import_module
from typing import Any
__all__ = ["cli"]
def __getattr__(name: str) -> Any:
"""
Lazily expose ``pkgmgr.cli`` as attribute on the top-level package.
This keeps ``import pkgmgr`` lightweight while still allowing
``from pkgmgr import cli`` in tests and entry points.
"""
if name == "cli":
return import_module("pkgmgr.cli")
raise AttributeError(f"module 'pkgmgr' has no attribute {name!r}")

View File

@@ -197,13 +197,8 @@ def _load_layer_dir(
def _load_defaults_from_package_or_project() -> Dict[str, Any]: def _load_defaults_from_package_or_project() -> Dict[str, Any]:
""" """
Fallback: Versuche Defaults aus dem installierten Paket ODER Fallback: load default configs from various possible install or development
aus dem Projekt-Root zu laden: layouts (pip-installed, editable install, source repo with src/ layout).
<pkg_root>/config_defaults
<pkg_root>/config
<project_root>/config_defaults
<project_root>/config
""" """
try: try:
import pkgmgr # type: ignore import pkgmgr # type: ignore
@@ -211,14 +206,25 @@ def _load_defaults_from_package_or_project() -> Dict[str, Any]:
return {"directories": {}, "repositories": []} return {"directories": {}, "repositories": []}
pkg_root = Path(pkgmgr.__file__).resolve().parent pkg_root = Path(pkgmgr.__file__).resolve().parent
project_root = pkg_root.parent roots = set()
candidates = [ # Case 1: installed package (site-packages/pkgmgr)
pkg_root / "config_defaults", roots.add(pkg_root)
pkg_root / "config",
project_root / "config_defaults", # Case 2: parent directory (site-packages/, src/)
project_root / "config", roots.add(pkg_root.parent)
]
# Case 3: src-layout during development:
# repo_root/src/pkgmgr -> repo_root
parent = pkg_root.parent
if parent.name == "src":
roots.add(parent.parent)
# Candidate config dirs
candidates = []
for root in roots:
candidates.append(root / "config_defaults")
candidates.append(root / "config")
for cand in candidates: for cand in candidates:
defaults = _load_layer_dir(cand, skip_filename=None) defaults = _load_layer_dir(cand, skip_filename=None)
@@ -227,7 +233,6 @@ def _load_defaults_from_package_or_project() -> Dict[str, Any]:
return {"directories": {}, "repositories": []} return {"directories": {}, "repositories": []}
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Hauptfunktion # Hauptfunktion
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------

Some files were not shown because too many files have changed in this diff Show More