From 418c512b16d73d268fc8fb6d5f841f7e9f3551c5 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 12 Nov 2016 03:44:51 +0000 Subject: [PATCH 1/2] Use ~/.rustup instead of ~/.multirust This will silently do the upgrade when rustup is run, and uses several defenses to avoid breaking due to interactions with rustup.sh. --- src/rustup-cli/self_update.rs | 2 +- src/rustup-utils/src/utils.rs | 131 ++++++++++++++++++++++++++++++++- tests/cli-rustup.rs | 134 ++++++++++++++++++++++++++++++++++ 3 files changed, 265 insertions(+), 2 deletions(-) diff --git a/src/rustup-cli/self_update.rs b/src/rustup-cli/self_update.rs index 1d5ec2b89ee..68135847cdb 100644 --- a/src/rustup-cli/self_update.rs +++ b/src/rustup-cli/self_update.rs @@ -508,7 +508,7 @@ fn cleanup_legacy() -> Result<()> { #[cfg(unix)] fn legacy_multirust_home_dir() -> Result { - Ok(try!(utils::multirust_home())) + Ok(try!(utils::legacy_multirust_home())) } #[cfg(windows)] diff --git a/src/rustup-utils/src/utils.rs b/src/rustup-utils/src/utils.rs index 4b568befccb..7ae21f2672b 100644 --- a/src/rustup-utils/src/utils.rs +++ b/src/rustup-utils/src/utils.rs @@ -497,12 +497,141 @@ pub fn cargo_home() -> Result { cargo_home.or(user_home).ok_or(ErrorKind::CargoHome.into()) } +// Convert the ~/.multirust folder to ~/.rustup while dealing with rustup.sh +// metadata, which used to also live in ~/.rustup, but now lives in ~/rustup.sh. +pub fn do_rustup_home_upgrade() -> bool { + + fn rustup_home_is_set() -> bool { + env::var_os("RUSTUP_HOME").is_some() + } + + fn rustup_dir() -> Option { + dot_dir(".rustup") + } + + fn rustup_sh_dir() -> Option { + dot_dir(".rustup.sh") + } + + fn multirust_dir() -> Option { + dot_dir(".multirust") + } + + fn rustup_dir_exists() -> bool { + rustup_dir().map(|p| p.exists()).unwrap_or(false) + } + + fn rustup_sh_dir_exists() -> bool { + rustup_sh_dir().map(|p| p.exists()).unwrap_or(false) + } + + fn multirust_dir_exists() -> bool { + multirust_dir().map(|p| p.exists()).unwrap_or(false) + } + + fn rustup_old_version_exists() -> bool { + rustup_dir() + .map(|p| p.join("rustup-version").exists()) + .unwrap_or(false) + } + + fn delete_rustup_dir() -> Result<()> { + if let Some(dir) = rustup_dir() { + raw::remove_dir(&dir) + .chain_err(|| "unable to delete rustup dir")?; + } + + Ok(()) + } + + fn rename_rustup_dir_to_rustup_sh() -> Result<()> { + let dirs = (rustup_dir(), rustup_sh_dir()); + if let (Some(rustup), Some(rustup_sh)) = dirs { + fs::rename(&rustup, &rustup_sh) + .chain_err(|| "unable to rename rustup dir")?; + } + + Ok(()) + } + + fn rename_multirust_dir_to_rustup() -> Result<()> { + let dirs = (multirust_dir(), rustup_dir()); + if let (Some(rustup), Some(rustup_sh)) = dirs { + fs::rename(&rustup, &rustup_sh) + .chain_err(|| "unable to rename multirust dir")?; + } + + Ok(()) + } + + // If RUSTUP_HOME is set then its default path doesn't matter, so we're + // not going to risk doing any I/O work and making a mess. + if rustup_home_is_set() { return true } + + // Now we are just trying to get a bogus, rustup.sh-created ~/.rustup out + // of the way in the manner that is least likely to take time and generate + // errors. First try to rename it to ~/.rustup.sh, then try to delete it. + // If that doesn't work we can't use the ~/.rustup name. + let old_rustup_dir_removed = if rustup_old_version_exists() { + if !rustup_sh_dir_exists() { + if rename_rustup_dir_to_rustup_sh().is_ok() { + true + } else { + if delete_rustup_dir().is_ok() { + true + } else { + false + } + } + } else { + if delete_rustup_dir().is_ok() { + true + } else { + false + } + } + } else { + true + }; + + // Now we're trying to move ~/.multirust to ~/.rustup + old_rustup_dir_removed && if multirust_dir_exists() { + if rustup_dir_exists() { + // There appears to be both a ~/.multirust dir and a valid ~/.rustup + // dir. Weird situation. Pick ~/.rustup. + true + } else { + if rename_multirust_dir_to_rustup().is_ok() { + true + } else { + false + } + } + } else { + true + } +} + +fn dot_dir(name: &str) -> Option { + home_dir().map(|p| p.join(name)) +} + +pub fn legacy_multirust_home() -> Result { + dot_dir(".multirust").ok_or(ErrorKind::MultirustHome.into()) +} + pub fn multirust_home() -> Result { + let use_rustup_dir = do_rustup_home_upgrade(); + let cwd = try!(env::current_dir().chain_err(|| ErrorKind::MultirustHome)); let multirust_home = env::var_os("RUSTUP_HOME").map(|home| { cwd.join(home) }); - let user_home = home_dir().map(|p| p.join(".multirust")); + let user_home = if use_rustup_dir { + dot_dir(".rustup") + } else { + dot_dir(".multirust") + }; multirust_home.or(user_home).ok_or(ErrorKind::MultirustHome.into()) } diff --git a/tests/cli-rustup.rs b/tests/cli-rustup.rs index 69c73dedcc4..699ffb1c32c 100644 --- a/tests/cli-rustup.rs +++ b/tests/cli-rustup.rs @@ -7,6 +7,8 @@ extern crate tempdir; use std::fs; use std::env::consts::EXE_SUFFIX; +use std::process; +use rustup_utils::raw; use rustup_mock::clitools::{self, Config, Scenario, expect_ok, expect_ok_ex, expect_stdout_ok, @@ -583,3 +585,135 @@ fn remove_component() { assert!(!path.parent().unwrap().exists()); }); } + +// Run without setting RUSTUP_HOME, with setting HOME and USERPROFILE +fn run_no_home(config: &Config, args: &[&str], env: &[(&str, &str)]) -> process::Output { + let home_dir_str = &format!("{}", config.homedir.display()); + let mut cmd = clitools::cmd(config, "rustup", args); + clitools::env(config, &mut cmd); + cmd.env_remove("RUSTUP_HOME"); + cmd.env("HOME", home_dir_str); + cmd.env("USERPROFILE", home_dir_str); + for &(name, val) in env { + cmd.env(name, val); + } + let out = cmd.output().unwrap(); + assert!(out.status.success()); + + out +} + +// Rename ~/.multirust to ~/.rustup +#[test] +fn multirust_dir_upgrade_rename_multirust_dir_to_rustup() { + setup(&|config| { + let multirust_dir = config.homedir.join(".multirust"); + let rustup_dir = config.homedir.join(".rustup"); + let multirust_dir_str = &format!("{}", multirust_dir.display()); + + // First write data into ~/.multirust + run_no_home(config, &["default", "stable"], + &[("RUSTUP_HOME", multirust_dir_str)]); + let out = run_no_home(config, &["toolchain", "list"], + &[("RUSTUP_HOME", multirust_dir_str)]); + assert!(String::from_utf8(out.stdout).unwrap().contains("stable")); + + assert!(multirust_dir.exists()); + assert!(!rustup_dir.exists()); + + // Next run without RUSTUP_DIR, but with HOME/USERPROFILE set so rustup + // can infer RUSTUP_DIR. It will silently move ~/.multirust to + // ~/.rustup. + let out = run_no_home(config, &["toolchain", "list"], &[]); + assert!(String::from_utf8(out.stdout).unwrap().contains("stable")); + + assert!(!multirust_dir.exists()); + assert!(rustup_dir.exists()); + }); +} + +// Renaming ~/.multirust to ~/.rustup but ~/.rustup/rustup-version (rustup.sh) exists +#[test] +fn multirust_dir_upgrade_old_rustup_exists() { + setup(&|config| { + let multirust_dir = config.homedir.join(".multirust"); + let rustup_dir = config.homedir.join(".rustup"); + let rustup_sh_dir = config.homedir.join(".rustup.sh"); + + let multirust_dir_str = &format!("{}", multirust_dir.display()); + let old_rustup_sh_version_file = rustup_dir.join("rustup-version"); + let new_rustup_sh_version_file = rustup_sh_dir.join("rustup-version"); + + // First write data into ~/.multirust + run_no_home(config, &["default", "stable"], + &[("RUSTUP_HOME", multirust_dir_str)]); + let out = run_no_home(config, &["toolchain", "list"], + &[("RUSTUP_HOME", multirust_dir_str)]); + assert!(String::from_utf8(out.stdout).unwrap().contains("stable")); + + assert!(multirust_dir.exists()); + assert!(!rustup_dir.exists()); + + // Now add rustup.sh data to ~/.rustup + fs::create_dir_all(&rustup_dir).unwrap(); + raw::write_file(&old_rustup_sh_version_file, "1").unwrap(); + assert!(old_rustup_sh_version_file.exists()); + + // Now do the upgrade, and ~/.rustup will be moved to ~/.rustup.sh + let out = run_no_home(config, &["toolchain", "list"], &[]); + assert!(String::from_utf8(out.stdout).unwrap().contains("stable")); + + assert!(!multirust_dir.exists()); + assert!(rustup_dir.exists()); + assert!(!old_rustup_sh_version_file.exists()); + assert!(new_rustup_sh_version_file.exists()); + }); +} + +// Renaming ~/.multirust to ~/.rustup but ~/.rustup/rustup-version (rustup.sh) exists, +// oh and alse ~/.rustup.sh exists +#[test] +fn multirust_dir_upgrade_old_rustup_existsand_new_rustup_sh_exists() { + setup(&|config| { + let multirust_dir = config.homedir.join(".multirust"); + let rustup_dir = config.homedir.join(".rustup"); + let rustup_sh_dir = config.homedir.join(".rustup.sh"); + + let multirust_dir_str = &format!("{}", multirust_dir.display()); + let old_rustup_sh_version_file = rustup_dir.join("rustup-version"); + let new_rustup_sh_version_file = rustup_sh_dir.join("rustup-version"); + + // First write data into ~/.multirust + run_no_home(config, &["default", "stable"], + &[("RUSTUP_HOME", multirust_dir_str)]); + let out = run_no_home(config, &["toolchain", "list"], + &[("RUSTUP_HOME", multirust_dir_str)]); + assert!(String::from_utf8(out.stdout).unwrap().contains("stable")); + + assert!(multirust_dir.exists()); + assert!(!rustup_dir.exists()); + + // This time there are two things that look like rustup.sh. + // Only one can win. It doesn't matter much which. + + // Now add rustup.sh data to ~/.rustup + fs::create_dir_all(&rustup_dir).unwrap(); + raw::write_file(&old_rustup_sh_version_file, "1").unwrap(); + + // Also to ~/.rustup.sh + fs::create_dir_all(&rustup_sh_dir).unwrap(); + raw::write_file(&new_rustup_sh_version_file, "1").unwrap(); + + assert!(old_rustup_sh_version_file.exists()); + assert!(new_rustup_sh_version_file.exists()); + + // Now do the upgrade, and ~/.rustup will be moved to ~/.rustup.sh + let out = run_no_home(config, &["toolchain", "list"], &[]); + assert!(String::from_utf8(out.stdout).unwrap().contains("stable")); + + assert!(!multirust_dir.exists()); + assert!(rustup_dir.exists()); + assert!(!old_rustup_sh_version_file.exists()); + assert!(new_rustup_sh_version_file.exists()); + }); +} From a07ee8c0e3b7634bd0b5725348780c19c82f1446 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 22 Nov 2016 04:30:50 +0000 Subject: [PATCH 2/2] Set up ~/.multirust as a temporary symlink to ~/.rustup --- src/rustup-cli/self_update.rs | 6 ++++ src/rustup-mock/src/clitools.rs | 4 +-- src/rustup-utils/src/utils.rs | 55 ++++++++++++++++++++++++++++++++- tests/cli-rustup.rs | 49 +++++++++++++++++++++-------- tests/cli-self-upd.rs | 38 +++++++++++++++++++++-- 5 files changed, 134 insertions(+), 18 deletions(-) diff --git a/src/rustup-cli/self_update.rs b/src/rustup-cli/self_update.rs index 68135847cdb..00fc26619ea 100644 --- a/src/rustup-cli/self_update.rs +++ b/src/rustup-cli/self_update.rs @@ -228,6 +228,10 @@ pub fn install(no_prompt: bool, verbose: bool, if !opts.no_modify_path { try!(do_add_to_path(&get_add_path_methods())); } + // Create ~/.rustup and a compatibility ~/.multirust symlink. + // FIXME: Someday we can stop setting up the symlink, and when + // we do that we can stop creating ~/.rustup as well. + try!(utils::create_rustup_home()); try!(maybe_install_rust(&opts.default_toolchain, &opts.default_host_triple, verbose)); if cfg!(unix) { @@ -607,6 +611,8 @@ pub fn uninstall(no_prompt: bool) -> Result<()> { info!("removing rustup home"); + try!(utils::delete_legacy_multirust_symlink()); + // Delete RUSTUP_HOME let ref rustup_dir = try!(utils::multirust_home()); if rustup_dir.exists() { diff --git a/src/rustup-mock/src/clitools.rs b/src/rustup-mock/src/clitools.rs index c1790cd0b92..f04417d51ac 100644 --- a/src/rustup-mock/src/clitools.rs +++ b/src/rustup-mock/src/clitools.rs @@ -259,9 +259,9 @@ pub fn env(config: &Config, cmd: &mut Command) { cmd.env("CARGO_HOME", config.cargodir.to_string_lossy().to_string()); cmd.env("RUSTUP_OVERRIDE_HOST_TRIPLE", this_host_triple()); - // This is only used for some installation tests on unix where CARGO_HOME - // above is unset + // These are used in some installation tests that unset RUSTUP_HOME/CARGO_HOME cmd.env("HOME", config.homedir.to_string_lossy().to_string()); + cmd.env("USERPROFILE", config.homedir.to_string_lossy().to_string()); // Setting HOME will confuse the sudo check for rustup-init. Override it cmd.env("RUSTUP_INIT_SKIP_SUDO_CHECK", "yes"); diff --git a/src/rustup-utils/src/utils.rs b/src/rustup-utils/src/utils.rs index 7ae21f2672b..ffbf69164a7 100644 --- a/src/rustup-utils/src/utils.rs +++ b/src/rustup-utils/src/utils.rs @@ -598,10 +598,14 @@ pub fn do_rustup_home_upgrade() -> bool { old_rustup_dir_removed && if multirust_dir_exists() { if rustup_dir_exists() { // There appears to be both a ~/.multirust dir and a valid ~/.rustup - // dir. Weird situation. Pick ~/.rustup. + // dir. Most likely because one is a symlink to the other, as configured + // below. true } else { if rename_multirust_dir_to_rustup().is_ok() { + // Finally, making the hardlink from ~/.multirust back to + // ~/.rustup, for temporary compatibility. + let _ = create_legacy_multirust_symlink(); true } else { false @@ -612,6 +616,51 @@ pub fn do_rustup_home_upgrade() -> bool { } } +// Creates a ~/.rustup folder and a ~/.multirust symlink +pub fn create_rustup_home() -> Result<()> { + // If RUSTUP_HOME is set then don't make any assumptions about where it's + // ok to put ~/.multirust + if env::var_os("RUSTUP_HOME").is_some() { return Ok(()) } + + let home = rustup_home_in_user_dir()?; + fs::create_dir_all(&home) + .chain_err(|| "unable to create ~/.rustup")?; + + // This is a temporary compatibility symlink + create_legacy_multirust_symlink()?; + + Ok(()) +} + +// Create a symlink from ~/.multirust to ~/.rustup to temporarily +// accomodate old tools that are expecting that directory +fn create_legacy_multirust_symlink() -> Result<()> { + let newhome = rustup_home_in_user_dir()?; + let oldhome = legacy_multirust_home()?; + + raw::symlink_dir(&newhome, &oldhome) + .chain_err(|| format!("unable to symlink {} from {}", + newhome.display(), oldhome.display()))?; + + Ok(()) +} + +pub fn delete_legacy_multirust_symlink() -> Result<()> { + let oldhome = legacy_multirust_home()?; + + if oldhome.exists() { + let meta = fs::symlink_metadata(&oldhome) + .chain_err(|| "unable to get metadata for ~/.multirust")?; + if meta.file_type().is_symlink() { + // remove_dir handles unlinking symlinks + raw::remove_dir(&oldhome) + .chain_err(|| format!("unable to delete legacy symlink {}", oldhome.display()))?; + } + } + + Ok(()) +} + fn dot_dir(name: &str) -> Option { home_dir().map(|p| p.join(name)) } @@ -620,6 +669,10 @@ pub fn legacy_multirust_home() -> Result { dot_dir(".multirust").ok_or(ErrorKind::MultirustHome.into()) } +pub fn rustup_home_in_user_dir() -> Result { + dot_dir(".rustup").ok_or(ErrorKind::MultirustHome.into()) +} + pub fn multirust_home() -> Result { let use_rustup_dir = do_rustup_home_upgrade(); diff --git a/tests/cli-rustup.rs b/tests/cli-rustup.rs index 699ffb1c32c..4679cc7dde5 100644 --- a/tests/cli-rustup.rs +++ b/tests/cli-rustup.rs @@ -589,7 +589,7 @@ fn remove_component() { // Run without setting RUSTUP_HOME, with setting HOME and USERPROFILE fn run_no_home(config: &Config, args: &[&str], env: &[(&str, &str)]) -> process::Output { let home_dir_str = &format!("{}", config.homedir.display()); - let mut cmd = clitools::cmd(config, "rustup", args); + let mut cmd = clitools::cmd(config, args[0], &args[1..]); clitools::env(config, &mut cmd); cmd.env_remove("RUSTUP_HOME"); cmd.env("HOME", home_dir_str); @@ -612,9 +612,9 @@ fn multirust_dir_upgrade_rename_multirust_dir_to_rustup() { let multirust_dir_str = &format!("{}", multirust_dir.display()); // First write data into ~/.multirust - run_no_home(config, &["default", "stable"], + run_no_home(config, &["rustup", "default", "stable"], &[("RUSTUP_HOME", multirust_dir_str)]); - let out = run_no_home(config, &["toolchain", "list"], + let out = run_no_home(config, &["rustup", "toolchain", "list"], &[("RUSTUP_HOME", multirust_dir_str)]); assert!(String::from_utf8(out.stdout).unwrap().contains("stable")); @@ -624,10 +624,11 @@ fn multirust_dir_upgrade_rename_multirust_dir_to_rustup() { // Next run without RUSTUP_DIR, but with HOME/USERPROFILE set so rustup // can infer RUSTUP_DIR. It will silently move ~/.multirust to // ~/.rustup. - let out = run_no_home(config, &["toolchain", "list"], &[]); + let out = run_no_home(config, &["rustup", "toolchain", "list"], &[]); assert!(String::from_utf8(out.stdout).unwrap().contains("stable")); - assert!(!multirust_dir.exists()); + assert!(multirust_dir.exists()); + assert!(fs::symlink_metadata(&multirust_dir).unwrap().file_type().is_symlink()); assert!(rustup_dir.exists()); }); } @@ -645,9 +646,9 @@ fn multirust_dir_upgrade_old_rustup_exists() { let new_rustup_sh_version_file = rustup_sh_dir.join("rustup-version"); // First write data into ~/.multirust - run_no_home(config, &["default", "stable"], + run_no_home(config, &["rustup", "default", "stable"], &[("RUSTUP_HOME", multirust_dir_str)]); - let out = run_no_home(config, &["toolchain", "list"], + let out = run_no_home(config, &["rustup", "toolchain", "list"], &[("RUSTUP_HOME", multirust_dir_str)]); assert!(String::from_utf8(out.stdout).unwrap().contains("stable")); @@ -660,10 +661,11 @@ fn multirust_dir_upgrade_old_rustup_exists() { assert!(old_rustup_sh_version_file.exists()); // Now do the upgrade, and ~/.rustup will be moved to ~/.rustup.sh - let out = run_no_home(config, &["toolchain", "list"], &[]); + let out = run_no_home(config, &["rustup", "toolchain", "list"], &[]); assert!(String::from_utf8(out.stdout).unwrap().contains("stable")); - assert!(!multirust_dir.exists()); + assert!(multirust_dir.exists()); + assert!(fs::symlink_metadata(&multirust_dir).unwrap().file_type().is_symlink()); assert!(rustup_dir.exists()); assert!(!old_rustup_sh_version_file.exists()); assert!(new_rustup_sh_version_file.exists()); @@ -684,9 +686,9 @@ fn multirust_dir_upgrade_old_rustup_existsand_new_rustup_sh_exists() { let new_rustup_sh_version_file = rustup_sh_dir.join("rustup-version"); // First write data into ~/.multirust - run_no_home(config, &["default", "stable"], + run_no_home(config, &["rustup", "default", "stable"], &[("RUSTUP_HOME", multirust_dir_str)]); - let out = run_no_home(config, &["toolchain", "list"], + let out = run_no_home(config, &["rustup", "toolchain", "list"], &[("RUSTUP_HOME", multirust_dir_str)]); assert!(String::from_utf8(out.stdout).unwrap().contains("stable")); @@ -708,12 +710,33 @@ fn multirust_dir_upgrade_old_rustup_existsand_new_rustup_sh_exists() { assert!(new_rustup_sh_version_file.exists()); // Now do the upgrade, and ~/.rustup will be moved to ~/.rustup.sh - let out = run_no_home(config, &["toolchain", "list"], &[]); + let out = run_no_home(config, &["rustup", "toolchain", "list"], &[]); assert!(String::from_utf8(out.stdout).unwrap().contains("stable")); - assert!(!multirust_dir.exists()); + // .multirust is now a symlink to .rustup + assert!(multirust_dir.exists()); + assert!(fs::symlink_metadata(&multirust_dir).unwrap().file_type().is_symlink()); + assert!(rustup_dir.exists()); assert!(!old_rustup_sh_version_file.exists()); assert!(new_rustup_sh_version_file.exists()); }); } + +#[test] +fn multirust_upgrade_works_with_proxy() { + setup(&|config| { + let multirust_dir = config.homedir.join(".multirust"); + let rustup_dir = config.homedir.join(".rustup"); + + // Put data in ~/.multirust + run_no_home(config, &["rustup", "default", "stable"], + &[("RUSTUP_HOME", &format!("{}", multirust_dir.display()))]); + + run_no_home(config, &["rustc", "--version"], &[]); + + assert!(multirust_dir.exists()); + assert!(fs::symlink_metadata(&multirust_dir).unwrap().file_type().is_symlink()); + assert!(rustup_dir.exists()); + }); +} diff --git a/tests/cli-self-upd.rs b/tests/cli-self-upd.rs index 13e4556c194..e3013cff072 100644 --- a/tests/cli-self-upd.rs +++ b/tests/cli-self-upd.rs @@ -802,9 +802,9 @@ fn install_sets_up_stable_unless_there_is_already_a_default() { #[cfg(unix)] fn install_deletes_legacy_multirust_bins() { setup(&|config| { - let ref multirust_bin_dir = config.rustupdir.join("bin"); + let ref multirust_bin_dir = config.homedir.join(".multirust/bin"); fs::create_dir_all(multirust_bin_dir).unwrap(); - let ref multirust_bin = multirust_bin_dir.join("rustup"); + let ref multirust_bin = multirust_bin_dir.join("multirust"); let ref rustc_bin = multirust_bin_dir.join("rustc"); raw::write_file(multirust_bin, "").unwrap(); raw::write_file(rustc_bin, "").unwrap(); @@ -1076,3 +1076,37 @@ fn legacy_upgrade_removes_multirust_bin() { assert!(!multirust_bin.exists()); }); } + +// Create a ~/.multirust symlink to ~/.rustup +#[test] +fn install_creates_legacy_home_symlink() { + setup(&|config| { + let mut cmd = clitools::cmd(config, "rustup-init", &["-y"]); + // It'll only do this behavior when RUSTUP_HOME isn't set + cmd.env_remove("RUSTUP_HOME"); + + assert!(cmd.output().unwrap().status.success()); + + let rustup_dir = config.homedir.join(".rustup"); + assert!(rustup_dir.exists()); + let multirust_dir = config.homedir.join(".multirust"); + assert!(multirust_dir.exists()); + assert!(fs::symlink_metadata(&multirust_dir).unwrap().file_type().is_symlink()); + }); +} + +#[test] +fn uninstall_removes_legacy_home_symlink() { + setup(&|config| { + let mut cmd = clitools::cmd(config, "rustup-init", &["-y"]); + // It'll only do this behavior when RUSTUP_HOME isn't set + cmd.env_remove("RUSTUP_HOME"); + assert!(cmd.output().unwrap().status.success()); + + let multirust_dir = config.homedir.join(".multirust"); + assert!(multirust_dir.exists()); + + expect_ok(config, &["rustup", "self", "uninstall", "-y"]); + assert!(!multirust_dir.exists()); + }); +}