]> git.proxmox.com Git - cargo.git/commitdiff
Canonicalize CARGO_HOME fallback on Windows
authorAlex Crichton <alex@alexcrichton.com>
Thu, 12 May 2016 22:12:16 +0000 (15:12 -0700)
committerbar <baz>
Fri, 13 May 2016 00:27:57 +0000 (17:27 -0700)
This commit ensures that we always return the same fallback value on Windows
regardless of whichever shell we happen to be run from. We do this by removing
the `$HOME` environment variable which `std::env::home_dir` will inspect to
force it to fall back to the system APIs. If the old directory exists then we
favor that one, but otherwise we favor locations like `C:\Users\$user`

Supercedes and closes #2604

src/cargo/util/config.rs
tests/tests.rs

index 9f41c56f5c0fe886cdcde8e49ef25401df519ade..d3ee857e3cc2cf2015660de9e52c743706df26f0 100644 (file)
@@ -600,8 +600,50 @@ fn homedir(cwd: &Path) -> Option<PathBuf> {
     let cargo_home = env::var_os("CARGO_HOME").map(|home| {
         cwd.join(home)
     });
-    let user_home = env::home_dir().map(|p| p.join(".cargo"));
-    cargo_home.or(user_home)
+    if cargo_home.is_some() {
+        return cargo_home
+    }
+
+    // If `CARGO_HOME` wasn't defined then we want to fall back to
+    // `$HOME/.cargo`. Note that currently, however, the implementation of
+    // `env::home_dir()` uses the $HOME environment variable *on all platforms*.
+    // Platforms like Windows then have *another* fallback based on system APIs
+    // if this isn't set.
+    //
+    // Specifically on Windows this can lead to some weird behavior where if you
+    // invoke cargo inside an MSYS shell it'll have $HOME defined and it'll
+    // place output there by default. If, however, you run in another shell
+    // (like cmd.exe or powershell) it'll place output in
+    // `C:\Users\$user\.cargo` by default.
+    //
+    // This snippet is meant to handle this case to ensure that on Windows we
+    // always place output in the same location, regardless of the shell we were
+    // invoked from. We first check `env::home_dir()` without tampering the
+    // environment, and then afterwards we remove `$HOME` and call it again to
+    // see what happened. If they both returned success then on Windows we only
+    // return the first (with the $HOME in place) if it already exists. This
+    // should help existing installs of Cargo continue using the same cargo home
+    // directory.
+    let home_dir_with_env = env::home_dir().map(|p| p.join(".cargo"));
+    let home_dir = env::var_os("HOME");
+    env::remove_var("HOME");
+    let home_dir_without_env = env::home_dir().map(|p| p.join(".cargo"));
+    if let Some(home_dir) = home_dir {
+        env::set_var("HOME", home_dir);
+    }
+
+    match (home_dir_with_env, home_dir_without_env) {
+        (None, None) => None,
+        (None, Some(p)) |
+        (Some(p), None) => Some(p),
+        (Some(a), Some(b)) => {
+            if cfg!(windows) && !a.exists() {
+                Some(b)
+            } else {
+                Some(a)
+            }
+        }
+    }
 }
 
 fn walk_tree<F>(pwd: &Path, mut walk: F) -> CargoResult<()>
index c41cb9b3c25e444a015e7d1416e787e50ca1547c..ff330a5c5c18a75f04a5284af9973bb4d356a3b4 100644 (file)
@@ -92,8 +92,9 @@ fn is_nightly() -> bool {
 fn process<T: AsRef<OsStr>>(t: T) -> cargo::util::ProcessBuilder {
     let mut p = cargo::util::process(t.as_ref());
     p.cwd(&support::paths::root())
-     .env("HOME", &support::paths::home())
      .env_remove("CARGO_HOME")
+     .env("HOME", support::paths::home())
+     .env("CARGO_HOME", support::paths::home().join(".cargo"))
      .env_remove("RUSTC")
      .env_remove("RUSTFLAGS")
      .env_remove("XDG_CONFIG_HOME")      // see #2345