Compare commits

...

5 Commits

Author SHA1 Message Date
Kevin Veen-Birkenbach
955028288f Release version 1.8.4
Some checks are pending
Mark stable commit / test-unit (push) Waiting to run
Mark stable commit / test-integration (push) Waiting to run
Mark stable commit / test-env-virtual (push) Waiting to run
Mark stable commit / test-env-nix (push) Waiting to run
Mark stable commit / test-e2e (push) Waiting to run
Mark stable commit / test-virgin-user (push) Waiting to run
Mark stable commit / test-virgin-root (push) Waiting to run
Mark stable commit / lint-shell (push) Waiting to run
Mark stable commit / lint-python (push) Waiting to run
Mark stable commit / mark-stable (push) Blocked by required conditions
2025-12-17 11:20:16 +01:00
Kevin Veen-Birkenbach
866572e252 ci(docker): fix repo mount path for pkgmgr as base layer of Infinito.Nexus
Some checks failed
Mark stable commit / test-unit (push) Has been cancelled
Mark stable commit / test-integration (push) Has been cancelled
Mark stable commit / test-env-virtual (push) Has been cancelled
Mark stable commit / test-env-nix (push) Has been cancelled
Mark stable commit / test-e2e (push) Has been cancelled
Mark stable commit / test-virgin-user (push) Has been cancelled
Mark stable commit / test-virgin-root (push) Has been cancelled
Mark stable commit / lint-shell (push) Has been cancelled
Mark stable commit / lint-python (push) Has been cancelled
Mark stable commit / mark-stable (push) Has been cancelled
Standardize Docker/CI/test environments to mount pkgmgr at /opt/src/pkgmgr.
This makes the layering explicit: pkgmgr is the lower-level foundation used by
Infinito.Nexus.

Infra-only change (Docker, CI, shell scripts). No runtime or Nix semantics changed.

https://chatgpt.com/share/69427fe7-e288-800f-90a4-c1c3c11a8484
2025-12-17 11:03:02 +01:00
Kevin Veen-Birkenbach
b0a733369e Optimized output for debugging
Some checks failed
Mark stable commit / test-unit (push) Has been cancelled
Mark stable commit / test-integration (push) Has been cancelled
Mark stable commit / test-env-virtual (push) Has been cancelled
Mark stable commit / test-env-nix (push) Has been cancelled
Mark stable commit / test-e2e (push) Has been cancelled
Mark stable commit / test-virgin-user (push) Has been cancelled
Mark stable commit / test-virgin-root (push) Has been cancelled
Mark stable commit / lint-shell (push) Has been cancelled
Mark stable commit / lint-python (push) Has been cancelled
Mark stable commit / mark-stable (push) Has been cancelled
2025-12-17 10:51:56 +01:00
Kevin Veen-Birkenbach
c5843ccd30 Release version 1.8.3
Some checks failed
Mark stable commit / test-unit (push) Has been cancelled
Mark stable commit / test-integration (push) Has been cancelled
Mark stable commit / test-env-virtual (push) Has been cancelled
Mark stable commit / test-env-nix (push) Has been cancelled
Mark stable commit / test-e2e (push) Has been cancelled
Mark stable commit / test-virgin-user (push) Has been cancelled
Mark stable commit / test-virgin-root (push) Has been cancelled
Mark stable commit / lint-shell (push) Has been cancelled
Mark stable commit / lint-python (push) Has been cancelled
Mark stable commit / mark-stable (push) Has been cancelled
2025-12-16 19:49:51 +01:00
Kevin Veen-Birkenbach
3cb7852cb4 feat(mirrors): support URL-only MIRRORS entries and keep git config clean
- Allow MIRRORS to contain plain URLs (one per line) in addition to legacy "NAME URL"
- Treat strings as single URLs to avoid iterable pitfalls
- Write PyPI URLs as metadata-only entries (never added to git config)
- Keep MIRRORS as the single source of truth for mirror setup
- Update integration test to assert URL-only MIRRORS output

