3
3
extern crate cargo_metadata;
4
4
5
5
use std:: path:: { PathBuf , Path } ;
6
- use std:: io:: Write ;
6
+ use std:: io:: { self , Write } ;
7
7
use std:: process:: Command ;
8
8
9
9
10
10
const CARGO_MIRI_HELP : & str = r#"Interprets bin crates
11
11
12
12
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)
14
19
15
20
Common options:
16
21
-h, --help Print this message
@@ -27,7 +32,7 @@ it to configure the resource limits
27
32
available resource limits are `memory_size`, `step_limit`, `stack_limit`
28
33
"# ;
29
34
30
- #[ derive( Copy , Clone , Debug ) ]
35
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
31
36
enum MiriCommand {
32
37
Run ,
33
38
Test ,
@@ -43,6 +48,11 @@ fn show_version() {
43
48
env!( "CARGO_PKG_VERSION" ) , env!( "VERGEN_SHA_SHORT" ) , env!( "VERGEN_COMMIT_DATE" ) ) ;
44
49
}
45
50
51
+ fn show_error ( msg : String ) -> ! {
52
+ eprintln ! ( "fatal error: {}" , msg) ;
53
+ std:: process:: exit ( 1 )
54
+ }
55
+
46
56
fn list_targets ( mut args : impl Iterator < Item =String > ) -> impl Iterator < Item =cargo_metadata:: Target > {
47
57
// We need to get the manifest, and then the metadata, to enumerate targets.
48
58
let manifest_path_arg = args. find ( |val| {
@@ -91,6 +101,40 @@ fn list_targets(mut args: impl Iterator<Item=String>) -> impl Iterator<Item=carg
91
101
package. targets . into_iter ( )
92
102
}
93
103
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
+
94
138
fn main ( ) {
95
139
// Check for version and help flags even when invoked as 'cargo-miri'
96
140
if std:: env:: args ( ) . any ( |a| a == "--help" || a == "-h" ) {
@@ -117,11 +161,15 @@ fn main() {
117
161
None => ( MiriCommand :: Run , 2 ) ,
118
162
// Unvalid command
119
163
Some ( s) => {
120
- eprintln ! ( "Unknown command `{}`" , s) ;
121
- std:: process:: exit ( 1 )
164
+ show_error ( format ! ( "Unknown command `{}`" , s) )
122
165
}
123
166
} ;
124
167
168
+ // We always setup
169
+ let ask = subcommand != MiriCommand :: Setup ;
170
+ setup ( ask) ;
171
+
172
+ // Now run the command.
125
173
for target in list_targets ( std:: env:: args ( ) . skip ( skip) ) {
126
174
let args = std:: env:: args ( ) . skip ( skip) ;
127
175
let kind = target. kind . get ( 0 ) . expect (
0 commit comments