Skip to content

Auto-update /Applications/Emacs.app in post_install#914

Open
peteWT wants to merge 2 commits intod12frosted:masterfrom
peteWT:warn-stale-applications-emacs
Open

Auto-update /Applications/Emacs.app in post_install#914
peteWT wants to merge 2 commits intod12frosted:masterfrom
peteWT:warn-stale-applications-emacs

Conversation

@peteWT
Copy link

@peteWT peteWT commented Feb 5, 2026

Summary

After brew reinstall emacs-plus@XX, users who previously copied Emacs.app to /Applications may still be running a stale binary. This causes confusing errors like the libjpeg.9.dylib issue in #912 — the Cellar copy is rebuilt but the /Applications copy isn't.

This PR adds auto-update logic to post_install: if an existing /Applications/Emacs.app (or ~/Applications/Emacs.app) is detected, it's automatically refreshed from the newly built Cellar copy.

Changes

  • Added auto-update of /Applications copies in post_install for @29, @30, and @31
  • Handles both Emacs.app and Emacs Client.app (for @30 and @31)
  • Re-signs after copy for macOS Sequoia compatibility
  • Graceful error handling — warns but doesn't fail if permissions prevent the update

Why post_install instead of runtime check?

Per feedback from @d12frosted:

  • Solves the root cause: The [General]: jpeg 10 bottle now breaking emacs@30 builds #912 scenario involves unchanged versions but stale dylib linkage — a version check wouldn't catch it
  • No runtime overhead: No --version spawn on every launch
  • Works for GUI: No stderr warning that vanishes before users can read it
  • Prevention > detection: Keeping the copy in sync is better than warning about drift

Motivation

See #912

After `brew reinstall emacs-plus@XX`, users who previously copied
Emacs.app to /Applications may not realize they're still running
the old version. The wrapper script now checks version mismatches
and prints a warning with the command to update.

This addresses confusion seen in issues like d12frosted#912 where users
reinstalled emacs-plus but continued running stale binaries.

Behavior is unchanged - the warning is informational only.
@d12frosted
Copy link
Owner

Interesting! Thanks for the idea and PR. My head is already exploding a bit, so will think about it later today / early tomorrow 🙏 Time for a bottle of wine lol.

@d12frosted
Copy link
Owner

Thanks for the PR and for digging into this! The problem you identified in #912 is real and frustrating — stale Emacs.app copies in /Applications are a genuine UX trap.

I have some concerns about this specific approach though, and I think the root issue is actually broader than version mismatches.

The version check doesn't catch the problem from #912

The scenario in #912 plays out like this:

  1. Build emacs-plus@30 (version 30.2), which links against e.g. libjpeg.9.dylib
  2. Copy Emacs.app to /Applications
  3. brew upgrade runs → libjpeg upgrades to v10 → libjpeg.9.dylib disappears
  4. Homebrew doesn't rebuild emacs-plus because the formula version (30.2) is unchanged
  5. Both the Cellar and /Applications Emacs are now broken (referencing a missing dylib)
  6. User runs brew reinstall emacs-plus@30 → Cellar copy is rebuilt against the new dylib
  7. But /Applications still has the old binary → wrapper finds it first → still broken

The version check sees 30.2 == 30.2 and stays silent — the exact scenario this PR was meant to address is invisible to it. The version didn't change; the dylib linkage did.

Same issue with emacs-plus@31 where the version is always 31.0.50 regardless of the git commit being built.

Implementation concerns

Even setting the above aside, there are some practical issues:

  1. Performanceemacs --version spawns the full Emacs binary on every invocation (50-200ms+), even when versions match.

  2. Warning visibility — the stderr warning prints right before exec replaces the process. In GUI mode (the exact scenario from [General]: jpeg 10 bottle now breaking emacs@30 builds #912), it vanishes before the user can read it.

  3. Dock flash — running the Cocoa Emacs binary with --version can briefly appear in the Dock.

A different approach: auto-update in post_install

Instead of detecting staleness at runtime, we could prevent it at build time. The formula's post_install already re-applies icons and re-signs the app. We could add a step that checks if /Applications/Emacs.app (or ~/Applications/Emacs.app) exists and refreshes it automatically:

# Auto-update /Applications copy if it exists
["/Applications/Emacs.app", "#{Dir.home}/Applications/Emacs.app"].each do |app_dest|
  if File.exist?(app_dest)
    ohai "Updating #{app_dest}..."
    begin
      FileUtils.rm_rf(app_dest)
      FileUtils.cp_r((prefix/"Emacs.app").to_s, app_dest)
      system "codesign", "--force", "--deep", "--sign", "-", app_dest
    rescue => e
      opoo "Could not update #{app_dest}: #{e.message}"
      opoo "Update manually: cp -r #{prefix}/Emacs.app \"#{File.dirname(app_dest)}/\""
    end
  end
end

This solves the #912 scenario directly — after brew reinstall, the /Applications copy is automatically refreshed with the new binary. No version comparison needed; the copy is simply kept in sync.

We also have cask builds (emacs-plus-app, emacs-plus-app@master) that properly manage the app lifecycle in /Applications, which is another option for users who want Spotlight integration without the staleness risk.

What do you think?

Adopts the approach suggested by @d12frosted: instead of warning about
stale /Applications/Emacs.app at runtime, automatically refresh it
during post_install. This:

- Solves the root cause (d12frosted#912) rather than detecting a symptom
- Handles the dylib linkage case (where version is unchanged but
  binary is stale)
- Avoids runtime performance overhead (no --version spawn on launch)
- Works in GUI mode (no stderr warning that vanishes)
- Also handles Emacs Client.app for @30 and @31
- Gracefully handles permission errors with opoo fallback
@peteWT
Copy link
Author

peteWT commented Feb 14, 2026

Revised based on your feedback — you're right that the runtime version check misses the actual #912 scenario (same version, different dylib linkage) and has the performance/GUI visibility issues.

This now implements the post_install auto-update approach you suggested:

  • If /Applications/Emacs.app or ~/Applications/Emacs.app exists when brew install/reinstall/postinstall runs, it's automatically refreshed from the Cellar copy
  • Re-signs after copy for Sequoia compatibility
  • Graceful fallback with opoo if permissions prevent the update
  • Also handles Emacs Client.app for @30 and @31

No runtime changes — the wrapper script is back to stock. Force-pushed to the same branch.

@peteWT peteWT changed the title Warn when /Applications/Emacs.app has a different version Auto-update /Applications/Emacs.app in post_install Feb 14, 2026
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

Comments