Ver Fonte

fix(avm): expose anchor on PATH via $CARGO_HOME/bin symlink (#3835)

Arthur Bretas há 1 mês atrás
pai
commit
6f76df4161
1 ficheiros alterados com 76 adições e 0 exclusões
  1. 76 0
      avm/src/lib.rs

+ 76 - 0
avm/src/lib.rs

@@ -44,6 +44,15 @@ pub fn version_binary_path(version: &Version) -> PathBuf {
     get_bin_dir_path().join(format!("anchor-{version}"))
 }
 
+/// Path to the cargo binary directory, defaults to `~/.cargo/bin` if `CARGO_HOME`
+#[cfg(not(test))] // this prevents tests from running this function so we don't change the developer environment during tests
+fn cargo_bin_dir() -> Option<PathBuf> {
+    if let Ok(cargo_home) = std::env::var("CARGO_HOME") {
+        return Some(PathBuf::from(cargo_home).join("bin"));
+    }
+    dirs::home_dir().map(|home| home.join(".cargo").join("bin"))
+}
+
 /// Ensure the users home directory is setup with the paths required by AVM.
 pub fn ensure_paths() {
     let home_dir = AVM_HOME.to_path_buf();
@@ -94,6 +103,73 @@ pub fn ensure_paths() {
         }
     }
 
+    // Try to make `anchor` available on PATH by placing it into $CARGO_HOME/bin (or ~/.cargo/bin).
+    #[cfg(not(test))]
+    {
+        if let Some(cargo_bin) = cargo_bin_dir() {
+            if cargo_bin.exists() {
+                let anchor_in_cargo = cargo_bin.join(if cfg!(target_os = "windows") {
+                    "anchor.exe"
+                } else {
+                    "anchor"
+                });
+                if !anchor_in_cargo.exists() {
+                    let target = avm_in_bin.clone(); // ~/.avm/bin/avm
+
+                    let mut linked = false;
+                    #[cfg(unix)]
+                    {
+                        if let Err(e) = std::os::unix::fs::symlink(&target, &anchor_in_cargo) {
+                            eprintln!(
+                                "Failed to create cargo-bin symlink: {e}. Falling back to copy."
+                            );
+                        } else {
+                            linked = true;
+                        }
+                    }
+                    #[cfg(windows)]
+                    {
+                        use std::os::windows::fs::symlink_file;
+                        if let Err(e) = symlink_file(&target, &anchor_in_cargo) {
+                            eprintln!(
+                                "Failed to create cargo-bin symlink: {e}. Falling back to copy."
+                            );
+                        } else {
+                            linked = true;
+                        }
+                    }
+
+                    if !linked {
+                        if let Err(e) = fs::copy(&target, &anchor_in_cargo) {
+                            eprintln!(
+                                "Failed to place `anchor` in {}: {}.\nAdd {} to your PATH or create a symlink manually.",
+                                cargo_bin.display(),
+                                e,
+                                bin_dir.display()
+                            );
+                        } else {
+                            // Ensure executable bit on UNIX when copying.
+                            #[cfg(unix)]
+                            {
+                                use std::os::unix::fs::PermissionsExt;
+                                if let Err(e) = fs::set_permissions(
+                                    &anchor_in_cargo,
+                                    fs::Permissions::from_mode(0o775),
+                                ) {
+                                    eprintln!(
+                                        "Failed to set executable permissions on {}: {}",
+                                        anchor_in_cargo.display(),
+                                        e
+                                    );
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     if !current_version_file_path().exists() {
         fs::File::create(current_version_file_path()).expect("Could not create .version file");
     }