11//! Tests for Cargo's behavior under Rustup.
22
3+ use std:: collections:: BTreeMap ;
34use std:: env;
45use std:: env:: consts:: EXE_EXTENSION ;
56use std:: ffi:: OsString ;
7+ use std:: fmt:: Write ;
68use std:: fs;
79use std:: path:: { Path , PathBuf } ;
810
@@ -77,84 +79,115 @@ fn real_rustc_wrapper(bin_dir: &Path, message: &str) -> PathBuf {
7779 )
7880}
7981
80- /// Creates a simulation of a rustup environment with `~/.cargo/bin` and
81- /// `~/.rustup` directories populated with some executables that simulate
82- /// rustup.
82+ /// A builder for a simulated rustup environment.
8383///
84- /// Arguments
85- ///
86- /// - `proxy_calls_cargo`: if true, the cargo proxy calls the cargo under test;
87- /// otherwise, the cargo proxy calls an executable that panics immediately
88- /// - `env_setup`: environment variable setup the proxy should perform
89- fn simulated_rustup_environment ( proxy_calls_cargo : bool , env_setup : & str ) -> RustupEnvironment {
90- // Set up ~/.rustup/toolchains/test-toolchain/bin with a custom rustc and cargo.
91- let rustup_home = home ( ) . join ( ".rustup" ) ;
92- let toolchain_bin = rustup_home
93- . join ( "toolchains" )
94- . join ( "test-toolchain" )
95- . join ( "bin" ) ;
96- toolchain_bin. mkdir_p ( ) ;
97- let rustc_toolchain_exe = real_rustc_wrapper ( & toolchain_bin, "real rustc running" ) ;
98- let cargo_toolchain_exe = if proxy_calls_cargo {
99- crate :: utils:: cargo_exe ( )
100- } else {
101- make_exe (
102- & toolchain_bin,
103- "cargo" ,
104- r#"panic!("cargo toolchain should not be called");"# ,
105- & [ ] ,
106- )
107- } ;
84+ /// The environment has `~/.cargo/bin` and `~/.rustup` directories populated
85+ /// with some executables that simulate rustup.
86+ struct RustupEnvironmentBuilder {
87+ /// Whether the cargo proxy should call the cargo under test. By default,
88+ /// the proxy calls an executable that panics immediately.
89+ proxy_calls_cargo : bool ,
90+ /// Environment variable setup the proxy should perform.
91+ env : BTreeMap < String , String > ,
92+ }
10893
109- // Set up ~/.cargo/bin with a typical set of rustup proxies.
110- let cargo_bin = home ( ) . join ( ".cargo" ) . join ( "bin" ) ;
111- cargo_bin. mkdir_p ( ) ;
94+ impl RustupEnvironmentBuilder {
95+ /// Creates a new [`RustupEnvironmentBuilder`].
96+ fn new ( ) -> Self {
97+ Self {
98+ proxy_calls_cargo : false ,
99+ env : BTreeMap :: new ( ) ,
100+ }
101+ }
112102
113- let proxy = make_exe (
114- & cargo_bin,
115- "rustc" ,
116- & format ! (
117- r#"
118- let file_stem = std::path::PathBuf::from(std::env::args().next().unwrap())
119- .file_stem()
120- .map(ToOwned::to_owned)
121- .unwrap();
122- let program = match file_stem.to_str().unwrap() {{
123- "cargo" => env!("CARGO_RUSTUP_TEST_cargo_toolchain_exe"),
124- "rustc" => env!("CARGO_RUSTUP_TEST_rustc_toolchain_exe"),
125- arg => panic!("proxy only supports cargo and rustc, got {{arg:?}}"),
126- }};
127- eprintln!("`{{program}}` proxy running");
128- let r = std::process::Command::new(program)
129- .args(std::env::args_os().skip(1))
130- {env_setup}
131- .status();
132- std::process::exit(r.unwrap().code().unwrap_or(2));
103+ /// Call the cargo under test rather than an executable that panics
104+ /// immediately.
105+ pub fn call_cargo_under_test ( & mut self ) -> & mut Self {
106+ self . proxy_calls_cargo = true ;
107+ self
108+ }
109+
110+ /// (chainable) Sets an environment variable for the proxy.
111+ pub fn env < T : AsRef < str > > ( & mut self , key : & str , val : T ) -> & mut Self {
112+ self . env . insert ( key. to_string ( ) , val. as_ref ( ) . to_string ( ) ) ;
113+ self
114+ }
115+
116+ pub fn build ( & mut self ) -> RustupEnvironment {
117+ // Set up ~/.rustup/toolchains/test-toolchain/bin with a custom rustc and cargo.
118+ let rustup_home = home ( ) . join ( ".rustup" ) ;
119+ let toolchain_bin = rustup_home
120+ . join ( "toolchains" )
121+ . join ( "test-toolchain" )
122+ . join ( "bin" ) ;
123+ toolchain_bin. mkdir_p ( ) ;
124+ let rustc_toolchain_exe = real_rustc_wrapper ( & toolchain_bin, "real rustc running" ) ;
125+ let cargo_toolchain_exe = if self . proxy_calls_cargo {
126+ crate :: utils:: cargo_exe ( )
127+ } else {
128+ make_exe (
129+ & toolchain_bin,
130+ "cargo" ,
131+ r#"panic!("cargo toolchain should not be called");"# ,
132+ & [ ] ,
133+ )
134+ } ;
135+
136+ // Set up ~/.cargo/bin with a typical set of rustup proxies.
137+ let cargo_bin = home ( ) . join ( ".cargo" ) . join ( "bin" ) ;
138+ cargo_bin. mkdir_p ( ) ;
139+
140+ let mut env_setup = String :: new ( ) ;
141+ for ( k, v) in & self . env {
142+ write ! ( env_setup, ".env(\" {k}\" , \" {v}\" )" ) . unwrap ( ) ;
143+ }
144+
145+ let proxy = make_exe (
146+ & cargo_bin,
147+ "rustc" ,
148+ & format ! (
149+ r#"
150+ let file_stem = std::path::PathBuf::from(std::env::args().next().unwrap())
151+ .file_stem()
152+ .map(ToOwned::to_owned)
153+ .unwrap();
154+ let program = match file_stem.to_str().unwrap() {{
155+ "cargo" => env!("CARGO_RUSTUP_TEST_cargo_toolchain_exe"),
156+ "rustc" => env!("CARGO_RUSTUP_TEST_rustc_toolchain_exe"),
157+ arg => panic!("proxy only supports cargo and rustc, got {{arg:?}}"),
158+ }};
159+ eprintln!("`{{program}}` proxy running");
160+ let r = std::process::Command::new(program)
161+ .args(std::env::args_os().skip(1))
162+ {env_setup}
163+ .status();
164+ std::process::exit(r.unwrap().code().unwrap_or(2));
133165 "#
134- ) ,
135- & [
136- ( "CARGO_RUSTUP_TEST_rustc_toolchain_exe" , rustc_toolchain_exe) ,
137- (
138- "CARGO_RUSTUP_TEST_cargo_toolchain_exe" ,
139- cargo_toolchain_exe. clone ( ) ,
140166 ) ,
141- ] ,
142- ) ;
143- fs:: hard_link (
144- & proxy,
145- cargo_bin. join ( "cargo" ) . with_extension ( EXE_EXTENSION ) ,
146- )
147- . unwrap ( ) ;
148- fs:: hard_link (
149- & proxy,
150- cargo_bin. join ( "rustup" ) . with_extension ( EXE_EXTENSION ) ,
151- )
152- . unwrap ( ) ;
167+ & [
168+ ( "CARGO_RUSTUP_TEST_rustc_toolchain_exe" , rustc_toolchain_exe) ,
169+ (
170+ "CARGO_RUSTUP_TEST_cargo_toolchain_exe" ,
171+ cargo_toolchain_exe. clone ( ) ,
172+ ) ,
173+ ] ,
174+ ) ;
175+ fs:: hard_link (
176+ & proxy,
177+ cargo_bin. join ( "cargo" ) . with_extension ( EXE_EXTENSION ) ,
178+ )
179+ . unwrap ( ) ;
180+ fs:: hard_link (
181+ & proxy,
182+ cargo_bin. join ( "rustup" ) . with_extension ( EXE_EXTENSION ) ,
183+ )
184+ . unwrap ( ) ;
153185
154- RustupEnvironment {
155- cargo_bin,
156- rustup_home,
157- cargo_toolchain_exe,
186+ RustupEnvironment {
187+ cargo_bin,
188+ rustup_home,
189+ cargo_toolchain_exe,
190+ }
158191 }
159192}
160193
@@ -165,7 +198,7 @@ fn typical_rustup() {
165198 cargo_bin,
166199 rustup_home,
167200 cargo_toolchain_exe,
168- } = simulated_rustup_environment ( false , "" ) ;
201+ } = RustupEnvironmentBuilder :: new ( ) . build ( ) ;
169202
170203 // Set up a project and run a normal cargo build.
171204 let p = project ( ) . file ( "src/lib.rs" , "" ) . build ( ) ;
@@ -215,7 +248,7 @@ fn custom_calls_other_cargo() {
215248 cargo_bin,
216249 rustup_home,
217250 cargo_toolchain_exe : _,
218- } = simulated_rustup_environment ( false , "" ) ;
251+ } = RustupEnvironmentBuilder :: new ( ) . build ( ) ;
219252
220253 // Create a directory with a custom toolchain (outside of the rustup universe).
221254 let custom_bin = root ( ) . join ( "custom-bin" ) ;
@@ -283,11 +316,11 @@ fn cargo_install_with_non_default_toolchain() {
283316 cargo_bin,
284317 rustup_home : _,
285318 cargo_toolchain_exe : _,
286- } = simulated_rustup_environment (
287- true ,
288- " .env(\ " RUSTUP_TOOLCHAIN_SOURCE\ " , \ " env\ " )
289- .env(\ " RUSTUP_TOOLCHAIN\ " , \ " test-toolchain\" )" ,
290- ) ;
319+ } = RustupEnvironmentBuilder :: new ( )
320+ . call_cargo_under_test ( )
321+ . env ( "RUSTUP_TOOLCHAIN_SOURCE" , "env" )
322+ . env ( "RUSTUP_TOOLCHAIN" , "test-toolchain" )
323+ . build ( ) ;
291324
292325 pkg ( "foo" , "0.0.1" ) ;
293326
0 commit comments