Skip to content

Reuse deployed CVMFS releases - #110

Merged
pbuncic merged 30 commits into
mainfrom
feature/reuse-from-modules
Aug 25, 2026
Merged

Reuse deployed CVMFS releases#110
pbuncic merged 30 commits into
mainfrom
feature/reuse-from-modules

Conversation

@pbuncic

@pbuncic pbuncic commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

This makes it possible to re-use bits packages deployed on CVMFS in subsequent builds.

pbuncic added 30 commits August 24, 2026 16:47
Introduce --reuse-from <abs-path>|cvmfs, the module-based reuse source,
kept separate from --remote-store (the tarball store). 'cvmfs' resolves
module_path from the defaults system: layout, failing if unset. Pure
resolver resolve_reuse_from; nothing consumes the value yet.
Add rewrite_module_anchor: replace a deployed modulefile's shared
$::env(BASEDIR) with an absolute install base so a reused copy is
self-anchoring (the first BASE on MODULEPATH no longer pins every
package's location). write_overlay now writes a pre-rendered modulefile
when an entry carries one; foreign entries still regenerate from ops.
Mechanism for trusted harvest; no producer wired yet.
bits import --trusted reads a deployed release's own modulefiles
(--modulepath) and re-anchors each to --install-base, strips the now
unneeded BASE dep, and captures package hash + build_id from the install
tree's .meta.json. Deterministic (no modulecmd); feeds the same overlay
writer. Produces the self-anchoring modules a strict reuse consumes.
generate_initdotsh gains a per-dependency branch: a dep marked
reuse_module_id (satisfied from a reused CVMFS release) is set up via
'module use <overlay>' + 'module load <id>' instead of sourcing its
init.sh, while locally-built deps are unchanged. Per-dependency, so a
legacy package can consume a module-reused dep. Dormant until the marker
and reuse_modulepath are wired (next step).
The import subcommand is dispatched in bitsBuild but was missing from the
wrapper's command allowlist, so 'bits import' failed with 'Unknown
command'. Add it to the route list.
The deployed BASE dependency is a multi-line 'if ![ is-loaded BASE ] {
module load BASE }' block; the old per-line strip dropped the first two
lines but left the orphan '}', so the reused modulefile failed to load
(invalid command name }). Make strip_base_dep brace-aware: consume
through the matching '}'. Found by the testbed module load.
When --reuse-from is set, doBuild runs import_trusted_release to build the
local re-anchored overlay (install base from the layout) and threads its
path into generate_initdotsh. import_trusted_release now returns the
overlay path. Dormant: nothing is marked reused yet, so builds are
unchanged; a --reuse-from build just logs the imported overlay.
After each package's hash is finalized, if the reuse overlay satisfies it
(strict: same remote hash, publishable; relaxed: any version in the
one-release overlay) set reuse_module_id so consumers 'module load' it
instead of sourcing its init.sh. defaults-*/--build-local never grafted.
The package still builds here; skipping its build is the next step.
With --reuse-from cvmfs the Packages root comes from the layout; with an
explicit .../Modules/modulefiles path and no layout, derive it by the
deployment convention (Modules/modulefiles<->Packages, the map BASE uses)
so the explicit form works without configuring the layout.
A package satisfied by the reuse overlay is now set up from modules only:
it adopts a consistent identity, records already_installed, and continues
before fetch_symlinks — so the legacy CVMFS tarball synthesis + relocate
path is skipped entirely (that was the relocate-me.sh failure). Devel
packages excluded. Initialise mainBuildFamily before the loop so reusing
the target package doesn't leave the final banner unset.
args.buildLocal is normalized to a list (args.py:1965), but the 4b reuse
guard treated it as a comma string and called .split() -> AttributeError
when --build-local was passed. Accept both list and string forms.
generate_initdotsh was given the host overlay abspath, so 'module use'
inside the build container pointed at a nonexistent /home/... path. Pass
the overlay under init_workDir (the container workdir under --docker), so
it resolves at $WORK_DIR/MODULES/<build_id>/<arch> in the container.
Replace module use/load (which needs modulecmd in the image) with the
standard mechanism: source the dep's deployed init.sh from CVMFS. Point
its $WORK_DIR/$BITS_ARCH_PREFIX at the Packages base while sourcing;
BITS_ARCH_PREFIX="." (non-null) survives the deployed init.sh's
`:= <arch>` default that "" would not. Mount /cvmfs into the build
container when reuse is active. No image change, no modulecmd.
A reused dep's deployed init.sh transitively re-sources its own deps
(guarded on _REVISION) from CVMFS. A local-built prerequisite must be set
up first so that guard skips the CVMFS re-source, which misses a
local-only build (e.g. bits-recipe-tools before a reused CMake).
The relaxed build_id graft path warns 'packages will be built / no packages
will be grafted' when it has no cvmfs:// store or --reuse-base. Under
--reuse-from overlay reuse those warnings are misleading — the overlay grafts
independently. Gate them on args.reuseOverlay. Non-reuse-from output unchanged.
resolve_tag ran only under `if "source"` (git), so a tarball-only recipe with
`tag: "v%(version)s"` kept the raw tag; it leaked into commit_hash and the
SOURCES/<pkg>/<version>/<tag> path, breaking the source copy. Resolve it on the
sources path too — no-op for literal tags, and matches the git path.
A deployed .pc can bake a prefix= that doesn't match its CVMFS location
(publish-time relocation), so pkg-config resolves a missing libdir and a
consumer's find_package fails (xrootd -> Davix). Stage corrected .pc copies
under $WORK_DIR with prefix set to the reused dep's real root, prepend to
PKG_CONFIG_PATH.
The revision scan reports a TARS symlink whose store tarball is gone
(leftover from a failed build or a cleanup) then skips it and rebuilds —
self-healing, not actionable. It fired on every build as WARNING noise;
make it debug. The unparseable-symlink case stays a warning.
A trailing ::relaxed/::strict on --reuse-from sets the reuse policy alongside
the source (e.g. cvmfs::relaxed). --reuse-policy stays canonical: it wins, and
if both are given they must agree (error otherwise). Absolute paths never
contain ::, so the split is unambiguous.
When the defaults declare no module layout (module_dir/cvmfs_dir), --reuse-from
cvmfs now derives the modulefiles base from the group's cvmfs_modules_template
(one declaration drives publish and reuse). Expanded with the deployed (raw)
arch so it matches where packages live, not the build-qualified family.
Retire the ADR-0001 graft path now that --reuse-from module overlay is the
proven mechanism. Drops the build_id auto-select, the graftable_match
performCvmfsMatch callback, the reuseBase default, and the reuseCvmfs ->
remote-store=cvmfs:// wiring. Overlay reuse and the relaxed publish guard are
untouched. getPackageList's now-unused callback param goes next.
Drop the performCvmfsMatch graft branch from getPackageList, the from_cvmfs
hash-adoption in storeHashes, and the from_cvmfs closure-loose provenance
check (nothing sets from_cvmfs after 5/1). Legacy graft tests removed
(test_reuse_resolver stubbed pending git rm); provenance loose is now driven
solely by untracked_requires.
…(5/3)

The cvmfs:// remote-store reader (synthesized-tarball reuse) is retired.
remote_from_url now errors on a cvmfs:// --remote-store, pointing at
--reuse-from; the http+write dual path and all other backends are unchanged.
Legacy CVMFSRemoteSync tests removed (fetch_symlinks stub pending git rm).
The build_id-graft flags and the select_build_id/graftable_match helpers they
drove have no consumers after 5/1-5/3. Remove the flags, empty cvmfs_reuse.py
(stub pending git rm), retarget the bits-import help at --reuse-from, and prune
the legacy arg tests.
bits use [section] <args> records reusable CLI args (INI-style: [common] plus
per-command sections) so repeated commands stay short. The wrapper injects
[common]+[<action>] right after the action token before parsing, so build and
the module commands (q/enter) both see it and explicit args still win. New
bits_use.py (rewrite_argv/--rewrite0) + tests.
@pbuncic
pbuncic merged commit a82e40b into main Aug 25, 2026
13 checks passed
@pbuncic
pbuncic deleted the feature/reuse-from-modules branch August 25, 2026 16:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant