Skip to content

Try to use .dmg installers on macOS before .tar.gz#1320

Merged
IanButterworth merged 2 commits intomainfrom
ib/dmg
Feb 8, 2026
Merged

Try to use .dmg installers on macOS before .tar.gz#1320
IanButterworth merged 2 commits intomainfrom
ib/dmg

Conversation

@IanButterworth
Copy link
Copy Markdown
Member

@IanButterworth IanButterworth commented Nov 3, 2025

Summary

Use DMG installers instead of tarballs on macOS when available. This avoids the need for notarizing the standard library since DMG-distributed .app bundles come with notarization tickets intact.

Also strips the com.apple.quarantine extended attribute after extraction (both DMG and tarball) to prevent Gatekeeper/XProtect scanning delays during installation.

Changes

  • DMG-first installation: On macOS, attempt to download .dmg files first, falling back to .tar.gz if unavailable
  • App bundle support: Handle .app bundle directory structure (Contents/Resources/julia/bin/julia) when resolving Julia binary paths via resolve_julia_binary_path
  • Quarantine stripping: Remove com.apple.quarantine xattr after extraction to avoid Gatekeeper scanning delays that were causing macOS CI to take 20-45 minutes
  • RAII DMG handling: DmgMountGuard ensures DMG volumes are always detached, even on error paths
  • Progress feedback: Show status during DMG mount/copy/unmount phases ("Mounting installer...", "Copying application...", etc.)
  • Graceful fallback: If DMG download or mount fails, automatically fall back to tarball extraction with existing notarization check
  • Pre-computed binary paths: Store resolved binary paths in config (BinaryPath field, skip_serializing_if = "Option::is_none" for backward compatibility), with runtime fallback for existing installations
  • PR build codesigning: Skip codesigning for DMG installs (already signed); gate on is_pr && !used_dmg in install_from_url
  • HTTP error handling: Add status code checks and user-friendly hints for download_juliaup_version and download_versiondb failures
  • New tests: symlink_uses_app_bundle_for_system_channel, symlink_uses_app_bundle_for_direct_download_channel, dmg_failure_falls_back_to_tarball

CI performance

macOS CI time reduced significantly due to using dmgs and quarantine stripping:

  • aarch64: 25m → 8m
  • x86_64: 45m → 8m

Example

% juliaup add release
  Installing Julia 1.12.1+0.aarch64.apple.darwin14
         Add Installed Julia channel 'release'
% julia +release -e "@time using Pkg"
  0.328271 seconds (517.75 k allocations: 34.026 MiB)

Technical notes

  • The current implementation uses runtime URL manipulation (.tar.gz.dmg) as a workaround. TODO comments document the preferred approach: a v2 database schema with multiple ranked download sources per platform
  • install_from_url and install_non_db_version now return Result<(JuliaupConfigChannel, bool)> where the bool indicates whether a DMG was used, enabling callers to skip codesigning/notarization for DMG installs
  • The notarization check for tarball installations is preserved for Julia ≥1.11 when DMG is not available
  • Note: this does not affect setup-julia CI action — that downloads tarballs directly and handles notarization separately (context)

Related

@DilumAluthge
Copy link
Copy Markdown
Member

Might be worth sticking a link to this comment as a code comment somewhere here, otherwise people (like me) might forget why the setup-julia issue doesn't apply here.

Comment thread src/operations.rs

