@@ -31,6 +31,7 @@ use std::env;
31
31
use std:: ffi:: OsString ;
32
32
use std:: fmt;
33
33
use std:: fs;
34
+ use std:: iter;
34
35
use std:: io:: { self , Read , Write } ;
35
36
use std:: path:: { Path , PathBuf } ;
36
37
use std:: process:: { self , Command , Stdio } ;
@@ -309,19 +310,16 @@ impl DownloadParams {
309
310
if cfg. args. alt { "-alt" } else { "" }
310
311
) ;
311
312
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)
320
314
}
321
315
322
316
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 {
323
321
DownloadParams {
324
- url_prefix : NIGHTLY_SERVER . to_string ( ) ,
322
+ url_prefix : url_prefix ,
325
323
tmp_dir : cfg. rustup_tmp_path . clone ( ) ,
326
324
install_dir : cfg. toolchains_path . clone ( ) ,
327
325
install_cargo : cfg. args . with_cargo ,
@@ -450,6 +448,8 @@ enum InstallError {
450
448
TempDir ( #[ cause] io:: Error ) ,
451
449
#[ fail( display = "Could not move tempdir into destination: {}" , _0) ]
452
450
Move ( #[ cause] io:: Error ) ,
451
+ #[ fail( display = "Could not run subcommand {}: {}" , command, cause) ]
452
+ Subcommand { command : String , #[ cause] cause : io:: Error }
453
453
}
454
454
455
455
#[ derive( Debug ) ]
@@ -702,11 +702,6 @@ impl Toolchain {
702
702
}
703
703
704
704
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
-
710
705
debug ! ( "installing {}" , self ) ;
711
706
let tmpdir = TempDir :: new_in ( & dl_params. tmp_dir , & self . rustup_name ( ) )
712
707
. map_err ( InstallError :: TempDir ) ?;
@@ -720,6 +715,40 @@ impl Toolchain {
720
715
return Ok ( ( ) ) ;
721
716
}
722
717
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
+
723
752
let rustc_filename = format ! ( "rustc-nightly-{}" , self . host) ;
724
753
725
754
let location = match self . spec {
@@ -794,6 +823,46 @@ impl Toolchain {
794
823
}
795
824
}
796
825
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
+
797
866
struct Config {
798
867
args : Opts ,
799
868
rustup_tmp_path : PathBuf ,
0 commit comments