https://chatgpt.com/share/6941a9aa-b8b4-800f-963d-2486b34856b1
2025-12-16 19:49:09 +01:00
19 changed files with 128 additions and 63 deletions

View File

@@ -31,15 +31,15 @@ jobs:
set -euo pipefail
docker run --rm \
-v "$PWD":/src \
-v "$PWD":/opt/src/pkgmgr \
-v pkgmgr_repos:/root/Repositories \
-v pkgmgr_pip_cache:/root/.cache/pip \
-w /src \
-w /opt/src/pkgmgr \
"pkgmgr-${{ matrix.distro }}-virgin" \
bash -lc '
set -euo pipefail
git config --global --add safe.directory /src
git config --global --add safe.directory /opt/src/pkgmgr
make install
make setup
@@ -50,5 +50,5 @@ jobs:
pkgmgr version pkgmgr
echo ">>> Running Nix-based: nix run .#pkgmgr -- version pkgmgr"
nix run /src#pkgmgr -- version pkgmgr
nix run /opt/src/pkgmgr#pkgmgr -- version pkgmgr
'

View File

@@ -31,8 +31,8 @@ jobs:
set -euo pipefail
docker run --rm \
-v "$PWD":/src \
-w /src \
-v "$PWD":/opt/src/pkgmgr \
-w /opt/src/pkgmgr \
"pkgmgr-${{ matrix.distro }}-virgin" \
bash -lc '
set -euo pipefail
@@ -42,7 +42,7 @@ jobs:
useradd -m dev
echo "dev ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/dev
chmod 0440 /etc/sudoers.d/dev
chown -R dev:dev /src
chown -R dev:dev /opt/src/pkgmgr
mkdir -p /nix/store /nix/var/nix /nix/var/log/nix /nix/var/nix/profiles
chown -R dev:dev /nix
@@ -51,7 +51,7 @@ jobs:
sudo -H -u dev env HOME=/home/dev PKGMGR_DISABLE_NIX_FLAKE_INSTALLER=1 bash -lc "
set -euo pipefail
cd /src
cd /opt/src/pkgmgr
make setup-venv
. \"\$HOME/.venvs/pkgmgr/bin/activate\"
@@ -59,6 +59,6 @@ jobs:
pkgmgr version pkgmgr
export NIX_REMOTE=local
nix run /src#pkgmgr -- version pkgmgr
nix run /opt/src/pkgmgr#pkgmgr -- version pkgmgr
"
'

View File

@@ -1,3 +1,13 @@
## [1.8.4] - 2025-12-17
* * Made pkgmgrs base-layer role explicit by standardizing the Docker/CI mount path to *`/opt/src/pkgmgr`*.
## [1.8.3] - 2025-12-16
* MIRRORS now supports plain URL entries, ensuring metadata-only sources like PyPI are recorded without ever being added to the Git configuration.
## [1.8.2] - 2025-12-16
* * ***pkgmgr tools code*** is more robust and predictable: it now fails early with clear errors if VS Code is not installed or a repository is not yet identified.

View File

@@ -50,6 +50,6 @@ RUN set -euo pipefail; \
# Entry point
COPY scripts/docker/entry.sh /usr/local/bin/docker-entry.sh
WORKDIR /src
WORKDIR /opt/src/pkgmgr
ENTRYPOINT ["/usr/local/bin/docker-entry.sh"]
CMD ["pkgmgr", "--help"]

View File

