@@ -16,8 +16,11 @@ use std::{
1616
1717use enum_map:: { enum_map, Enum , EnumMap } ;
1818use once_cell:: sync:: Lazy ;
19+ use tokio:: runtime:: Builder ;
1920use url:: Url ;
2021
22+ use crate :: cli:: rustup_mode;
23+ use crate :: currentprocess;
2124use crate :: test as rustup_test;
2225use crate :: test:: const_dist_dir;
2326use crate :: test:: this_host_triple;
@@ -676,8 +679,13 @@ impl Config {
676679 I : IntoIterator < Item = A > + Clone + Debug ,
677680 A : AsRef < OsStr > ,
678681 {
682+ let inprocess = allow_inprocess ( name, args. clone ( ) ) ;
679683 let start = Instant :: now ( ) ;
680- let out = self . run_subprocess ( name, args. clone ( ) , env) ;
684+ let out = if inprocess {
685+ self . run_inprocess ( name, args. clone ( ) , env)
686+ } else {
687+ self . run_subprocess ( name, args. clone ( ) , env)
688+ } ;
681689 let duration = Instant :: now ( ) - start;
682690 let output = SanitizedOutput {
683691 ok : matches ! ( out. status, Some ( 0 ) ) ,
@@ -686,6 +694,7 @@ impl Config {
686694 } ;
687695
688696 println ! ( "ran: {} {:?}" , name, args) ;
697+ println ! ( "inprocess: {inprocess}" ) ;
689698 println ! ( "status: {:?}" , out. status) ;
690699 println ! ( "duration: {:.3}s" , duration. as_secs_f32( ) ) ;
691700 println ! ( "stdout:\n ====\n {}\n ====\n " , output. stdout) ;
@@ -694,6 +703,55 @@ impl Config {
694703 output
695704 }
696705
706+ #[ cfg_attr( feature = "otel" , tracing:: instrument( skip_all) ) ]
707+ pub ( crate ) fn run_inprocess < I , A > ( & self , name : & str , args : I , env : & [ ( & str , & str ) ] ) -> Output
708+ where
709+ I : IntoIterator < Item = A > ,
710+ A : AsRef < OsStr > ,
711+ {
712+ // should we use vars_os, or skip over non-stringable vars? This is test
713+ // code after all...
714+ let mut vars: HashMap < String , String > = HashMap :: default ( ) ;
715+ self :: env ( self , & mut vars) ;
716+ vars. extend ( env. iter ( ) . map ( |( k, v) | ( k. to_string ( ) , v. to_string ( ) ) ) ) ;
717+ let mut arg_strings: Vec < Box < str > > = Vec :: new ( ) ;
718+ arg_strings. push ( name. to_owned ( ) . into_boxed_str ( ) ) ;
719+ for arg in args {
720+ arg_strings. push (
721+ arg. as_ref ( )
722+ . to_os_string ( )
723+ . into_string ( )
724+ . unwrap ( )
725+ . into_boxed_str ( ) ,
726+ ) ;
727+ }
728+ let mut builder = Builder :: new_multi_thread ( ) ;
729+ builder
730+ . enable_all ( )
731+ . worker_threads ( 2 )
732+ . max_blocking_threads ( 2 ) ;
733+ let rt = builder. build ( ) . unwrap ( ) ;
734+ rt. block_on ( async {
735+ let tp =
736+ currentprocess:: TestProcess :: new ( & * self . workdir . borrow ( ) , & arg_strings, vars, "" ) ;
737+ let process_res =
738+ rustup_mode:: main ( tp. process . current_dir ( ) . unwrap ( ) , & tp. process ) . await ;
739+ // convert Err's into an ec
740+ let ec = match process_res {
741+ Ok ( process_res) => process_res,
742+ Err ( e) => {
743+ crate :: cli:: common:: report_error ( & e, & tp. process ) ;
744+ utils:: ExitCode ( 1 )
745+ }
746+ } ;
747+ Output {
748+ status : Some ( ec. 0 ) ,
749+ stderr : tp. stderr ( ) ,
750+ stdout : tp. stdout ( ) ,
751+ }
752+ } )
753+ }
754+
697755 #[ track_caller]
698756 pub fn run_subprocess < I , A > ( & self , name : & str , args : I , env : & [ ( & str , & str ) ] ) -> Output
699757 where
@@ -797,6 +855,43 @@ pub fn env<E: rustup_test::Env>(config: &Config, cmd: &mut E) {
797855 config. env ( cmd)
798856}
799857
858+ fn allow_inprocess < I , A > ( name : & str , args : I ) -> bool
859+ where
860+ I : IntoIterator < Item = A > ,
861+ A : AsRef < OsStr > ,
862+ {
863+ // Only the rustup alias is currently ready for in-process testing:
864+ // - -init performs self-update which monkey with global external state.
865+ // - proxies themselves behave appropriately the proxied output needs to be
866+ // collected for assertions to be made on it as our tests traverse layers.
867+ // - self update executions cannot run in-process because on windows the
868+ // process replacement dance would replace the test process.
869+ // - any command with --version in it is testing to see something was
870+ // installed properly, so we have to shell out to it to be sure
871+ if name != "rustup" {
872+ return false ;
873+ }
874+ let mut is_update = false ;
875+ let mut no_self_update = false ;
876+ let mut self_cmd = false ;
877+ let mut run = false ;
878+ let mut version = false ;
879+ for arg in args {
880+ if arg. as_ref ( ) == "update" {
881+ is_update = true ;
882+ } else if arg. as_ref ( ) == "--no-self-update" {
883+ no_self_update = true ;
884+ } else if arg. as_ref ( ) == "self" {
885+ self_cmd = true ;
886+ } else if arg. as_ref ( ) == "run" {
887+ run = true ;
888+ } else if arg. as_ref ( ) == "--version" {
889+ version = true ;
890+ }
891+ }
892+ !( run || self_cmd || version || ( is_update && !no_self_update) )
893+ }
894+
800895#[ derive( Copy , Clone , Eq , PartialEq ) ]
801896enum RlsStatus {
802897 Available ,
0 commit comments