Skip to content

Commit 3907999

Browse files
Add container runtime setup script
1 parent 25e3aca commit 3907999

7 files changed

Lines changed: 153 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## [0.13.3] - 2026-06-03
4+
5+
### Added
6+
- **Container runtime setup script**: Add `/opt/spine/setup.sh` and `/opt/spine/check-env.sh` to the published container image so ROOT/LArCV/SPINE runtime environment setup is explicit, testable, and recoverable when unpacked-image runtimes fail to apply the container environment automatically.
7+
38
## [0.13.2] - 2026-06-02
49

510
### Changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,19 @@ apptainer exec --nv spine_<release>.sif \
8080

8181
The Docker and Apptainer paths consume the same released image; the difference is only the container runtime.
8282

83+
The published image now includes a canonical fallback setup script at
84+
`/opt/spine/setup.sh`. Normal Docker and Apptainer execution should not require
85+
manual sourcing. Some sites expose the image through CVMFS as an unpacked root
86+
filesystem; in that mode, the site integration should still apply the image
87+
environment automatically. If it does not, diagnose the runtime from inside that
88+
unpacked-image environment with:
89+
90+
```bash
91+
source /opt/spine/setup.sh
92+
/opt/spine/check-env.sh
93+
python -c "import ROOT, larcv, spine"
94+
```
95+
8396
### Local Python Installation
8497

8598
Use a local pip installation when you only need downstream tooling such as post-processing, analysis, visualization, documentation, or light development.

docker/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,29 @@ apptainer run --nv \
244244

245245
When pulled with Apptainer/Singularity, the fully built image is about **5.7 GB**.
246246

247+
### CVMFS / Unpacked Image Environments
248+
249+
Some sites distribute container root filesystems through CVMFS or another
250+
unpacked-image mechanism instead of asking users to run a local `.sif` file.
251+
That is a supported distribution model, but the site integration layer is still
252+
responsible for applying the image environment automatically. Users should not
253+
normally need to set `PYTHONPATH` or `LD_LIBRARY_PATH` by hand.
254+
255+
The SPINE image includes `/opt/spine/setup.sh` as the canonical fallback recipe
256+
for the runtime environment, plus `/opt/spine/check-env.sh` for diagnostics. If
257+
an unpacked-image launch path starts SPINE but cannot import ROOT or LArCV,
258+
run the following from inside that same unpacked-image environment:
259+
260+
```bash
261+
source /opt/spine/setup.sh
262+
/opt/spine/check-env.sh
263+
python -c "import ROOT, larcv, spine"
264+
```
265+
266+
If that succeeds, the image contains the expected dependencies and the remaining
267+
issue is that the CVMFS/OSG launch path is not applying the image environment
268+
before starting SPINE.
269+
247270
### HPC SLURM Example
248271