#[cfg(target_os = "macos")]
fn try_download_dmg_with_fallback(url: &url::Url, target_path: &Path) -> Result<(String, bool)> {
let dmg_url = if url.as_str().ends_with(".tar.gz") {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should really handle that in the construction of the version db, right? I.e. where there is a dmg file available, the UrlPath path in the version DB should just point to that.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I thought about that but would that be backwards compatible? The db needs to serve before and after we add dmg support

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The version db file itself is versioned, so when we update the schema (which this would essentially be a case of) we would publish it as version db 2 file, so any old client would just stay on the old version file. Would actually be good to test such a version db schema change with a relatively simply case like this one.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I spent some time trying to figure out the database update approach and don't think I understand how to add the v2 database and keep updating the v1 database.

I think implementing that is a bit outside of my wheelhouse...

Do you think we could proceed with this approach for now, with a TODO to update the database version format appropriately?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think my original thinking for DB versions was that we stop updating v1 database once we start to publish v2 databases. The general idea for Juliaup is that the binaries need to be kept up-to-date.

I would prefer that we try to do this with a DB update, I'm happy to help with that.

One thing I don't fully understand yet: do we need this stuff for only the PR type channels, or for everything?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Oh, and I can help with the DB update!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Thanks.

It's needed for all official releases. I'm not sure which of the nightlies or PRs have dmgs

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@davidanthoff to try and help this move along I've given the database format changes a go. What do you think?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think we need to keep moving forward here, so I'm going to implement the dmg switch via the workaround for now, and we can do the db format switch when you have time @davidanthoff

IanButterworth added a commit that referenced this pull request Jan 17, 2026
This implements DMG support for macOS installations using runtime URL conversion
from .tar.gz to .dmg, with fallback to tarball if DMG is not available.

Changes:
- Add resolve_julia_binary_path() to handle .app bundle installations
- Add download_extract_dmg() and try_download_dmg_with_fallback() for DMG handling
- Convert .tar.gz URLs to .dmg on macOS at runtime (string replacement)
- Only do notarization check for stdlib when using tarballs on macOS
- Add TODOs for future database schema v2 that would include multiple ranked
  download sources (DMG, tarball) to eliminate runtime string manipulation

See discussion at: #1320
IanButterworth added a commit that referenced this pull request Jan 17, 2026
This implements DMG support for macOS installations using runtime URL conversion
from .tar.gz to .dmg, with fallback to tarball if DMG is not available.

Changes:
- Add resolve_julia_binary_path() to handle .app bundle installations
- Add download_extract_dmg() and try_download_dmg_with_fallback() for DMG handling
- Convert .tar.gz URLs to .dmg on macOS at runtime (string replacement)
- Only do notarization check for stdlib when using tarballs on macOS
- Add TODOs for future database schema v2 that would include multiple ranked
  download sources (DMG, tarball) to eliminate runtime string manipulation

See discussion at: #1320
IanButterworth added a commit that referenced this pull request Jan 17, 2026
This implements DMG support for macOS installations using runtime URL conversion
from .tar.gz to .dmg, with fallback to tarball if DMG is not available.

Changes:
- Add resolve_julia_binary_path() to handle .app bundle installations
- Add download_extract_dmg() and try_download_dmg_with_fallback() for DMG handling
- Convert .tar.gz URLs to .dmg on macOS at runtime (string replacement)
- Only do notarization check for stdlib when using tarballs on macOS
- Add TODOs for future database schema v2 that would include multiple ranked
  download sources (DMG, tarball) to eliminate runtime string manipulation

See discussion at: #1320
@IanButterworth IanButterworth changed the title Try to use dmgs first on macos Try to use .dmg installers on macOS before .tar.gz Jan 18, 2026
@IanButterworth IanButterworth marked this pull request as ready for review January 18, 2026 02:02
@IanButterworth
Copy link
Copy Markdown
Member Author

Note that this speeds up macOS CI to be in line with other platforms.

aarch - 19m -> 8m
x86 - 27m -> 8m

@IanButterworth IanButterworth force-pushed the ib/dmg branch 2 times, most recently from c1f3150 to 8338920 Compare February 7, 2026 05:05
On macOS, attempt to download .dmg files first when installing Julia,
falling back to .tar.gz if unavailable. DMG-distributed .app bundles
come with notarization tickets intact, avoiding the need for the
stdlib notarization check and local codesigning of PR builds.

Key changes:
- Add download_extract_dmg and try_download_dmg_with_fallback for
  DMG-first installation with automatic tarball fallback
- Add resolve_julia_binary_path to handle .app bundle directory
  structure (Contents/Resources/julia/bin/julia) vs flat layout
- Store pre-computed binary_path in config for efficient launch,
  with runtime fallback for backward compatibility
- Skip codesigning for PR builds installed via DMG (already signed)
- Use resolve_julia_binary_path in codesign_pr_build_if_needed so
  paths are correct for both .app bundles and tarball layouts
- Add HTTP sta
On macOS, attempt to download .dmg files first when installing Julia,
falling back to .tar.gz if unavailable. DMG-distributed .app bundles
come with notarization tauthored-by: Claude <noreply@anthropic.com>
@IanButterworth IanButterworth merged commit a9b4dc5 into main Feb 8, 2026
45 of 54 checks passed
@IanButterworth IanButterworth deleted the ib/dmg branch February 8, 2026 03:22
DilumAluthge added a commit to julia-actions/install-juliaup that referenced this pull request Feb 8, 2026
DilumAluthge added a commit to julia-actions/install-juliaup that referenced this pull request Feb 8, 2026
@DilumAluthge DilumAluthge mentioned this pull request Feb 8, 2026
github-merge-queue Bot pushed a commit to julia-actions/install-juliaup that referenced this pull request Feb 9, 2026
* CI: Fix macOS tests after JuliaLang/juliaup#1320

Necessary after JuliaLang/juliaup#1320

* Add some more debugging output
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.

3 participants