Skip to content

Move a translocated Lite to Applications before updating (0.0.96) - #289

Merged
glenn-jocher merged 3 commits into
mainfrom
move-translocated-app
Nov 10, 2026
Merged

glenn-jocher merged 3 commits into
mainfrom
move-translocated-app

Conversation

@glenn-jocher

@glenn-jocher glenn-jocher commented Nov 10, 2026 •

Copy link
Copy Markdown
Member

A new user's update failed with Update failed: Read-only file system (os error 30) at path "/private/var/folders/…/T/AppTranslocation/…/d/tauri_current_app…".

macOS runs a downloaded app that Finder never moved (opened from the disk image or Downloads) from a randomized read-only copy, which no updater can replace. Lite's release is ad-hoc signed, so new users approve it in Gatekeeper first, which is exactly how they end up running it translocated.

When install_update finds its bundle under /AppTranslocation/, it:

  1. copies the bundle with ditto into /Applications, or ~/Applications when that is not writable, staging under a hidden name and replacing an older Lite.app there;
  2. removes com.apple.quarantine from the copy, as Move-to-Applications helpers do, so it opens in place instead of being translocated again;
  3. opens the copy with open -n and exits; the relaunched Lite finds the same update waiting.

Validation (macOS):

  • The v0.0.95 DMG, quarantined and mounted read-only, copies with ditto. The copy carries quarantine 0083, which xattr -dr removes, and codesign --verify --deep --strict passes on the copy.
  • cargo clippy, cargo fmt --check, and cargo test pass.

Not run here: an actual translocated launch through to the relaunch.

🛠️ PR Summary

Made with ❤️ by Ultralytics Actions

🌟 Summary

Lite 0.0.96 now detects macOS App Translocation during update installation, moves to an Applications folder, and relaunches from there so the update can be retried outside the read-only location.

📊 Key Changes

  • On macOS, install_update checks whether Lite’s bundle path contains /AppTranslocation/.
  • Lite copies its bundle with ditto to /Applications, falling back to ~/Applications, and removes the copy’s quarantine attribute.
  • If a Lite bundle already exists at the chosen destination, it is reused; otherwise, failed copy attempts are cleaned up before trying the next folder.
  • Lite opens the destination with open -n and exits; if it cannot find a usable destination or open the copy, it returns guidance to open Lite from Applications and update again.
  • The package version is bumped from 0.0.95 to 0.0.96.

🎯 Purpose & Impact

  • For a translocated macOS launch, the update workflow now moves and relaunches Lite from an Applications folder before retrying the update. An end-to-end translocated launch through relaunch was not run.
📋 Skipped 1 file (lock files, generated, images, etc.)
  • src-tauri/Cargo.lock

macOS runs a downloaded app that Finder never moved from a read-only copy, so an
update failed with "Read-only file system (os error 30)" under AppTranslocation.
Lite now copies itself into /Applications (or ~/Applications), lifts the download
mark so the copy opens in place, and reopens from there, where the update waits.
@UltralyticsAssistant UltralyticsAssistant added bug Something isn't working fixed Bug has been resolved labels Nov 10, 2026
@UltralyticsAssistant

Copy link
Copy Markdown
Member

👋 Hello @glenn-jocher, thank you for submitting a ultralytics/lite 🚀 PR! This automated message confirms your contribution was received, and an Ultralytics engineer will assist with the review. To ensure a seamless integration of your work, please review the following checklist:

  • ✅ Define a Purpose: Clearly explain the purpose of your fix or feature in your PR description, and link to any relevant issues. Ensure your commit messages are clear, concise, and adhere to the project's conventions.
  • ✅ Synchronize with Source: Confirm your PR is synchronized with the ultralytics/lite main branch. If it's behind, update it by clicking the 'Update branch' button or by running git pull and git merge main locally.
  • ✅ Ensure CI Checks Pass: Verify all Ultralytics Continuous Integration (CI) checks are passing. If any checks fail, please address the issues.
  • ✅ Update Documentation: Update the relevant documentation for any new or modified features.
  • ✅ Add Tests: If applicable, include or update tests to cover your changes, and confirm that all tests are passing.
  • ✅ Sign the CLA: Please ensure you have signed our Contributor License Agreement if this is your first Ultralytics PR; the CLA check will comment with signing instructions if needed.
  • ✅ Minimize Changes: Limit your changes to the minimum necessary for your bug fix or feature addition. "It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is." — Bruce Lee

For more guidance, please refer to our Contributing Guide. Don't hesitate to leave a comment if you have any questions. Thank you for contributing to Ultralytics! 🚀

@UltralyticsAssistant UltralyticsAssistant left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🔍 PR Review

Made with ❤️ by Ultralytics Actions

Reviewed the version bump and macOS translocation relocation path. The relocation handles the intended read-only launch scenario, but replacing an existing app can leave no installation if the staged rename fails after the old bundle is removed.

💬 Posted 1 inline comment
  • 💡 MEDIUM src-tauri/src/lib.rs:7993 If removing the existing app succeeds but the following rename fails, this deletes the working installation; the error path then removes the staged copy and continues. Preserve the old bundle until the replacement succeeds, for example by renaming it to a backup and restoring it if the staged rename fails.
📋 Skipped 1 file (lock files, generated, images, etc.)
  • src-tauri/Cargo.lock

Comment thread src-tauri/src/lib.rs
}
// An older Lite already there is the one this copy replaces.
let target = folder.join(name);
let _ = fs::remove_dir_all(&target);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

💡 MEDIUM: If removing the existing app succeeds but the following rename fails, this deletes the working installation; the error path then removes the staged copy and continues. Preserve the old bundle until the replacement succeeds, for example by renaming it to a backup and restoring it if the staged rename fails.

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.

Resolved in 5d54c6a: an existing Lite.app is never removed or replaced any more. It is opened instead, and the only cleanup deletes a copy this call just created.

…n the move fails

- A Lite already in Applications is opened rather than replaced, so the move never
  deletes anything it did not create.
- ditto copies straight to the target; a failed copy or a quarantine mark that
  cannot be lifted removes only that new copy.
- A failed open reports the error instead of quitting Lite.
@glenn-jocher
glenn-jocher merged commit 366e3af into main Nov 10, 2026
9 checks passed
@glenn-jocher
glenn-jocher deleted the move-translocated-app branch November 10, 2026 18:35
@UltralyticsAssistant

Copy link
Copy Markdown
Member

🎉 Thanks @glenn-jocher — this PR has been merged! Lite now detects macOS App Translocation, moves and relaunches from an Applications folder so users can retry the update outside the read-only location.

“Great things are done by a series of small things brought together.” — Vincent van Gogh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working fixed Bug has been resolved

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants