Skip to content

Commit 26d2dcc

Browse files
committed
Auto merge of #830 - brson:rustup-dir, r=brson
Rename ~/.multirust to ~/.rustup This renames the ~/.multirust directory to ~/.rustup. The logic for the upgrade is in `do_rustup_home_upgrade`, and is defensive against errors. It amounts to moving an unrecognized `~/.rustup` folder to `~/.rustup.sh`, then moving a `~/.multirust` dir to `~/.rustup`. If the upgrade fails then rustup will silently continue using `~/.multirust`, though this code path doesn't have tests, and is unlikely to happen... After the upgrade, or during initial install this also sets up `~/.multirust` as a symlink to `~/.rustup` in case there are tools depending on it. This is intended to be temporary, to avoid breakage while getting it done quickly. This needs some more manual testing before deployment but is ready for review. r? @alexcrichton
2 parents f6cd385 + a07ee8c commit 26d2dcc

File tree

5 files changed

+385
-6
lines changed

5 files changed

+385
-6
lines changed

src/rustup-cli/self_update.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,10 @@ pub fn install(no_prompt: bool, verbose: bool,
228228
if !opts.no_modify_path {
229229
try!(do_add_to_path(&get_add_path_methods()));
230230
}
231+
// Create ~/.rustup and a compatibility ~/.multirust symlink.
232+
// FIXME: Someday we can stop setting up the symlink, and when
233+
// we do that we can stop creating ~/.rustup as well.
234+
try!(utils::create_rustup_home());
231235
try!(maybe_install_rust(&opts.default_toolchain, &opts.default_host_triple, verbose));
232236

233237
if cfg!(unix) {
@@ -508,7 +512,7 @@ fn cleanup_legacy() -> Result<()> {
508512

509513
#[cfg(unix)]
510514
fn legacy_multirust_home_dir() -> Result<PathBuf> {
511-
Ok(try!(utils::multirust_home()))
515+
Ok(try!(utils::legacy_multirust_home()))
512516
}
513517

514518
#[cfg(windows)]
@@ -607,6 +611,8 @@ pub fn uninstall(no_prompt: bool) -> Result<()> {
607611

608612
info!("removing rustup home");
609613

614+
try!(utils::delete_legacy_multirust_symlink());
615+
610616
// Delete RUSTUP_HOME
611617
let ref rustup_dir = try!(utils::multirust_home());
612618
if rustup_dir.exists() {

src/rustup-mock/src/clitools.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,9 @@ pub fn env(config: &Config, cmd: &mut Command) {
259259
cmd.env("CARGO_HOME", config.cargodir.to_string_lossy().to_string());
260260
cmd.env("RUSTUP_OVERRIDE_HOST_TRIPLE", this_host_triple());
261261

262-
// This is only used for some installation tests on unix where CARGO_HOME
263-
// above is unset
262+
// These are used in some installation tests that unset RUSTUP_HOME/CARGO_HOME
264263
cmd.env("HOME", config.homedir.to_string_lossy().to_string());
264+
cmd.env("USERPROFILE", config.homedir.to_string_lossy().to_string());
265265

266266
// Setting HOME will confuse the sudo check for rustup-init. Override it
267267
cmd.env("RUSTUP_INIT_SKIP_SUDO_CHECK", "yes");

src/rustup-utils/src/utils.rs

Lines changed: 183 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,12 +497,194 @@ pub fn cargo_home() -> Result<PathBuf> {
497497
cargo_home.or(user_home).ok_or(ErrorKind::CargoHome.into())
498498
}
499499

500+
// Convert the ~/.multirust folder to ~/.rustup while dealing with rustup.sh
501+
// metadata, which used to also live in ~/.rustup, but now lives in ~/rustup.sh.
502+
pub fn do_rustup_home_upgrade() -> bool {
503+
504+
fn rustup_home_is_set() -> bool {
505+
env::var_os("RUSTUP_HOME").is_some()
506+
}
507+
508+
fn rustup_dir() -> Option<PathBuf> {
509+
dot_dir(".rustup")
510+
}
511+
512+
fn rustup_sh_dir() -> Option<PathBuf> {
513+
dot_dir(".rustup.sh")
514+
}
515+
516+
fn multirust_dir() -> Option<PathBuf> {
517+
dot_dir(".multirust")
518+
}
519+
520+
fn rustup_dir_exists() -> bool {
521+
rustup_dir().map(|p| p.exists()).unwrap_or(false)
522+
}
523+
524+
fn rustup_sh_dir_exists() -> bool {
525+
rustup_sh_dir().map(|p| p.exists()).unwrap_or(false)
526+
}
527+
528+
fn multirust_dir_exists() -> bool {
529+
multirust_dir().map(|p| p.exists()).unwrap_or(false)
530+
}
531+
532+
fn rustup_old_version_exists() -> bool {
533+
rustup_dir()
534+
.map(|p| p.join("rustup-version").exists())
535+
.unwrap_or(false)
536+
}
537+
538+
fn delete_rustup_dir() -> Result<()> {
539+
if let Some(dir) = rustup_dir() {
540+
raw::remove_dir(&dir)
541+
.chain_err(|| "unable to delete rustup dir")?;
542+
}
543+
544+
Ok(())
545+
}
546+
547+
fn rename_rustup_dir_to_rustup_sh() -> Result<()> {
548+
let dirs = (rustup_dir(), rustup_sh_dir());
549+
if let (Some(rustup), Some(rustup_sh)) = dirs {
550+
fs::rename(&rustup, &rustup_sh)
551+
.chain_err(|| "unable to rename rustup dir")?;
552+
}
553+
554+
Ok(())
555+
}
556+
557+
fn rename_multirust_dir_to_rustup() -> Result<()> {
558+
let dirs = (multirust_dir(), rustup_dir());
559+
if let (Some(rustup), Some(rustup_sh)) = dirs {
560+
fs::rename(&rustup, &rustup_sh)
561+
.chain_err(|| "unable to rename multirust dir")?;
562+
}
563+
564+
Ok(())
565+
}
566+
567+
// If RUSTUP_HOME is set then its default path doesn't matter, so we're
568+
// not going to risk doing any I/O work and making a mess.
569+
if rustup_home_is_set() { return true }
570+
571+
// Now we are just trying to get a bogus, rustup.sh-created ~/.rustup out
572+
// of the way in the manner that is least likely to take time and generate
573+
// errors. First try to rename it to ~/.rustup.sh, then try to delete it.
574+
// If that doesn't work we can't use the ~/.rustup name.
575+
let old_rustup_dir_removed = if rustup_old_version_exists() {
576+
if !rustup_sh_dir_exists() {
577+
if rename_rustup_dir_to_rustup_sh().is_ok() {
578+
true
579+
} else {
580+
if delete_rustup_dir().is_ok() {
581+
true
582+
} else {
583+
false
584+
}
585+
}
586+
} else {
587+
if delete_rustup_dir().is_ok() {
588+
true
589+
} else {
590+
false
591+
}
592+
}
593+
} else {
594+
true
595+
};
596+
597+
// Now we're trying to move ~/.multirust to ~/.rustup
598+
old_rustup_dir_removed && if multirust_dir_exists() {
599+
if rustup_dir_exists() {
600+
// There appears to be both a ~/.multirust dir and a valid ~/.rustup
601+
// dir. Most likely because one is a symlink to the other, as configured
602+
// below.
603+
true
604+
} else {
605+
if rename_multirust_dir_to_rustup().is_ok() {
606+
// Finally, making the hardlink from ~/.multirust back to
607+
// ~/.rustup, for temporary compatibility.
608+
let _ = create_legacy_multirust_symlink();
609+
true
610+
} else {
611+
false
612+
}
613+
}
614+
} else {
615+
true
616+
}
617+
}
618+
619+
// Creates a ~/.rustup folder and a ~/.multirust symlink
620+
pub fn create_rustup_home() -> Result<()> {
621+
// If RUSTUP_HOME is set then don't make any assumptions about where it's
622+
// ok to put ~/.multirust
623+
if env::var_os("RUSTUP_HOME").is_some() { return Ok(()) }
624+
625+
let home = rustup_home_in_user_dir()?;
626+
fs::create_dir_all(&home)
627+
.chain_err(|| "unable to create ~/.rustup")?;
628+
629+
// This is a temporary compatibility symlink
630+
create_legacy_multirust_symlink()?;
631+
632+
Ok(())
633+
}
634+
635+
// Create a symlink from ~/.multirust to ~/.rustup to temporarily
636+
// accomodate old tools that are expecting that directory
637+
fn create_legacy_multirust_symlink() -> Result<()> {
638+
let newhome = rustup_home_in_user_dir()?;
639+
let oldhome = legacy_multirust_home()?;
640+
641+
raw::symlink_dir(&newhome, &oldhome)
642+
.chain_err(|| format!("unable to symlink {} from {}",
643+
newhome.display(), oldhome.display()))?;
644+
645+
Ok(())
646+
}
647+
648+
pub fn delete_legacy_multirust_symlink() -> Result<()> {
649+
let oldhome = legacy_multirust_home()?;
650+
651+
if oldhome.exists() {
652+
let meta = fs::symlink_metadata(&oldhome)
653+
.chain_err(|| "unable to get metadata for ~/.multirust")?;
654+
if meta.file_type().is_symlink() {
655+
// remove_dir handles unlinking symlinks
656+
raw::remove_dir(&oldhome)
657+
.chain_err(|| format!("unable to delete legacy symlink {}", oldhome.display()))?;
658+
}
659+
}
660+
661+
Ok(())
662+
}
663+
664+
fn dot_dir(name: &str) -> Option<PathBuf> {
665+
home_dir().map(|p| p.join(name))
666+
}
667+
668+
pub fn legacy_multirust_home() -> Result<PathBuf> {
669+
dot_dir(".multirust").ok_or(ErrorKind::MultirustHome.into())
670+
}
671+
672+
pub fn rustup_home_in_user_dir() -> Result<PathBuf> {
673+
dot_dir(".rustup").ok_or(ErrorKind::MultirustHome.into())
674+
}
675+
500676
pub fn multirust_home() -> Result<PathBuf> {
677+
let use_rustup_dir = do_rustup_home_upgrade();
678+
501679
let cwd = try!(env::current_dir().chain_err(|| ErrorKind::MultirustHome));
502680
let multirust_home = env::var_os("RUSTUP_HOME").map(|home| {
503681
cwd.join(home)
504682
});
505-
let user_home = home_dir().map(|p| p.join(".multirust"));
683+
let user_home = if use_rustup_dir {
684+
dot_dir(".rustup")
685+
} else {
686+
dot_dir(".multirust")
687+
};
506688
multirust_home.or(user_home).ok_or(ErrorKind::MultirustHome.into())
507689
}
508690

0 commit comments

Comments
 (0)