249272
```bash

docker/spine/Dockerfile

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,21 +127,29 @@ RUN pip install --no-cache-dir \
127127
ARG OPT0FINDER_REF=v1.0.0
128128
ARG OPT0FINDER_COMMIT=bd03fa90eaae9d753a68db390df80470a6181039
129129
ARG OPT0FINDER_MAX_JOBS=2
130-
ENV FMATCH_BASEDIR=/opt/OpT0Finder \
130+
ENV SPINE_RUNTIME_DIR=/opt/spine \
131+
ROOTSYS=/opt/root \
132+
LARCV_BASEDIR=/app/larcv2 \
133+
LARCV_LIBDIR=/app/larcv2/build/lib \
134+
LARCV_PYTHONDIR=/app/larcv2/python \
135+
FMATCH_BASEDIR=/opt/OpT0Finder \
131136
FMATCH_BUILDDIR=/opt/OpT0Finder/build \
132137
FMATCH_LIBDIR=/opt/OpT0Finder/build/lib \
133138
FMATCH_INCDIR=/opt/OpT0Finder/build/include \
134139
FMATCH_BINDIR=/opt/OpT0Finder/build/bin \
135140
FMATCH_DATADIR=/opt/OpT0Finder/dat \
136-
LD_LIBRARY_PATH=/opt/OpT0Finder/build/lib:${LD_LIBRARY_PATH} \
137-
PYTHONPATH=/opt/OpT0Finder/python:${PYTHONPATH} \
138-
PATH=/opt/OpT0Finder/bin:/opt/OpT0Finder/build/bin:${PATH}
141+
LD_LIBRARY_PATH=/opt/root/lib:/app/larcv2/build/lib:/opt/OpT0Finder/build/lib:${LD_LIBRARY_PATH} \
142+
PYTHONPATH=/app/larcv2/python:/opt/OpT0Finder/python:/opt/root/lib:${PYTHONPATH} \
143+
PATH=/opt/root/bin:/opt/OpT0Finder/bin:/opt/OpT0Finder/build/bin:${PATH}
139144
RUN git clone https://github.com/DeepLearnPhysics/OpT0Finder.git ${FMATCH_BASEDIR} && \
140145
cd ${FMATCH_BASEDIR} && \
141146
git checkout ${OPT0FINDER_REF} && \
142147
test "$(git rev-parse HEAD)" = "${OPT0FINDER_COMMIT}" && \
143148
bash -lc "source ./configure.sh && make -j${OPT0FINDER_MAX_JOBS}"
144149

150+
COPY docker/spine/setup.sh docker/spine/check-env.sh /opt/spine/
151+
RUN chmod 755 /opt/spine/setup.sh /opt/spine/check-env.sh
152+
145153
# Make ROOT/LArCV/OpT0Finder imports survive user-provided PYTHONPATH overrides,
146154
# such as `-e PYTHONPATH=/workspace/src` for editable notebook sessions.
147155
RUN python -c "import site; print('\n'.join(site.getsitepackages()))" | \
@@ -177,6 +185,14 @@ COPY src/ ./src/
177185
# Install SPINE with all dependencies
178186
RUN pip install --no-cache-dir --no-build-isolation .[all]
179187

188+
# Verify that the default container environment and the explicit fallback setup
189+
# recipe both provide the compiled dependency imports SPINE needs at runtime.
190+
RUN python -c "import ROOT, larcv, spine; print('container runtime imports ok')"
191+
RUN /opt/spine/check-env.sh
192+
RUN env -u ROOTSYS -u LARCV_BASEDIR -u LARCV_LIBDIR -u LARCV_PYTHONDIR \
193+
-u PYTHONPATH -u LD_LIBRARY_PATH bash -lc \
194+
"source /opt/spine/setup.sh && /opt/spine/check-env.sh"
195+
180196
# Set working directory for user data
181197
WORKDIR /workspace
182198

docker/spine/check-env.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
source /opt/spine/setup.sh
6+
7+
echo "which python: $(command -v python)"
8+
python - <<'PY'
9+
import os
10+
import sys
11+
12+
print(f"sys.executable: {sys.executable}")
13+
for key in (
14+
"ROOTSYS",
15+
"LARCV_BASEDIR",
16+
"LARCV_LIBDIR",
17+
"LARCV_PYTHONDIR",
18+
"PYTHONPATH",
19+
"LD_LIBRARY_PATH",
20+
):
21+
print(f"{key}: {os.environ.get(key, '')}")
22+
23+
import ROOT
24+
25+
print(f"ROOT OK: {ROOT.gROOT.GetVersion()}")
26+
27+
import larcv
28+
29+
print(f"larcv OK: {larcv}")
30+
31+
import spine
32+
33+
print(f"spine OK: {spine}")
34+
PY

docker/spine/setup.sh

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env bash
2+
3+
# Canonical runtime environment for SPINE container dependencies.
4+
# This script is primarily a fallback for runtimes that expose the image
5+
# filesystem but fail to apply the container environment automatically.
6+
7+
if [ "${BASH_SOURCE[0]:-}" = "$0" ]; then
8+
echo "Source this file instead of executing it: source /opt/spine/setup.sh" >&2
9+
exit 1
10+
fi
11+
12+
_spine_prepend_path() {
13+
local var_name="$1"
14+
local entry="$2"
15+
local current_value
16+
17+
if [ ! -e "${entry}" ]; then
18+
return 0
19+
fi
20+
21+
current_value="${!var_name:-}"
22+
case ":${current_value}:" in
23+
*":${entry}:"*) ;;
24+
"")
25+
export "${var_name}=${entry}"
26+
;;
27+
*)
28+
export "${var_name}=${entry}:${current_value}"
29+
;;
30+
esac
31+
}
32+
33+
export SPINE_RUNTIME_DIR="${SPINE_RUNTIME_DIR:-/opt/spine}"
34+
export ROOTSYS="${ROOTSYS:-/opt/root}"
35+
export LARCV_BASEDIR="${LARCV_BASEDIR:-/app/larcv2}"
36+
export LARCV_LIBDIR="${LARCV_LIBDIR:-${LARCV_BASEDIR}/build/lib}"
37+
export LARCV_PYTHONDIR="${LARCV_PYTHONDIR:-${LARCV_BASEDIR}/python}"
38+
export FMATCH_BASEDIR="${FMATCH_BASEDIR:-/opt/OpT0Finder}"
39+
export FMATCH_BUILDDIR="${FMATCH_BUILDDIR:-${FMATCH_BASEDIR}/build}"
40+
export FMATCH_LIBDIR="${FMATCH_LIBDIR:-${FMATCH_BUILDDIR}/lib}"
41+
export FMATCH_INCDIR="${FMATCH_INCDIR:-${FMATCH_BUILDDIR}/include}"
42+
export FMATCH_BINDIR="${FMATCH_BINDIR:-${FMATCH_BUILDDIR}/bin}"
43+
export FMATCH_DATADIR="${FMATCH_DATADIR:-${FMATCH_BASEDIR}/dat}"
44+
45+
_spine_prepend_path PATH "${ROOTSYS}/bin"
46+
_spine_prepend_path PATH "${FMATCH_BASEDIR}/bin"
47+
_spine_prepend_path PATH "${FMATCH_BINDIR}"
48+
49+
_spine_prepend_path LD_LIBRARY_PATH "${ROOTSYS}/lib"
50+
_spine_prepend_path LD_LIBRARY_PATH "${LARCV_LIBDIR}"
51+
_spine_prepend_path LD_LIBRARY_PATH "${FMATCH_LIBDIR}"
52+
53+
_spine_prepend_path PYTHONPATH "${LARCV_PYTHONDIR}"
54+
_spine_prepend_path PYTHONPATH "${FMATCH_BASEDIR}/python"
55+
_spine_prepend_path PYTHONPATH "${ROOTSYS}/lib"
56+
57+
unset -f _spine_prepend_path

src/spine/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Module which stores the current software version."""
22

3-
__version__ = "0.13.2"
3+
__version__ = "0.13.3"

0 commit comments

Comments
 (0)