Skip to content

Commit 1a8a35e

Browse files
committed
Add RustupEnvironmentBuilder
1 parent 11a708b commit 1a8a35e

File tree

1 file changed

+112
-79
lines changed

1 file changed

+112
-79
lines changed

tests/testsuite/rustup.rs

Lines changed: 112 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
//! Tests for Cargo's behavior under Rustup.
22
3+
use std::collections::BTreeMap;
34
use std::env;
45
use std::env::consts::EXE_EXTENSION;
56
use std::ffi::OsString;
7+
use std::fmt::Write;
68
use std::fs;
79
use 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

Comments
 (0)