Skip to content

Fix: Fixes #857, and turns the macOS package into a self-contained, Apple-silicon-only install - #859

Merged
m-reuter merged 64 commits into
Deep-MI:devfrom
m-reuter:mac-installer
Sep 2, 2026
Merged

Fix: Fixes #857, and turns the macOS package into a self-contained, Apple-silicon-only install#859
m-reuter merged 64 commits into
Deep-MI:devfrom
m-reuter:mac-installer

Conversation

@m-reuter

@m-reuter m-reuter commented Aug 30, 2026

Copy link
Copy Markdown
Member

Scope change during review: the Intel (x86_64) package is dropped. PyTorch has published no
macOS x86_64 wheels since 2.2, so the bundled environment cannot be resolved for Intel at all.
This is not a regression: v2.5.0 introduced both the macOS packaging workflow and the torch==2.7.*
pin (4688714), so no working Intel package was ever released. The published x86_64 assets simply
failed later, during the install-time pip install on the user's machine. Intel users are pointed at
Docker, whose amd64 image runs natively there and which INSTALL.md already recommended for them.

Installer reliability (the #857 root cause)

  • Fixed the root cause of installer "failed" reports on macOS Unable to Install FastSurfer on MacBook M2 #857: postinstall.sh had no set -e
    (masking real failures) and its trailing xattr -dr com.apple.quarantine cleanup returned non-zero
    whenever any file simply never had the attribute, which was virtually always: added set -e and
    made that cleanup non-fatal
  • Made link_fs.sh symlinks idempotent (ln -sf) so re-running the installer after a prior attempt
    doesn't abort under the new set -e
  • Delete a previous installation of the same version before installing, instead of unpacking into it
  • Fail the build on the first error instead of emitting an incomplete-but-successful-looking installer

Self-contained package

  • Bundle a standalone Python distribution, all dependencies and the network checkpoints into the
    package, so installing needs no network, no Homebrew and no Python on the target machine, and the
    first run does not download weights. Dependencies go into the distribution's own site-packages with
    no virtual environment in between, since a venv's pyvenv.cfg and activate scripts do not survive
    the move to the install location
  • Build against tool.python.version (3.12) rather than the requires-python floor, which is only a
    support floor and was pulling an unintended interpreter
  • FastSurfer itself is deliberately not installed into that environment: the package ships its
    source tree and both run_fastsurfer.sh and the console put it on PYTHONPATH. Installing it as
    well left a second, shadowed copy of every module, which is how the console and the pipeline
    previously imported different copies of the same code. The pyproject.toml fallback path now
    resolves dependencies first and installs those, since installing $FASTSURFER_HOME[qc] directly
    reintroduced exactly that duplication
  • Fixed checkpoint staging, which would have shipped zero checkpoints from CI: the downloader
    resolves paths against the FastSurferCNN package it imports, not $FASTSURFER_HOME, so running the
    checkout's copy wrote the weights into the checkout and copied an untouched --checkpoints-dir into
    the package. In CI that directory is the actions/cache path, so it stayed empty on every run, and an
    empty checkpoints/ is unrecoverable at runtime because the install tree is root-owned
  • Package only tracked, runtime-relevant files, so a dirty tree and dev/CI material stay out of the
    installer; checkpoints are staged explicitly from --checkpoints-dir
  • Record the source commit and ship a complete BUILD.info, so --version works at runtime in a
    package that has no git checkout to interrogate. It is retargeted to the install prefix, and its
    intermediate cache is written outside the checkout, so the shipped file reports neither
    build-machine paths nor a dirty source tree
  • Pin the applet to its packaged location instead of resolving to an older bundle, with a
    version-unique CFBundleIdentifier

Platform support

  • Apple silicon only, built on macos-15 (off the now-deprecated macos-14). arm is the only
    accepted argument; an intel invocation is refused immediately with the reason rather than failing
    an hour later in dependency resolution
  • Two build-time guards, since $ARCH_TYPE only names the package and selects nothing: the build fails
    if the bundled interpreter's architecture does not match the package name, and if any bundled binary
    requires a newer macOS than the documented floor. That floor is the single version the docs state, so
    a dependency update raising it fails the build rather than silently invalidating the documentation
  • Documented one lower bound, macOS 14, the version the bundled binaries are compiled for, and
    explicitly not a tested-support claim, plus Rosetta 2, which the full pipeline needs because
    the bundled FreeSurfer is upstream's Intel-only build. Segmentation (--seg_only) does not use it,
    and a native arm64 FreeSurfer 8 would remove the requirement entirely
  • Normalised the applet's CFBundleShortVersionString and CFBundleVersion, which accept only one to
    three dot-separated integers: a non-release version like 2.6.0-dev0 becomes 0.0.0 rather than
    claiming a release that does not exist yet

FreeSurfer layout

  • Relocated the pruned FreeSurfer install from /Applications/freesurfer to
    $FASTSURFER_HOME/fs-pruned, so it can no longer collide with or partially overwrite a real
    FreeSurfer install (install_fs_pruned.sh gained a --name option; Docker's own use of the script
    is unaffected, but we can consider moving it there too, would be cleaner)
  • Added automatic fallback to $FASTSURFER_HOME/fs-pruned when $FREESURFER_HOME is unset, in the
    shared recon_surf/functions.sh (covers run_fastsurfer.sh, recon-surf.sh, and all other
    consumers); the fallback sources SetUpFreeSurfer.sh rather than only exporting FREESURFER_HOME,
    so it yields a complete environment

The FastSurfer console

  • The applet now execs an explicit /bin/bash and hands it the setup script as its init file.
    do script runs its text in whatever shell Terminal is configured to start, and the setup script
    has always been bash, so the console failed on the first line for anyone whose Terminal shell was
    tcsh or fish. Since --init-file replaces ~/.bashrc, the script sources that first, keeping the
    user's own aliases and settings
  • The console sets PATH in every session rather than only the first, and no longer modifies the
    user's shell profile. Persisting only the PATH entry was a trap, since run_fastsurfer.sh would
    then be found while python3 was still Apple's system Python and FREESURFER_HOME was unset
  • The setup script survives being sourced from a script running set -u or set -e: it no longer
    expands FASTSURFER_CONSOLE, FS_LICENSE, PYTHONPATH or PS1 without defaults (PS1 is unset in
    every non-interactive shell), and it suspends both options across FreeSurfer's own
    SetUpFreeSurfer.sh, which is not strict-mode safe, restoring what the caller had. Building
    PYTHONPATH with ${PYTHONPATH:+:...} also drops a trailing colon that put the working directory on
    sys.path
  • Default PYTORCH_ENABLE_MPS_FALLBACK=1 on macOS, set in run_fastsurfer.sh (it must be in place
    before torch is imported, so it cannot live in Python), which also let the redundant export be
    dropped from the console template

macOS and BSD portability

  • Check the running bash version rather than whatever bash is on PATH, since Apple ships bash 3.2
    as /bin/bash while a Homebrew bash 5 may be first on PATH
  • Fall back gracefully when timeout is unavailable, as on macOS, and stop warning on every timed
    command once timing is known to be unavailable
  • Removed two GNU-only assumptions that would have failed on the runners: version.py hashed the
    checkpoints by shelling out to md5sum (now hashlib, which also drops a 10 second timeout that
    hundreds of MB of weights could exceed), and the deployment-target check used sort -V. Both exist
    on macOS 26 but not on macOS 15, so a local test proves nothing about CI

Build and CI

  • Made the slow download+prune cacheable: install_fs_pruned.sh skips the work when a valid pruned
    install is already there, and build_release_package.sh gained --fs-download-cache (raw tarball)
    and --fs-pruned-cache-dir (pruned install), both cached in CI. Cache identity is the URL plus a
    digest of the prune script plus --upx, so editing what gets pruned invalidates it; a partial cache
    is not reused (build-stamp.txt must exist), a corrupt tarball is deleted rather than stamped valid,
    a cached tarball is tied by a sidecar to the URL it came from, and extraction now happens in a
    private directory so it can never delete a sibling freesurfer install
  • Isolated py2app in its own cached venv (--py2app-venv): its dependency scanner walks the whole
    environment it runs in, so unrelated dev packages (matplotlib) make it fail. Plus build-script fixes
    for absolute paths across the pushd, the resolved --fs-pruned-cache-dir, and installing py2app
    whenever it is not importable rather than only when the venv is missing
  • Resolve the uv and checkpoint cache directories in a shell so $HOME is expanded. They were given
    as a literal ~, which actions/cache expands in path but which is passed to a step's env
    verbatim, so the build wrote to a directory actually named ~ inside the workspace while the cache
    action saved and restored one under $HOME, and neither cache was ever hit
  • The installer has a stable file name, so the docs can link straight to
    releases/latest/download/FastSurfer-macos-darwin_arm64.pkg. The version moved to the installer
    window title, which is not name-constrained
  • workflow_dispatch runs upload the installer as a build artifact, so the CI build can be tested
    without publishing a release

Docs

  • Documented the FastSurfer console/environment, the Gatekeeper "Open Anyway" workaround for the
    unsigned .pkg, and the FreeSurfer license situation for package users (where to register, where to
    store the file, why autodetection into fs-pruned won't work) in INSTALL.md
  • Replaced the installer's plain-text conclusion with a styled HTML screen and removed MACOS.md
    entirely; its content is now covered by INSTALL.md, and it was the last consumer of the file
  • Scoped the "source it in any shell" claim to bash and zsh, and dropped --device mps from the
    full-pipeline example: it raises ValueError on any Mac without an MPS-capable GPU, while the
    default auto already picks MPS where available
  • Pinned sphinx-argparse<0.6, whose 0.6.1 broke command xref resolution
  • README.md routes macOS users by architecture, Intel to Docker and Apple silicon to the package.
    tools/macos_build/README.md drops intel and the instruction to install py2app by hand, which
    the cached venv makes unnecessary

Verification

Built via workflow_dispatch on macos-15, then installed from the resulting artifact and checked on macOS 26. Nothing is runtime-tested on 14 or 15. On the installed package: 11 checkpoints (293 MB), bundled python arm64, highest deployment target macOS 14.0, BUILD.info free of staging paths, run_fastsurfer.sh --version reporting 2.6.0-dev0+5967cb06 with no git checkout present, and the console sourcing cleanly under set -euo pipefail with torch 2.7.1 importing.

@m-reuter m-reuter changed the title Fix: false mac installer errors Fix: false mac installer errors and more Mac improvements Aug 30, 2026
@m-reuter
m-reuter requested a lite review from Copilot August 30, 2026 15:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new pruned-FreeSurfer cache reuse and packaging copy logic can mis-handle partially corrupted caches or pre-existing destinations, and the macOS MPS fallback docs should be clarified to match the new default behavior.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR improves the macOS .pkg installer reliability and macOS usability by making post-install steps fail correctly (while avoiding known false failures), relocating the bundled pruned FreeSurfer to avoid collisions with real FreeSurfer installs, and updating CI/docs to match the new packaging behavior.

Changes:

  • Make macOS postinstall stricter (set -e) while making quarantine attribute cleanup non-fatal; make FreeSurfer symlink creation idempotent.
  • Bundle pruned FreeSurfer under $FASTSURFER_HOME/fs-pruned, add --name support and CI caching for faster packaging.
  • Add a macOS-specific MPS fallback default and update installer/docs navigation and install guidance.
File summaries
File Description
tools/macos_build/scripts/postinstall.sh.template Enable set -e, point bundled FreeSurfer to fs-pruned, and make xattr cleanup non-fatal.
tools/macos_build/macos_setup_fastsurfer.sh.template Default FREESURFER_HOME to the bundled fs-pruned and update docs link.
tools/macos_build/edit_distribution.py Clarify that MACOS.md is used as the installer’s plain-text conclusion screen.
tools/macos_build/build_release_package.sh Install pruned FreeSurfer into fs-pruned, support cached builds, and retain MACOS.md in resources.
tools/build/link_fs.sh Make symlink creation idempotent via ln -sf.
tools/build/install_fs_pruned.sh Add --name option and introduce cache reuse keyed by the source URL marker.
run_fastsurfer.sh Auto-set PYTORCH_ENABLE_MPS_FALLBACK=1 on macOS when unset (before any PyTorch import).
recon_surf/functions.sh Add fallback to bundled fs-pruned when FREESURFER_HOME is unset and the stamp file exists.
pyproject.toml Pin sphinx-argparse to <0.6 due to issues in newer versions.
doc/overview/INSTALL.md Document Gatekeeper “Open Anyway” flow and expand macOS console/environment guidance.
doc/overview/index.rst Remove MACOS.md from visible nav while keeping it in a hidden toctree.
.github/workflows/deploy.yml Add cache keying and caching for pruned FreeSurfer to speed up macOS packaging CI.
Review details
  • Files reviewed: 12/12 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tools/build/install_fs_pruned.sh Outdated
Comment thread tools/macos_build/build_release_package.sh Outdated
Comment thread doc/overview/INSTALL.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The fallback omits FreeSurfer environment initialization, and interrupted cached downloads can be accepted as complete.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 12/12 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread recon_surf/functions.sh
Comment thread tools/build/install_fs_pruned.sh

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Cache copying, validation, and py2app environment handling can currently produce missing or persistently incomplete package contents.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

tools/build/install_fs_pruned.sh:491

  • The cache marker is written unconditionally even though this script does not use set -e and the preceding copy/pruning commands do not accumulate or check failures. For example, a missing archive member makes cp fail, but build-stamp.txt may already exist and this marker is still created; every later invocation then treats that incomplete install as valid and exits at line 93. Only publish the marker after verified successful pruning (ideally build in a temporary directory and atomically move it into the cache).
# record what this pruned install was built from, so a re-run (e.g. from a restored CI cache) can
# tell whether it is still valid instead of blindly reusing possibly-stale content
echo "$fslink" > "$source_marker"
  • Files reviewed: 13/13 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread tools/macos_build/build_release_package.sh Outdated
Comment thread tools/macos_build/build_release_package.sh

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Cold-cache builds currently fail, and stale or incomplete staging/cache contents can be packaged or reused.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

tools/build/install_fs_pruned.sh:491

  • This marker can certify an incomplete install. The script does not use set -e, and failures in the preceding cp/touch loops are followed by later successful commands, so the marker and build-stamp.txt can both exist even when required files were not copied; every later run then skips rebuilding that broken cache. Ensure all build operations abort on failure before writing the marker.
# record what this pruned install was built from, so a re-run (e.g. from a restored CI cache) can
# tell whether it is still valid instead of blindly reusing possibly-stale content
echo "$fslink" > "$source_marker"
  • Files reviewed: 15/15 changed files
  • Comments generated: 3
  • Review effort level: Balanced

Comment thread tools/macos_build/build_release_package.sh
Comment thread tools/macos_build/build_release_package.sh
Comment thread tools/build/install_fs_pruned.sh Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Intel-incompatible commands, shell PATH handling, and unchecked cache-copy failures can produce unusable installations.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (4)

Previously missed (3) — in code that hasn't changed since the last review.

tools/macos_build/conclusion.html.template:51

  • These examples are also embedded in the x86_64 installer, where MPS is unavailable and an explicit --device mps raises ValueError (FastSurferCNN/utils/common.py:133-137). Use auto so the same conclusion works for both package architectures while still selecting MPS on Apple silicon.
<pre>run_fastsurfer.sh --seg_only --device mps \
  --sd &lt;output/dir&gt; --sid &lt;subject_id&gt; --t1 &lt;subject/t1.nii.gz&gt;</pre>
<p>Full pipeline, including surfaces:</p>
<pre>run_fastsurfer.sh --device mps --fs_license ~/fs_license.txt \
  --sd &lt;output/dir&gt; --sid &lt;subject_id&gt; --t1 &lt;subject/t1.nii.gz&gt;</pre>

doc/overview/INSTALL.md:227

  • This command is presented in the package instructions shared by Intel and Apple-silicon users, but explicit mps fails on Intel Macs. Use auto (the script default), which selects MPS when available and CPU otherwise.
run_fastsurfer.sh --device mps --sd <path/to/output/dir> --sid <subject_id> --t1 <path/to/subjects/t1/image> --fs_license ~/fs_license.txt

tools/macos_build/conclusion.html.template:40

  • This PATH guarantee breaks after the first applet launch on macOS's default zsh. The setup script writes only ~/.bash_profile; on the first zsh launch it also exports PATH, but on later launches the existing profile line makes it skip the export even though zsh never loaded that file, leaving run_fastsurfer.sh unavailable. Persist/load the entries for the active shell and always export them in the current console.
<p>Double-click <b><fastsurfer></b> in your Applications folder. It opens a Terminal window that
has everything set up &mdash; the Python environment, the pruned FreeSurfer bundled with this
package, and <code>run_fastsurfer.sh</code> on your <code>PATH</code>. You can recognize it by the

tools/build/install_fs_pruned.sh:507

  • The source marker is written unconditionally even though this script does not use set -e and the preceding copy loop does not check cp failures. If an upstream archive omits a listed file or a copy fails, build-stamp.txt may already exist and this marker causes the incomplete tree to be accepted and cached as valid on every later run. Only create the marker after all required construction steps have been checked successfully.
# record what this pruned install was built from, so a re-run (e.g. from a restored CI cache) can
# tell whether it is still valid instead of blindly reusing possibly-stale content
echo "$fslink" > "$source_marker"
  • Files reviewed: 15/15 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread tools/macos_build/build_release_package.sh
postinstall had no set -e, so a real failure (pip, checkpoint download)
went unreported, while xattr -dr made the script exit non-zero whenever
any file simply never carried com.apple.quarantine -- which is most of
them -- so Installer.app reported failed even on a fully successful
install (Deep-MI#857).
…re to store it, why autodetection into fs-pruned won't work)
…conclusion screen) and pin sphinx-argparse<0.6 (0.6.1 broke command xref resolution)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The build uses GNU-only sort -V, which fails on the targeted macOS runners.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

tools/macos_build/build_release_package.sh:274

  • This second sort -V invocation has the same macOS portability failure: BSD sort rejects -V, so the comparison aborts the build instead of enforcing the deployment target. Use the same portable numeric-component ordering as the probe above.
elif [[ "$(printf '%s\n%s\n' "$MACOS_MIN_SUPPORTED" "$macos_min_found" | sort -V | tail -1)" != "$MACOS_MIN_SUPPORTED" ]]
  • Files reviewed: 22/22 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread tools/macos_build/build_release_package.sh Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The new FreeSurfer caching and custom-name logic can reuse incorrect archives or delete an unrelated installation.

Review details

Suppressed comments (3)

Previously missed (1) — in code that hasn't changed since the last review.

tools/build/install_fs_pruned.sh:97

  • The cache identity ignores --upx, although that flag changes the generated install. Reusing the same destination first without --upx and then with it exits here with an unpacked tree (and the reverse reuses a packed tree), so the requested output is not rebuilt.

This issue also appears in the following locations of the same file:

  • line 119
  • line 133
cache_stamp="$fslink $script_digest"

tools/build/install_fs_pruned.sh:119

  • With the new --name option, this unconditionally deletes a different sibling named freesurfer. For example, installing as --name fs-pruned under a directory that already contains a real FreeSurfer installation removes that installation, even though only $where/fs-pruned was requested. Extract into a private temporary directory (or fail rather than deleting an unrelated sibling) before moving the result to $fsd.
rm -rf "$fsd" "$fss" "$where/freesurfer"

tools/build/install_fs_pruned.sh:136

  • This cache file is reused solely because it exists; it is not tied to fslink. If the FreeSurfer URL/version changes while the caller keeps the same cache path, the old valid archive is pruned and then stamped as if it came from the new URL, producing a successful but incorrectly versioned package. Store and verify a URL/checksum sidecar, or invalidate the file whenever its source URL differs.
if [[ -n "$download_cache" ]] ; then
  freesurfer_dl="$download_cache"
  mkdir -p "$(dirname "$freesurfer_dl")"
  delete_freesurfer_dl="false"
  • Files reviewed: 22/22 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Extraction went into  and cleaned /freesurfer first, which with
--name deletes an unrelated FreeSurfer install rather than this script's own
target; it now unpacks into a private directory. Also fold --upx into the cache
identity, and tie the --fs-download-cache archive to the URL it came from, so a
version bump cannot prune the old tarball and stamp it as the new version.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The advertised Intel build cannot resolve the pinned PyTorch dependency because macOS x86_64 wheels are unavailable.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

doc/overview/INSTALL.md:184

  • This advertises Intel support, but the bundled dependency constraints cannot be installed on Intel macOS: both requirements.txt (torch==2.7.1) and the pyproject fallback (torch==2.7.*, torchvision>=0.22) require releases for which no macOS x86_64 wheels are published. Until the build uses an Intel-compatible dependency set or custom wheels, this requirement should not promise an Intel package.
  • Files reviewed: 22/22 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread .github/workflows/deploy.yml Outdated
PyTorch publishes no macOS x86_64 wheels after 2.2, so the bundled environment
cannot be resolved for Intel at all; the x86_64 packages released since v2.5.0
have never worked, they only failed later, at pip time on the user's machine.
Drop the intel matrix entry and point Intel users at Docker, which runs the
amd64 image natively there and is already the documented option for them.
The asset name embedded the version, so no permanent download URL was possible
and the docs had to tell people to navigate the releases page. Drop the version
from the file name, keep it in the installer window title via PACKAGE_TITLE, and
link releases/latest/download/... from INSTALL.md.
workflow_dispatch could already build on any branch, but both asset steps are
gated on a release, so the package was built and discarded. Upload it for
non-release runs, so the CI build can be tested and the result downloaded
without publishing anything.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The build still advertises an unsupported Intel target and temporary FreeSurfer URL sidecars are not cleaned up.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

tools/build/install_fs_pruned.sh:255

  • When the default temporary-download branch is used, the tarball is deleted but the newly created .url sidecar is not. Each uncached local or CI build therefore leaves a timestamped freesurfer_*.tar.gz.url artifact in its working directory. Remove the sidecar together with the temporary archive; only persistent caches need to retain it.
  • Files reviewed: 22/22 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread tools/macos_build/build_release_package.sh Outdated
@m-reuter m-reuter changed the title Fix: Fixes #857 and turns the macOS package into a self-contained install. Fix: Fixes #857 and turns the macOS arm package into a self-contained install. Sep 2, 2026
@m-reuter
m-reuter requested a balanced review from Copilot September 2, 2026 00:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Generated provenance is always marked dirty, and development builds emit an invalid bundle version string.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

tools/macos_build/build_release_package.sh:326

  • -o is parsed with argparse.FileType("w"), so this file is created before version.py runs git status -sb. Because tools/macos_build/BUILD.info.git is not ignored, every package built from an otherwise clean checkout records this generated file as an untracked change and reports a dirty source tree. Create the temporary cache outside the checkout.
  • Files reviewed: 22/22 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread tools/macos_build/setup.py Outdated
CFBundleShortVersionString allows only one to three dot-separated integers, so
2.6.0-dev0 was invalid. Non-release versions become 0.0.0 rather than being
truncated to a release that does not exist yet; the identifier keeps the full
version.
@m-reuter m-reuter changed the title Fix: Fixes #857 and turns the macOS arm package into a self-contained install. Fix: Fixes #857, and turns the macOS package into a self-contained, Apple-silicon-only install Sep 2, 2026
State one number, the macOS 14 the bundled binaries are compiled for, as a
lower bound rather than a support claim. The build-time check enforces that
figure, so it fails loudly if a dependency update raises it.
@m-reuter
m-reuter merged commit f07fd28 into Deep-MI:dev Sep 2, 2026
4 checks passed
@m-reuter
m-reuter deleted the mac-installer branch September 2, 2026 15:17
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.

2 participants