Skip to content

Commit c945e30

Browse files
committed
setup routine to install xargo when missing
1 parent 6bd76c7 commit c945e30

File tree

1 file changed

+53
-5
lines changed

1 file changed

+53
-5
lines changed

src/bin/cargo-miri.rs

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@
33
extern crate cargo_metadata;
44

55
use std::path::{PathBuf, Path};
6-
use std::io::Write;
6+
use std::io::{self, Write};
77
use std::process::Command;
88

99

1010
const CARGO_MIRI_HELP: &str = r#"Interprets bin crates
1111
1212
Usage:
13-
cargo miri [options] [--] [<opts>...]
13+
cargo miri [subcommand] [options] [--] [<opts>...]
14+
15+
Subcommands:
16+
run Run binaries (default)
17+
test Run tests
18+
setup Only perform automatic setup, but without asking questions (for getting a proper libstd)
1419
1520
Common options:
1621
-h, --help Print this message
@@ -27,7 +32,7 @@ it to configure the resource limits
2732
available resource limits are `memory_size`, `step_limit`, `stack_limit`
2833
"#;
2934

30-
#[derive(Copy, Clone, Debug)]
35+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
3136
enum MiriCommand {
3237
Run,
3338
Test,
@@ -43,6 +48,11 @@ fn show_version() {
4348
env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE"));
4449
}
4550

51+
fn show_error(msg: String) -> ! {
52+
eprintln!("fatal error: {}", msg);
53+
std::process::exit(1)
54+
}
55+
4656
fn list_targets(mut args: impl Iterator<Item=String>) -> impl Iterator<Item=cargo_metadata::Target> {
4757
// We need to get the manifest, and then the metadata, to enumerate targets.
4858
let manifest_path_arg = args.find(|val| {
@@ -91,6 +101,40 @@ fn list_targets(mut args: impl Iterator<Item=String>) -> impl Iterator<Item=carg
91101
package.targets.into_iter()
92102
}
93103

104+
fn ask(question: &str) {
105+
let mut buf = String::new();
106+
print!("{} [Y/n] ", question);
107+
io::stdout().flush().unwrap();
108+
io::stdin().read_line(&mut buf).unwrap();
109+
let answer = match buf.trim().to_lowercase().as_ref() {
110+
"" | "y" | "yes" => true,
111+
"n" | "no" => false,
112+
a => show_error(format!("I do not understand `{}`", a))
113+
};
114+
if !answer {
115+
show_error(format!("Aborting as per your request"))
116+
}
117+
}
118+
119+
/// Perform the setup requires to make `cargo miri` work: Getting a custom-built libstd. Then sets MIRI_SYSROOT.
120+
/// Skipped if MIRI_SYSROOT is already set, in that case we expect the user has done all this already.
121+
fn setup(ask_user: bool) {
122+
if std::env::var("MIRI_SYSROOT").is_ok() {
123+
return;
124+
}
125+
126+
// First, we need xargo
127+
if Command::new("xargo").arg("--version").output().is_err()
128+
{
129+
if ask_user {
130+
ask("It seems you do not have xargo installed. I will run `cargo install xargo`. Proceed?");
131+
}
132+
if !Command::new("cargo").args(&["install", "xargo"]).status().unwrap().success() {
133+
show_error(format!("Failed to install xargo"));
134+
}
135+
}
136+
}
137+
94138
fn main() {
95139
// Check for version and help flags even when invoked as 'cargo-miri'
96140
if std::env::args().any(|a| a == "--help" || a == "-h") {
@@ -117,11 +161,15 @@ fn main() {
117161
None => (MiriCommand::Run, 2),
118162
// Unvalid command
119163
Some(s) => {
120-
eprintln!("Unknown command `{}`", s);
121-
std::process::exit(1)
164+
show_error(format!("Unknown command `{}`", s))
122165
}
123166
};
124167

168+
// We always setup
169+
let ask = subcommand != MiriCommand::Setup;
170+
setup(ask);
171+
172+
// Now run the command.
125173
for target in list_targets(std::env::args().skip(skip)) {
126174
let args = std::env::args().skip(skip);
127175
let kind = target.kind.get(0).expect(

0 commit comments

Comments
 (0)