From fefb4d18e6f639ba659fdc0b40512e5a3d3ca6f6 Mon Sep 17 00:00:00 2001 From: ClePol Date: Tue, 19 May 2026 22:38:38 +0200 Subject: [PATCH 1/4] export backend-neutral pinned requirements --- requirements.txt | 195 +++++++++++++++++++----------------------- tools/export_pip-r.sh | 83 +++++++++++++----- 2 files changed, 153 insertions(+), 125 deletions(-) diff --git a/requirements.txt b/requirements.txt index 837acc236..90b3746b3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,120 +1,105 @@ # -# This file is autogenerated by kueglerd from fastsurfer:2.4.0-rc1 +# This file is autogenerated by pollakc from /Users/pollakc/Repositories/fastsurfer-dev-3c52a21.sif # by the following command from FastSurfer: # -# env/export_pip-r.sh requirements.txt fastsurfer:2.4.0-rc1 +# tools/export_pip-r.sh requirements.txt /Users/pollakc/Repositories/fastsurfer-dev-3c52a21.sif # # Which ran the following command: -# docker run --rm -u : --entrypoint /bin/bash fastsurfer:2.4.0-rc1 -c 'python --version && pip list --format=freeze --no-color --disable-pip-version-check --no-input --no-cache-dir' +# singularity exec /Users/pollakc/Repositories/fastsurfer-dev-3c52a21.sif /bin/bash -c 'python --version && pip list --format=freeze --no-color --disable-pip-version-check --no-input --no-cache-dir' # # -# Image was configured for cu126 -# using python version 3.10.16 +# Backend-neutral pinned requirements for FastSurfer. # ---extra-index-url https://download.pytorch.org/whl/cu126 - -# Python 3.10.16 -absl-py==2.1.0 -Brotli==1.1.0 -cached-property==1.5.2 -certifi==2024.12.14 -cffi==1.17.1 -charset-normalizer==3.4.1 -click==8.1.8 -colorama==0.4.6 -contourpy==1.3.1 +# Image was configured for cu118 using python version 3.12.12. +# +# This file pins the shared Python dependency set, but intentionally does not +# pin backend-specific PyTorch wheel variants, PyTorch index URLs, nvidia-* +# runtime packages, or triton. Select those at install time with uv's +# --torch-backend option, for example: +# +# uv pip compile --torch-backend=cu128 requirements.txt | uv pip sync --torch-backend=cu128 - +# uv pip compile --torch-backend=cpu requirements.txt | uv pip sync --torch-backend=cpu - +# +# To refresh this file from a container image, run: +# +# tools/export_pip-r.sh requirements.txt /Users/pollakc/Repositories/fastsurfer-dev-3c52a21.sif +# +absl-py==2.4.0 +annotated-doc==0.0.4 +certifi==2026.4.22 +charset-normalizer==3.4.7 +click==8.3.3 +contourpy==1.3.3 cycler==0.12.1 -Deprecated==1.2.18 -filelock==3.17.0 -fonttools==4.55.8 -fsspec==2024.12.0 -grpcio==1.67.1 -h2==4.1.0 -h5py==3.12.1 -hpack==4.1.0 -humanize==4.11.0 -hyperframe==6.1.0 -idna==3.10 -imagecodecs==2024.12.30 -imageio==2.37.0 -importlib_metadata==8.6.1 -importlib_resources==6.5.2 -Jinja2==3.1.5 -joblib==1.4.2 -kiwisolver==1.4.7 -lapy==1.2.0 -lazy_loader==0.4 -Markdown==3.6 -markdown-it-py==3.0.0 -MarkupSafe==3.0.2 -matplotlib==3.10.0 +Deprecated==1.3.1 +einops==0.8.2 +filelock==3.29.0 +fonttools==4.62.1 +fsspec==2026.4.0 +glfw==2.10.0 +grpcio==1.80.0 +h5py==3.16.0 +humanize==4.15.0 +idna==3.15 +ImageIO==2.37.3 +jaxtyping==0.3.9 +Jinja2==3.1.6 +joblib==1.5.3 +kiwisolver==1.5.0 +lapy==1.6.0 +lazy-loader==0.5 +Markdown==3.10.2 +markdown-it-py==4.2.0 +MarkupSafe==3.0.3 +matplotlib==3.10.9 mdurl==0.1.2 +meshpy==2025.1.1 +monai==1.5.2 mpmath==1.3.0 -munkres==1.1.4 -narwhals==1.24.1 -networkx==3.4.2 -neuroreg==0.6.0 -nibabel==5.3.2 -numpy==1.26.4 -nvidia-cublas-cu12==12.6.4.1 -nvidia-cuda-cupti-cu12==12.6.80 -nvidia-cuda-nvrtc-cu12==12.6.77 -nvidia-cuda-runtime-cu12==12.6.77 -nvidia-cudnn-cu12==9.5.1.17 -nvidia-cufft-cu12==11.3.0.4 -nvidia-curand-cu12==10.3.7.77 -nvidia-cusolver-cu12==11.7.1.2 -nvidia-cusparse-cu12==12.5.4.2 -nvidia-cusparselt-cu12==0.6.3 -nvidia-nccl-cu12==2.21.5 -nvidia-nvjitlink-cu12==12.6.85 -nvidia-nvtx-cu12==12.6.77 -packaging==24.2 -pandas==2.2.3 -pillow==11.1.0 -pip==25.0 -plotly==6.0.0 -protobuf==5.29.5 -psutil==6.1.1 -pycparser==2.22 -Pygments==2.19.1 -pyparsing==3.2.1 -PySide6==6.8.1 -PySocks==1.7.1 +multipledispatch==1.0.0 +narwhals==2.21.0 +networkx==3.6.1 +neurolit==0.6.1 +neuroreg==0.6.1 +nibabel==5.4.2 +numpy==2.4.4 +packaging==26.2 +pandas==3.0.3 +pillow==12.2.0 +pip==26.1.1 +platformdirs==4.9.6 +plotly==6.7.0 +protobuf==7.34.1 +psutil==7.2.2 +Pygments==2.20.0 +PyOpenGL==3.1.10 +pyparsing==3.3.2 +pyrr==0.10.3 python-dateutil==2.9.0.post0 -pytz==2024.1 -PyWavelets==1.8.0 -PyYAML==6.0.2 -requests==2.32.4 -rich==13.9.4 -scikit-image==0.25.1 -scikit-learn==1.6.1 -scikit-sparse==0.4.15 -scipy==1.15.1 -setuptools==78.1.1 +PyYAML==6.0.3 +requests==2.34.1 +rich==15.0.0 +scikit-image==0.26.0 +scikit-learn==1.8.0 +scipy==1.17.1 +setuptools==82.0.1 shellingham==1.5.4 -shiboken6==6.8.1 -SimpleITK==2.4.1 +simpleitk==2.5.5 six==1.17.0 -sympy==1.13.1 -tensorboard==2.18.0 -tensorboard_data_server==0.7.0 -threadpoolctl==3.5.0 -tifffile==2025.1.10 -torch==2.7.1+cpu -torchio==0.20.4 -torchvision==0.21.0+cu126 -tornado==6.5.1 -tqdm==4.67.1 -triton==3.2.0 -typer==0.15.1 -typing_extensions==4.12.2 -tzdata==2025.1 -unicodedata2==16.0.0 -urllib3==2.5.0 -Werkzeug==3.1.3 -wheel==0.45.1 -wrapt==1.17.2 +sympy==1.14.0 +tensorboard==2.20.0 +tensorboard-data-server==0.7.2 +threadpoolctl==3.6.0 +tifffile==2026.5.2 +torch==2.7.1 +torchio==1.2.0 +torchvision==0.22.1 +tqdm==4.67.3 +typer==0.25.1 +typing_extensions==4.15.0 +urllib3==2.7.0 +wadler_lindig==0.1.7 +Werkzeug==3.1.8 +whippersnappy==2.1.0 +wrapt==2.1.2 yacs==0.1.8 -zipp==3.21.0 -zstandard==0.23.0 diff --git a/tools/export_pip-r.sh b/tools/export_pip-r.sh index 7aff926e8..1ffc64f24 100755 --- a/tools/export_pip-r.sh +++ b/tools/export_pip-r.sh @@ -19,12 +19,14 @@ function usage() cat < -Will generate requirements files from docker/singularity images to distribute with -the FastSurfer repository. +Will generate a backend-neutral requirements file from docker/singularity images +to distribute with the FastSurfer repository. Backend-specific PyTorch wheel +suffixes, PyTorch index URLs, nvidia-* runtime packages, and triton packages are +intentionally omitted; select those at install/build time with uv --torch-backend. examples: export_pip-r.sh $FASTSURFER_HOME/requirements.txt fastsurfer:dev -export_pip-r.sh $FASTSURFER_HOME/requirements.cpu.txt fastsurfer:dev +export_pip-r.sh $FASTSURFER_HOME/requirements.txt fastsurfer.sif Created 26-11-2023, David Kügler, Image Analysis Lab, German Center for Neurodegenerative Diseases (DZNE), Bonn @@ -39,41 +41,82 @@ fi echo "Exporting versions from $2..." +target=$1 +image=$2 +display_target=${EXPORT_PIP_R_DISPLAY_TARGET:-$target} +display_args=("$display_target" "$image") +tmp_target=$(mktemp "${target}.tmp.XXXXXX") || exit 1 +trap 'rm -f "$tmp_target"' EXIT + { echo "#" - echo "# This file is autogenerated by $USER from $2" + echo "# This file is autogenerated by $USER from $image" echo "# by the following command from FastSurfer:" echo "#" - echo "# $0 $*" + echo "# $0 ${display_args[*]}" echo "#" -} > $1 +} > "$tmp_target" pip_cmd="python --version && pip list --format=freeze --no-color --disable-pip-version-check --no-input --no-cache-dir" -if [ "${2/#.sif}" != "$2" ] +if [[ "$image" == *.sif ]] then # singularity - cmd=("singularity" "exec" "$2" "/bin/bash" -c "$pip_cmd") - clean_cmd="singularity exec $2 /bin/bash -c '$pip_cmd'" + if command -v singularity > /dev/null + then + singularity_cmd=singularity + elif command -v apptainer > /dev/null + then + singularity_cmd=apptainer + else + echo "Could not find singularity or apptainer to inspect $image" + exit 1 + fi + cmd=("$singularity_cmd" "exec" "$image" "/bin/bash" -c "$pip_cmd") + clean_cmd="$singularity_cmd exec $image /bin/bash -c '$pip_cmd'" else # docker - clean_cmd="docker run --rm -u : --entrypoint /bin/bash $2 -c '$pip_cmd'" - cmd=("docker" "run" --rm -it -u "$(id -u):$(id -g)" --entrypoint /bin/bash "$2" -c "$pip_cmd") + clean_cmd="docker run --rm -u : --entrypoint /bin/bash $image -c '$pip_cmd'" + cmd=("docker" "run" --rm -u "$(id -u):$(id -g)" --entrypoint /bin/bash "$image" -c "$pip_cmd") fi { echo "# Which ran the following command:" echo "# $clean_cmd" echo "#" -} >> $1 -echo "Running '${cmd[*]}' to get $1" -out=$("${cmd[@]}") +} >> "$tmp_target" +echo "Running '${cmd[*]}' to get $target" +if ! out=$("${cmd[@]}") +then + echo "Failed to inspect $image" + exit 1 +fi hardware=$(echo "$out" | grep "torch==" | cut -d"+" -f2 | tr -d '\n') pyversion=$(echo "$out" | head -n 1 | cut -d" " -f2) { echo "#" - echo "# Image was configured for $hardware using python version $pyversion" + echo "# Backend-neutral pinned requirements for FastSurfer." + echo "#" + echo "# Image was configured for $hardware using python version $pyversion." echo "#" - echo "--extra-index-url https://download.pytorch.org/whl/$hardware" - echo "" - # first line is python version and gets commented here - echo "# $out" -} >> $1 + echo "# This file pins the shared Python dependency set, but intentionally does not" + echo "# pin backend-specific PyTorch wheel variants, PyTorch index URLs, nvidia-*" + echo "# runtime packages, or triton. Select those at install time with uv's" + echo "# --torch-backend option, for example:" + echo "#" + echo "# uv pip compile --torch-backend=cu128 requirements.txt | uv pip sync --torch-backend=cu128 -" + echo "# uv pip compile --torch-backend=cpu requirements.txt | uv pip sync --torch-backend=cpu -" + echo "#" + echo "# To refresh this file from a container image, run:" + echo "#" + echo "# $0 ${display_args[*]}" + echo "#" + echo "$out" \ + | tail -n +2 \ + | sed -E \ + -e '/^nvidia-/d' \ + -e '/^triton==/d' \ + -e '/^pytorch-triton/d' \ + -e 's/^((torch|torchvision|torchaudio)==[^+[:space:]]+)\+[^[:space:]]+/\1/' +} >> "$tmp_target" + +mv "$tmp_target" "$target" +trap - EXIT From 29e2c2d2c6e3ca6dd7b8f844f49087feca35130b Mon Sep 17 00:00:00 2001 From: ClePol Date: Tue, 19 May 2026 22:39:07 +0200 Subject: [PATCH 2/4] support pinned requirements builds --- .dockerignore | 1 + tools/Docker/Dockerfile | 12 +++++++++--- tools/Docker/README.md | 4 +++- tools/Docker/build.py | 13 +++++++++++-- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/.dockerignore b/.dockerignore index bc9e286e3..89477d5e7 100644 --- a/.dockerignore +++ b/.dockerignore @@ -20,3 +20,4 @@ /tools/macos_build /srun_fastsurfer.sh /requirements*.txt +!/requirements.txt diff --git a/tools/Docker/Dockerfile b/tools/Docker/Dockerfile index a7b619b25..484acf03c 100644 --- a/tools/Docker/Dockerfile +++ b/tools/Docker/Dockerfile @@ -151,19 +151,25 @@ ARG FASTSURFER_VERSION ARG GIT_HASH ARG VENDOR ARG BUILD_BASE_IMAGE +ARG PINNED_REQUIREMENTS=false SHELL ["/bin/bash", "--login", "-e", "-c"] -# Install the project's dependencies using the lockfile and settings +# Install the project's dependencies using either pyproject.toml or the backend-neutral pinned requirements. RUN --mount=type=cache,target=/root/.cache/uv \ - --mount=type=bind,source=pyproject.toml,target=/install/pyproject.toml </buildx-.`, for example `wget -qO ~/.docker/cli-plugins/docker-buildx https://github.com/docker/buildx/releases/download/v0.12.1/buildx-v0.12.1.linux-amd64`. See also https://github.com/docker/buildx#manual-download. @@ -97,7 +99,7 @@ In order to build your own Docker image for FastSurfer (FastSurferCNN + recon-su python tools/Docker/build.py --device cuda --tag my_fastsurfer:cuda ``` -The build script allows more specific options, that specify different CUDA options as well (see `build.py --help`). +The build script allows more specific options, that specify different CUDA options as well (see `build.py --help`). Add `--pinned_requirements` to use the pinned `requirements.txt` dependency versions while still selecting the CUDA backend from `--device`. For running the analysis, the command is the same as above for the prebuild option: ```bash diff --git a/tools/Docker/build.py b/tools/Docker/build.py index 790e9f2c5..f83de8f3c 100755 --- a/tools/Docker/build.py +++ b/tools/Docker/build.py @@ -262,6 +262,12 @@ def make_parser() -> argparse.ArgumentParser: action="store_true", help="Also tag the resulting image as 'fastsurfer:dev'.", ) + parser.add_argument( + "--pinned_requirements", + action="store_true", + help="Build the Python environment from backend-neutral pinned requirements.txt " + "instead of resolving the latest compatible versions from pyproject.toml.", + ) # --save_image does not work as expected right now, it cannot be imported via # docker load, but must be transferred to a registry... # parser.add_argument( @@ -542,7 +548,7 @@ def is_inline_cache(cache_kw): "--attest", "type=sbom", "--attest", "type=provenance", ]) - if not default_builder_is_container: + if not default_builder_is_container and alternative_builder != "use_default": args.extend(["--builder", alternative_builder]) kwargs_to_exclude = [] @@ -633,6 +639,7 @@ def main( image_tag: str | None = None, dry_run: bool = False, tag_dev: bool = True, + pinned_requirements: bool = False, fastsurfer_home: Path | None = None, insecure: bool = False, **keywords, @@ -659,6 +666,7 @@ def main( raise ValueError(f"Invalid target: {target}") if device not in get_args(AllDeviceType): raise ValueError(f"Invalid device: {device}") + mapped_device = DEFAULTS.MapDeviceType.get(device, "cpu") if keywords.get("action", "load") == "push": kwargs["action"] = "push" # special case to add extra environment variables to better support AWS and ROCm @@ -666,10 +674,11 @@ def main( target = "runtime_cuda" kwargs["target"] = target kwargs["build_arg"] = [ - f"DEVICE={DEFAULTS.MapDeviceType.get(device, 'cpu')}", + f"DEVICE={mapped_device}", f"FREESURFER_URL={pyproject_freesurfer['urls']['linux'].format(version=pyproject_freesurfer['version'])}", f"FREESURFER_VERSION={pyproject_freesurfer['version']}", f"INSECURE_FLAG={'--insecure' if insecure else ''}", + f"PINNED_REQUIREMENTS={'true' if pinned_requirements else 'false'}", ] if debug: kwargs["build_arg"].append("DEBUG=true") From 9f388fa14b55597f91450c2a1c0d1c95e498f2ee Mon Sep 17 00:00:00 2001 From: ClePol Date: Tue, 19 May 2026 22:39:20 +0200 Subject: [PATCH 3/4] reject unmapped default nonroot user --- long_fastsurfer.sh | 2 +- recon_surf/functions.sh | 10 +++++++++- run_fastsurfer.sh | 2 +- tools/Docker/Dockerfile | 7 +++++++ tools/Docker/README.md | 2 +- 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/long_fastsurfer.sh b/long_fastsurfer.sh index e13167884..db37abffb 100755 --- a/long_fastsurfer.sh +++ b/long_fastsurfer.sh @@ -314,7 +314,7 @@ function check_stage_dependencies() { done } -# Warning if run as root user +# Check for invalid docker/root user setup check_allow_root "${brun_flags[@]}" # --allow_root must be passed to brun # Validate required inputs based on which stages will run diff --git a/recon_surf/functions.sh b/recon_surf/functions.sh index dcc081c19..79cabb91b 100644 --- a/recon_surf/functions.sh +++ b/recon_surf/functions.sh @@ -225,7 +225,7 @@ function auto_detect_fs_license() function check_allow_root() { # Will check, if --allow_root is in arguments (to this function) and print an error message - # as well as exit. + # as well as exit. Also checks for the default docker user, which indicates a missing --user mapping. # Examples: # check_allow_root --arg 0 -> message and exit # @@ -252,6 +252,14 @@ function check_allow_root() echo " If you want to force running as root, you may pass --allow_root to $(basename "$BASH_ARGV0")." exit 1 fi + elif [[ -n "${FASTSURFER_DOCKER_DEFAULT_USER:-}" ]] \ + && [[ "$(id -un 2> /dev/null || true)" == "$FASTSURFER_DOCKER_DEFAULT_USER" ]] + then + echo "ERROR: You are trying to run '$(basename "$BASH_ARGV0")' as the default FastSurfer docker user" + echo " '$FASTSURFER_DOCKER_DEFAULT_USER'. This usually means the container was started without mapping" + echo " your host user into the container." + echo " Please run docker with '-u \$(id -u):\$(id -g)' (see https://docs.docker.com/engine/reference/run/#user)." + exit 1 fi } diff --git a/run_fastsurfer.sh b/run_fastsurfer.sh index 4e2bd7e40..2d79e7129 100755 --- a/run_fastsurfer.sh +++ b/run_fastsurfer.sh @@ -589,7 +589,7 @@ fi source "${reconsurfdir}/functions.sh" -# Warning if run as root user +# Check for invalid docker/root user setup check_allow_root "${allow_root[@]}" # from now to the creation of the logfile, all messages are only written to the console and thus lost if the output is diff --git a/tools/Docker/Dockerfile b/tools/Docker/Dockerfile index 484acf03c..81cb34fe2 100644 --- a/tools/Docker/Dockerfile +++ b/tools/Docker/Dockerfile @@ -296,6 +296,8 @@ EOF # DO_NOT_SEARCH_FS_LICENSE_IN_FREESURFER_HOME=true deactivates the search for FS_LICENSE in FREESURFER_HOME # XDG_DATA_HOME pins neurolit platformdirs data files to a deterministic, # runtime-writable image path outside the temporary directories. +# FASTSURFER_DOCKER_DEFAULT_USER identifies the image user used when docker is +# run without an explicit --user mapping. ENV OS=Linux \ FS_OVERRIDE=0 \ FIX_VERTEX_AREA="" \ @@ -309,6 +311,7 @@ ENV OS=Linux \ PATH=/venv/bin:/opt/freesurfer/bin:$PATH \ MPLCONFIGDIR=/tmp/matplotlib-config \ XDG_DATA_HOME=/var/.local/share \ + FASTSURFER_DOCKER_DEFAULT_USER=nonroot \ DO_NOT_SEARCH_FS_LICENSE_IN_FREESURFER_HOME="true" # Copy fastsurfer venv and pruned freesurfer from build images @@ -344,6 +347,10 @@ SHELL ["/bin/bash", "--login", "-c"] # Set FastSurfer workdir and entrypoint # the script entrypoint ensures that our venv is active +RUN < /dev/null || groupadd --system nonroot +id -u nonroot > /dev/null 2>&1 || useradd --system --gid nonroot --no-create-home --home-dir /nonexistent --shell /usr/sbin/nologin nonroot +EOF USER nonroot WORKDIR "/fastsurfer" ENTRYPOINT ["/fastsurfer/tools/Docker/entrypoint.sh","/fastsurfer/run_fastsurfer.sh"] diff --git a/tools/Docker/README.md b/tools/Docker/README.md index 9269ad483..76d328c6e 100644 --- a/tools/Docker/README.md +++ b/tools/Docker/README.md @@ -37,7 +37,7 @@ docker run --gpus all -v $HOME/my_mri_data:/data \ ### Docker Flags * `--gpus`: This argument is used to access GPU resources. With it, you can also specify how many GPUs to use. In the example above, `all` will make every GPU available to FastSurfer in the Docker container. To use a single one (e.g. GPU 0), set `--gpus device=0`. To use multiple specific GPUs (e.g. GPU 0, 1 and 3), use `--gpus "device=0,1,3"`. * `-v`: This argument defines which and how data is shared between the host system and the docker container. By default, no data is shared between the host and the container. `-v` is used to explicitly share data. It follows the format `-v ::`. In its simplest form, `` and `` are the same and folders inside the container are the same as on the host. `:` may be left out or `:ro` to indicate that files from this folder may not be modified by the docker container (readonly). The following files need to be shared: input files, output folder (subjects directory) and FreeSurfer license. -* `--user $(id -u):$(id -g)`: Which user the container runs as (relevant for file access, the user-id and group-id, **required**!). `$(id -u)` and `$(id -g)` determine the user and group, respectively. Running the docker container as root `--user 0:0` is strongly discouraged and must be combined with the FastSurfer flag `--allow_root`. +* `--user $(id -u):$(id -g)`: Which user the container runs as (relevant for file access, the user-id and group-id, **required**!). `$(id -u)` and `$(id -g)` determine the user and group, respectively. If this flag is omitted, FastSurfer exits with a message asking you to map your host user. Running the docker container as root `--user 0:0` is strongly discouraged and must be combined with the FastSurfer flag `--allow_root`. * `--rm`: The flag takes care of removing the container (cleanup of the container) once the analysis finished (optional, but recommended). * `-d`: You can add this flag to run in detached mode (no screen output, and you return to shell, optional). From 41d74caf5c815866cfca90e3b0e7b6ef75f468b2 Mon Sep 17 00:00:00 2001 From: ClePol Date: Wed, 20 May 2026 14:54:06 +0200 Subject: [PATCH 4/4] Address Docker release review comments --- requirements.txt | 8 ++++---- tools/export_pip-r.sh | 37 ++++++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/requirements.txt b/requirements.txt index 90b3746b3..e59e917c4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,11 @@ # -# This file is autogenerated by pollakc from /Users/pollakc/Repositories/fastsurfer-dev-3c52a21.sif +# This file is autogenerated by pollakc from fastsurfer-dev-3c52a21.sif # by the following command from FastSurfer: # -# tools/export_pip-r.sh requirements.txt /Users/pollakc/Repositories/fastsurfer-dev-3c52a21.sif +# tools/export_pip-r.sh requirements.txt fastsurfer-dev-3c52a21.sif # # Which ran the following command: -# singularity exec /Users/pollakc/Repositories/fastsurfer-dev-3c52a21.sif /bin/bash -c 'python --version && pip list --format=freeze --no-color --disable-pip-version-check --no-input --no-cache-dir' +# apptainer exec fastsurfer-dev-3c52a21.sif /bin/bash -c 'python --version && pip list --format=freeze --no-color --disable-pip-version-check --no-input --no-cache-dir' # # # Backend-neutral pinned requirements for FastSurfer. @@ -22,7 +22,7 @@ # # To refresh this file from a container image, run: # -# tools/export_pip-r.sh requirements.txt /Users/pollakc/Repositories/fastsurfer-dev-3c52a21.sif +# tools/export_pip-r.sh requirements.txt fastsurfer-dev-3c52a21.sif # absl-py==2.4.0 annotated-doc==0.0.4 diff --git a/tools/export_pip-r.sh b/tools/export_pip-r.sh index 1ffc64f24..50aa0d6d2 100755 --- a/tools/export_pip-r.sh +++ b/tools/export_pip-r.sh @@ -17,12 +17,14 @@ function usage() { cat < +export_pip-r.sh -Will generate a backend-neutral requirements file from docker/singularity images -to distribute with the FastSurfer repository. Backend-specific PyTorch wheel -suffixes, PyTorch index URLs, nvidia-* runtime packages, and triton packages are -intentionally omitted; select those at install/build time with uv --torch-backend. +Will generate a backend-neutral requirements file from docker or .sif images to +distribute with the FastSurfer repository. For .sif images, apptainer is used +when available and singularity is used as a fallback. Backend-specific PyTorch +wheel suffixes, PyTorch index URLs, nvidia-* runtime packages, and triton +packages are intentionally omitted; select those at install/build time with uv +--torch-backend. examples: export_pip-r.sh $FASTSURFER_HOME/requirements.txt fastsurfer:dev @@ -44,13 +46,14 @@ echo "Exporting versions from $2..." target=$1 image=$2 display_target=${EXPORT_PIP_R_DISPLAY_TARGET:-$target} -display_args=("$display_target" "$image") +display_image=${EXPORT_PIP_R_DISPLAY_IMAGE:-$(basename "$image")} +display_args=("$display_target" "$display_image") tmp_target=$(mktemp "${target}.tmp.XXXXXX") || exit 1 trap 'rm -f "$tmp_target"' EXIT { echo "#" - echo "# This file is autogenerated by $USER from $image" + echo "# This file is autogenerated by $USER from $display_image" echo "# by the following command from FastSurfer:" echo "#" echo "# $0 ${display_args[*]}" @@ -60,19 +63,19 @@ trap 'rm -f "$tmp_target"' EXIT pip_cmd="python --version && pip list --format=freeze --no-color --disable-pip-version-check --no-input --no-cache-dir" if [[ "$image" == *.sif ]] then - # singularity - if command -v singularity > /dev/null - then - singularity_cmd=singularity - elif command -v apptainer > /dev/null + # apptainer/singularity + if command -v apptainer > /dev/null then singularity_cmd=apptainer + elif command -v singularity > /dev/null + then + singularity_cmd=singularity else - echo "Could not find singularity or apptainer to inspect $image" + echo "Could not find apptainer or singularity to inspect $image" exit 1 fi cmd=("$singularity_cmd" "exec" "$image" "/bin/bash" -c "$pip_cmd") - clean_cmd="$singularity_cmd exec $image /bin/bash -c '$pip_cmd'" + clean_cmd="$singularity_cmd exec $display_image /bin/bash -c '$pip_cmd'" else # docker clean_cmd="docker run --rm -u : --entrypoint /bin/bash $image -c '$pip_cmd'" @@ -118,5 +121,9 @@ pyversion=$(echo "$out" | head -n 1 | cut -d" " -f2) -e 's/^((torch|torchvision|torchaudio)==[^+[:space:]]+)\+[^[:space:]]+/\1/' } >> "$tmp_target" -mv "$tmp_target" "$target" +if ! mv "$tmp_target" "$target" +then + echo "Failed to move $tmp_target to $target" + exit 1 +fi trap - EXIT