mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-08 08:04:25 -10:00
Merge pull request #6575 from Hmbown/fix/homebrew-install-detection
fix(update): detect Homebrew installs launched through the bin symlink on macOS
This commit is contained in:
2 files changed
+42
-5
No files matched your search
@@ -59,13 +59,23 @@ pub enum InstallMethod {
|
||||
impl InstallMethod {
|
||||
/// Detect from an executable path, honouring [`INSTALL_METHOD_ENV`].
|
||||
///
|
||||
/// Pass the *resolved* path — `std::env::current_exe()` already follows
|
||||
/// symlinks on the platforms we ship, which is what puts a globally
|
||||
/// npm-installed binary inside `node_modules` and a Homebrew one inside
|
||||
/// `Cellar` rather than in the manager's flat `bin` shim directory.
|
||||
/// `std::env::current_exe()` follows symlinks on Linux but not on macOS,
|
||||
/// where a Homebrew launch reports `/opt/homebrew/bin/codewhale` instead
|
||||
/// of the `Cellar` file it points at. When the path as given looks
|
||||
/// self-updatable, the symlink target is checked too, and a package
|
||||
/// manager that owns the real file wins.
|
||||
#[must_use]
|
||||
pub fn detect(exe: &Path) -> Self {
|
||||
let detected = Self::detect_with_omarchy_probe(exe, omarchy_package_owns);
|
||||
let mut detected = Self::detect_with_omarchy_probe(exe, omarchy_package_owns);
|
||||
if detected.supports_self_update()
|
||||
&& let Ok(real) = std::fs::canonicalize(exe)
|
||||
&& real != exe
|
||||
{
|
||||
let owner = Self::detect_with_omarchy_probe(&real, omarchy_package_owns);
|
||||
if !owner.supports_self_update() {
|
||||
detected = owner;
|
||||
}
|
||||
}
|
||||
// An override can identify a relocated package, but cannot authorize
|
||||
// replacing a file that a known package manager owns.
|
||||
if !detected.supports_self_update() {
|
||||
@@ -249,6 +259,30 @@ mod tests {
|
||||
assert!(!InstallMethod::Homebrew.supports_self_update());
|
||||
}
|
||||
|
||||
/// macOS reports the launcher symlink from `current_exe()`, so detection
|
||||
/// must follow it into `Cellar` before allowing an in-place update.
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn homebrew_symlink_launcher_is_detected_through_its_target() {
|
||||
let root = tempfile::tempdir().unwrap();
|
||||
let cellar_bin = root.path().join("Cellar/codewhale/0.10.0/bin");
|
||||
std::fs::create_dir_all(&cellar_bin).unwrap();
|
||||
let real = cellar_bin.join("codewhale");
|
||||
std::fs::write(&real, b"binary").unwrap();
|
||||
let bin = root.path().join("bin");
|
||||
std::fs::create_dir_all(&bin).unwrap();
|
||||
let launcher = bin.join("codewhale");
|
||||
std::os::unix::fs::symlink(&real, &launcher).unwrap();
|
||||
|
||||
assert_eq!(InstallMethod::from_path(&launcher), InstallMethod::Binary);
|
||||
assert_eq!(InstallMethod::detect(&launcher), InstallMethod::Homebrew);
|
||||
|
||||
// A plain release binary with no package owner stays self-updatable.
|
||||
let plain = bin.join("codew");
|
||||
std::fs::write(&plain, b"binary").unwrap();
|
||||
assert!(InstallMethod::detect(&plain).supports_self_update());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cargo_install_requires_the_cargo_bin_pair() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -77,6 +77,9 @@
|
||||
"crates/release/src/check.rs": {
|
||||
"std_fs": 4
|
||||
},
|
||||
"crates/release/src/install.rs": {
|
||||
"std_fs": 1
|
||||
},
|
||||
"crates/release/src/launch.rs": {
|
||||
"std_fs": 2
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user