@@ -32,7 +32,7 @@
rec {
pkgmgr = pyPkgs.buildPythonApplication {
pname = "package-manager";
version = "1.8.2";
version = "1.8.4";
# Use the git repo as source
src = ./.;

View File

@@ -1,7 +1,7 @@
# Maintainer: Kevin Veen-Birkenbach <info@veen.world>
pkgname=package-manager
pkgver=1.8.2
pkgver=1.8.4
pkgrel=1
pkgdesc="Local-flake wrapper for Kevin's package-manager (Nix-based)."
arch=('any')

View File

@@ -1,3 +1,15 @@
package-manager (1.8.4-1) unstable; urgency=medium
* * Made pkgmgrs base-layer role explicit by standardizing the Docker/CI mount path to *`/opt/src/pkgmgr`*.
-- Kevin Veen-Birkenbach <kevin@veen.world> Wed, 17 Dec 2025 11:20:16 +0100
package-manager (1.8.3-1) unstable; urgency=medium
* MIRRORS now supports plain URL entries, ensuring metadata-only sources like PyPI are recorded without ever being added to the Git configuration.
-- Kevin Veen-Birkenbach <kevin@veen.world> Tue, 16 Dec 2025 19:49:51 +0100
package-manager (1.8.2-1) unstable; urgency=medium
* * ***pkgmgr tools code*** is more robust and predictable: it now fails early with clear errors if VS Code is not installed or a repository is not yet identified.

View File

@@ -1,5 +1,5 @@
Name: package-manager
Version: 1.8.2
Version: 1.8.4
Release: 1%{?dist}
Summary: Wrapper that runs Kevin's package-manager via Nix flake
@@ -74,6 +74,12 @@ echo ">>> package-manager removed. Nix itself was not removed."
/usr/lib/package-manager/
%changelog
* Wed Dec 17 2025 Kevin Veen-Birkenbach <kevin@veen.world> - 1.8.4-1
- * Made pkgmgrs base-layer role explicit by standardizing the Docker/CI mount path to *`/opt/src/pkgmgr`*.
* Tue Dec 16 2025 Kevin Veen-Birkenbach <kevin@veen.world> - 1.8.3-1
- MIRRORS now supports plain URL entries, ensuring metadata-only sources like PyPI are recorded without ever being added to the Git configuration.
* Tue Dec 16 2025 Kevin Veen-Birkenbach <kevin@veen.world> - 1.8.2-1
- * ***pkgmgr tools code*** is more robust and predictable: it now fails early with clear errors if VS Code is not installed or a repository is not yet identified.

View File

@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "kpmx"
version = "1.8.2"
version = "1.8.4"
description = "Kevin's package-manager tool (pkgmgr)"
readme = "README.md"
requires-python = ">=3.9"

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
echo "[docker] Starting package-manager container"
echo "[docker-pkgmgr] Starting package-manager container"
# ---------------------------------------------------------------------------
# Log distribution info
@@ -9,19 +9,19 @@ echo "[docker] Starting package-manager container"
if [[ -f /etc/os-release ]]; then
# shellcheck disable=SC1091
. /etc/os-release
echo "[docker] Detected distro: ${ID:-unknown} (like: ${ID_LIKE:-})"
echo "[docker-pkgmgr] Detected distro: ${ID:-unknown} (like: ${ID_LIKE:-})"
fi
# Always use /src (mounted from host) as working directory
echo "[docker] Using /src as working directory"
cd /src
# Always use /opt/src/pkgmgr (mounted from host) as working directory
echo "[docker-pkgmgr] Using /opt/src/pkgmgr as working directory"
cd /opt/src/pkgmgr
# ---------------------------------------------------------------------------
# DEV mode: rebuild package-manager from the mounted /src tree
# DEV mode: rebuild package-manager from the mounted /opt/src/pkgmgr tree
# ---------------------------------------------------------------------------
if [[ "${REINSTALL_PKGMGR:-0}" == "1" ]]; then
echo "[docker] DEV mode enabled (REINSTALL_PKGMGR=1)"
echo "[docker] Rebuilding package-manager from /src via scripts/installation/package.sh..."
echo "[docker-pkgmgr] DEV mode enabled (REINSTALL_PKGMGR=1)"
echo "[docker-pkgmgr] Rebuilding package-manager from /opt/src/pkgmgr via scripts/installation/package.sh..."
bash scripts/installation/package.sh || exit 1
fi
@@ -29,9 +29,9 @@ fi
# Hand off to pkgmgr or arbitrary command
# ---------------------------------------------------------------------------
if [[ $# -eq 0 ]]; then
echo "[docker] No arguments provided. Showing pkgmgr help..."
echo "[docker-pkgmgr] No arguments provided. Showing pkgmgr help..."
exec pkgmgr --help
else
echo "[docker] Executing command: $*"
echo "[docker-pkgmgr] Executing command: $*"
exec "$@"
fi

View File

@@ -6,7 +6,7 @@ echo "[arch/package] Building Arch package (makepkg --nodeps) in an isolated bui
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
# We must not build inside /src (mounted repo). Build in /tmp to avoid permission issues.
# We must not build inside /opt/src/pkgmgr (mounted repo). Build in /tmp to avoid permission issues.
BUILD_ROOT="/tmp/package-manager-arch-build"
PKG_SRC_DIR="${PROJECT_ROOT}/packaging/arch"
PKG_BUILD_DIR="${BUILD_ROOT}/packaging/arch"

View File

@@ -6,12 +6,12 @@ echo ">>> Running E2E tests: $PKGMGR_DISTRO"
echo "============================================================"
docker run --rm \
-v "$(pwd):/src" \
-v "$(pwd):/opt/src/pkgmgr" \
-v "pkgmgr_nix_store_${PKGMGR_DISTRO}:/nix" \
-v "pkgmgr_nix_cache_${PKGMGR_DISTRO}:/root/.cache/nix" \
-e REINSTALL_PKGMGR=1 \
-e TEST_PATTERN="${TEST_PATTERN}" \
--workdir /src \
--workdir /opt/src/pkgmgr \
"pkgmgr-${PKGMGR_DISTRO}" \
bash -lc '
set -euo pipefail
@@ -40,14 +40,14 @@ docker run --rm \
}
# 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.
# Newer Git (e.g. on Ubuntu) complains about the gitdir (/opt/src/pkgmgr/.git),
# older versions about the worktree (/opt/src/pkgmgr). Nix turns "." into the
# flake input "git+file:///opt/src/pkgmgr", 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 /opt/src/pkgmgr || true
# Gitdir path shown in the "dubious ownership" error
git config --global --add safe.directory /src/.git || true
git config --global --add safe.directory /opt/src/pkgmgr/.git || true
# Ephemeral CI containers: allow all paths as a last resort
git config --global --add safe.directory "*" || true
fi
@@ -55,6 +55,6 @@ docker run --rm \
# Run the E2E tests inside the Nix development shell
nix develop .#default --no-write-lock-file -c \
python3 -m unittest discover \
-s /src/tests/e2e \
-s /opt/src/pkgmgr/tests/e2e \
-p "$TEST_PATTERN"
'

View File

@@ -9,18 +9,18 @@ echo ">>> Image: ${IMAGE}"
echo "============================================================"
docker run --rm \
-v "$(pwd):/src" \
-v "$(pwd):/opt/src/pkgmgr" \
-v "pkgmgr_nix_store_${PKGMGR_DISTRO}:/nix" \
-v "pkgmgr_nix_cache_${PKGMGR_DISTRO}:/root/.cache/nix" \
--workdir /src \
--workdir /opt/src/pkgmgr \
-e REINSTALL_PKGMGR=1 \
"${IMAGE}" \
bash -lc '
set -euo pipefail
if command -v git >/dev/null 2>&1; then
git config --global --add safe.directory /src || true
git config --global --add safe.directory /src/.git || true
git config --global --add safe.directory /opt/src/pkgmgr || true
git config --global --add safe.directory /opt/src/pkgmgr/.git || true
git config --global --add safe.directory "*" || true
fi
@@ -38,9 +38,9 @@ docker run --rm \
# ------------------------------------------------------------
# Retry helper for GitHub API rate-limit (HTTP 403)
# ------------------------------------------------------------
if [[ -f /src/scripts/nix/lib/retry_403.sh ]]; then
if [[ -f /opt/src/pkgmgr/scripts/nix/lib/retry_403.sh ]]; then
# shellcheck source=./scripts/nix/lib/retry_403.sh
source /src/scripts/nix/lib/retry_403.sh
source /opt/src/pkgmgr/scripts/nix/lib/retry_403.sh
elif [[ -f ./scripts/nix/lib/retry_403.sh ]]; then
# shellcheck source=./scripts/nix/lib/retry_403.sh
source ./scripts/nix/lib/retry_403.sh

View File

@@ -17,8 +17,8 @@ echo
# ------------------------------------------------------------
if OUTPUT=$(docker run --rm \
-e REINSTALL_PKGMGR=1 \
-v "$(pwd):/src" \
-w /src \
-v "$(pwd):/opt/src/pkgmgr" \
-w /opt/src/pkgmgr \
"${IMAGE}" \
bash -lc '
set -euo pipefail

View File

@@ -6,19 +6,19 @@ echo ">>> Running INTEGRATION tests in ${PKGMGR_DISTRO} container"
echo "============================================================"
docker run --rm \
-v "$(pwd):/src" \
-v "$(pwd):/opt/src/pkgmgr" \
-v "pkgmgr_nix_store_${PKGMGR_DISTRO}:/nix" \
-v "pkgmgr_nix_cache_${PKGMGR_DISTRO}:/root/.cache/nix" \
--workdir /src \
--workdir /opt/src/pkgmgr \
-e REINSTALL_PKGMGR=1 \
-e TEST_PATTERN="${TEST_PATTERN}" \
"pkgmgr-${PKGMGR_DISTRO}" \
bash -lc '
set -e;
git config --global --add safe.directory /src || true;
git config --global --add safe.directory /opt/src/pkgmgr || true;
nix develop .#default --no-write-lock-file -c \
python3 -m unittest discover \
-s tests/integration \
-t /src \
-t /opt/src/pkgmgr \
-p "$TEST_PATTERN";
'

View File

@@ -6,19 +6,19 @@ echo ">>> Running UNIT tests in ${PKGMGR_DISTRO} container"
echo "============================================================"
docker run --rm \
-v "$(pwd):/src" \
-v "$(pwd):/opt/src/pkgmgr" \
-v "pkgmgr_nix_cache_${PKGMGR_DISTRO}:/root/.cache/nix" \
-v "pkgmgr_nix_store_${PKGMGR_DISTRO}:/nix" \
--workdir /src \
--workdir /opt/src/pkgmgr \
-e REINSTALL_PKGMGR=1 \
-e TEST_PATTERN="${TEST_PATTERN}" \
"pkgmgr-${PKGMGR_DISTRO}" \
bash -lc '
set -e;
git config --global --add safe.directory /src || true;
git config --global --add safe.directory /opt/src/pkgmgr || true;
nix develop .#default --no-write-lock-file -c \
python3 -m unittest discover \
-s tests/unit \
-t /src \
-t /opt/src/pkgmgr \
-p "$TEST_PATTERN";
'

View File

@@ -1,8 +1,9 @@
from __future__ import annotations
import os
from collections.abc import Iterable, Mapping
from typing import Union
from urllib.parse import urlparse
from typing import Mapping
from .types import MirrorMap, Repository
@@ -32,7 +33,7 @@ def read_mirrors_file(repo_dir: str, filename: str = "MIRRORS") -> MirrorMap:
"""
Supports:
NAME URL
URL auto name = hostname
URL -> auto-generate name from hostname
"""
path = os.path.join(repo_dir, filename)
mirrors: MirrorMap = {}
@@ -52,7 +53,8 @@ def read_mirrors_file(repo_dir: str, filename: str = "MIRRORS") -> MirrorMap:
# Case 1: "name url"
if len(parts) == 2:
name, url = parts
# Case 2: "url" → auto-generate name
# Case 2: "url" -> auto name
elif len(parts) == 1:
url = parts[0]
parsed = urlparse(url)
@@ -67,21 +69,56 @@ def read_mirrors_file(repo_dir: str, filename: str = "MIRRORS") -> MirrorMap:
continue
mirrors[name] = url
except OSError as exc:
print(f"[WARN] Could not read MIRRORS file at {path}: {exc}")
return mirrors
MirrorsInput = Union[Mapping[str, str], Iterable[str]]
def write_mirrors_file(
repo_dir: str,
mirrors: Mapping[str, str],
mirrors: MirrorsInput,
filename: str = "MIRRORS",
preview: bool = False,
) -> None:
"""
Write MIRRORS in one of two formats:
1) Mapping[str, str] -> "NAME URL" per line (legacy / compatible)
2) Iterable[str] -> "URL" per line (new preferred)
Strings are treated as a single URL (not iterated character-by-character).
"""
path = os.path.join(repo_dir, filename)
lines = [f"{name} {url}" for name, url in sorted(mirrors.items())]
lines: list[str]
if isinstance(mirrors, Mapping):
items = [
(str(name), str(url))
for name, url in mirrors.items()
if url is not None and str(url).strip()
]
items.sort(key=lambda x: (x[0], x[1]))
lines = [f"{name} {url}" for name, url in items]
else:
if isinstance(mirrors, (str, bytes)):
urls = [str(mirrors).strip()]
else:
urls = [
str(url).strip()
for url in mirrors
if url is not None and str(url).strip()
]
urls = sorted(set(urls))
lines = urls
content = "\n".join(lines) + ("\n" if lines else "")
if preview:
@@ -94,5 +131,6 @@ def write_mirrors_file(
with open(path, "w", encoding="utf-8") as fh:
fh.write(content)
print(f"[INFO] Wrote MIRRORS file at {path}")
except OSError as exc:
print(f"[ERROR] Failed to write MIRRORS file at {path}: {exc}")

View File

@@ -12,8 +12,8 @@ class MirrorBootstrapper:
"""
MIRRORS is the single source of truth.
We write defaults to MIRRORS and then call mirror setup which will
configure git remotes based on MIRRORS content (but only for git URLs).
Defaults are written to MIRRORS and mirror setup derives
git remotes exclusively from that file (git URLs only).
"""
def write_defaults(
@@ -25,10 +25,8 @@ class MirrorBootstrapper:
preview: bool,
) -> None:
mirrors = {
# preferred SSH url is supplied by CreateRepoPlanner.primary_remote
"origin": primary,
# metadata only: must NEVER be configured as a git remote
"pypi": f"https://pypi.org/project/{name}/",
primary,
f"https://pypi.org/project/{name}/",
}
write_mirrors_file(repo_dir, mirrors, preview=preview)
@@ -41,7 +39,8 @@ class MirrorBootstrapper:
preview: bool,
remote: bool,
) -> None:
# IMPORTANT: do NOT set repo["mirrors"] here.
# IMPORTANT:
# Do NOT set repo["mirrors"] here.
# MIRRORS file is the single source of truth.
setup_mirrors(
selected_repos=[repo],

View File

@@ -75,12 +75,12 @@ class TestCreateRepoPypiNotInGitConfig(unittest.TestCase):
mirrors_content = mirrors_file.read_text(encoding="utf-8")
self.assertIn(
"pypi https://pypi.org/project/repo/",
"https://pypi.org/project/repo/",
mirrors_content,
"PyPI mirror entry must exist in MIRRORS",
)
self.assertIn(
"origin git@github.com:acme/repo.git",
"git@github.com:acme/repo.git",
mirrors_content,
"origin SSH URL must exist in MIRRORS",
)