@@ -31,6 +31,7 @@ use std::env;
3131use std:: ffi:: OsString ;
3232use std:: fmt;
3333use std:: fs;
34+ use std:: iter;
3435use std:: io:: { self , Read , Write } ;
3536use std:: path:: { Path , PathBuf } ;
3637use std:: process:: { self , Command , Stdio } ;
@@ -309,19 +310,16 @@ impl DownloadParams {
309310 if cfg. args. alt { "-alt" } else { "" }
310311 ) ;
311312
312- DownloadParams {
313- url_prefix : url_prefix,
314- tmp_dir : cfg. rustup_tmp_path . clone ( ) ,
315- install_dir : cfg. toolchains_path . clone ( ) ,
316- install_cargo : cfg. args . with_cargo ,
317- install_src : cfg. args . with_src ,
318- force_install : cfg. args . force_install ,
319- }
313+ Self :: from_cfg_with_url_prefix ( cfg, url_prefix)
320314 }
321315
322316 fn for_nightly ( cfg : & Config ) -> Self {
317+ Self :: from_cfg_with_url_prefix ( cfg, NIGHTLY_SERVER . to_string ( ) )
318+ }
319+
320+ fn from_cfg_with_url_prefix ( cfg : & Config , url_prefix : String ) -> Self {
323321 DownloadParams {
324- url_prefix : NIGHTLY_SERVER . to_string ( ) ,
322+ url_prefix : url_prefix ,
325323 tmp_dir : cfg. rustup_tmp_path . clone ( ) ,
326324 install_dir : cfg. toolchains_path . clone ( ) ,
327325 install_cargo : cfg. args . with_cargo ,
@@ -450,6 +448,8 @@ enum InstallError {
450448 TempDir ( #[ cause] io:: Error ) ,
451449 #[ fail( display = "Could not move tempdir into destination: {}" , _0) ]
452450 Move ( #[ cause] io:: Error ) ,
451+ #[ fail( display = "Could not run subcommand {}: {}" , command, cause) ]
452+ Subcommand { command : String , #[ cause] cause : io:: Error }
453453}
454454
455455#[ derive( Debug ) ]
@@ -702,11 +702,6 @@ impl Toolchain {
702702 }
703703
704704 fn install ( & self , client : & Client , dl_params : & DownloadParams ) -> Result < ( ) , InstallError > {
705- if self . is_current_nightly ( ) {
706- // pre existing installation
707- return Ok ( ( ) ) ;
708- }
709-
710705 debug ! ( "installing {}" , self ) ;
711706 let tmpdir = TempDir :: new_in ( & dl_params. tmp_dir , & self . rustup_name ( ) )
712707 . map_err ( InstallError :: TempDir ) ?;
@@ -720,6 +715,40 @@ impl Toolchain {
720715 return Ok ( ( ) ) ;
721716 }
722717
718+ if self . is_current_nightly ( ) {
719+ // make link to pre-existing installation
720+ debug ! ( "installing (via link) {}" , self ) ;
721+
722+ let nightly_path: String = {
723+ let cmd = CommandTemplate :: new ( [ "rustc" , "--print" , "sysroot" ]
724+ . iter ( )
725+ . map ( |s| s. to_string ( ) ) ) ;
726+ let stdout = cmd. output ( ) ?. stdout ;
727+ let output = String :: from_utf8_lossy ( & stdout) ;
728+ // the output should be the path, terminated by a newline
729+ let mut path = output. to_string ( ) ;
730+ let last = path. pop ( ) ;
731+ assert_eq ! ( last, Some ( '\n' ) ) ;
732+ path
733+ } ;
734+
735+ let cmd = CommandTemplate :: new ( [ "rustup" , "toolchain" , "link" ]
736+ . iter ( )
737+ . map ( |s| s. to_string ( ) )
738+ . chain ( iter:: once ( self . rustup_name ( ) ) )
739+ . chain ( iter:: once ( nightly_path) ) ) ;
740+ if cmd. status ( ) ?. success ( ) {
741+ return Ok ( ( ) ) ;
742+ } else {
743+ return Err ( InstallError :: Subcommand {
744+ command : cmd. string ( ) ,
745+ cause : io:: Error :: new ( io:: ErrorKind :: Other , "failed to link via `rustup`" ) ,
746+ } ) ;
747+ }
748+ }
749+
750+ debug ! ( "installing via download {}" , self ) ;
751+
723752 let rustc_filename = format ! ( "rustc-nightly-{}" , self . host) ;
724753
725754 let location = match self . spec {
@@ -794,6 +823,46 @@ impl Toolchain {
794823 }
795824}
796825
826+ // A simpler wrapper struct to make up for impoverished `Command` in libstd.
827+ struct CommandTemplate ( Vec < String > ) ;
828+
829+ impl CommandTemplate {
830+ fn new ( strings : impl Iterator < Item =String > ) -> Self {
831+ CommandTemplate ( strings. collect ( ) )
832+ }
833+
834+ fn command ( & self ) -> Command {
835+ assert ! ( self . 0 . len( ) > 0 ) ;
836+ let mut cmd = Command :: new ( & self . 0 [ 0 ] ) ;
837+ for arg in & self . 0 [ 1 ..] {
838+ cmd. arg ( arg) ;
839+ }
840+ cmd
841+ }
842+
843+ fn string ( & self ) -> String {
844+ assert ! ( self . 0 . len( ) > 0 ) ;
845+ let mut s = self . 0 [ 0 ] . to_string ( ) ;
846+ for arg in & self . 0 [ 1 ..] {
847+ s. push_str ( " " ) ;
848+ s. push_str ( arg) ;
849+ }
850+ s
851+ }
852+
853+ fn status ( & self ) -> Result < process:: ExitStatus , InstallError > {
854+ self . command ( ) . status ( ) . map_err ( |cause| {
855+ InstallError :: Subcommand { command : self . string ( ) , cause }
856+ } )
857+ }
858+
859+ fn output ( & self ) -> Result < process:: Output , InstallError > {
860+ self . command ( ) . output ( ) . map_err ( |cause| {
861+ InstallError :: Subcommand { command : self . string ( ) , cause }
862+ } )
863+ }
864+ }
865+
797866struct Config {
798867 args : Opts ,
799868 rustup_tmp_path : PathBuf ,
0 commit comments