@@ -11,12 +11,21 @@ use shell_escape::escape;
11
11
use util:: { CargoResult , CargoResultExt , CargoError , process_error, read2} ;
12
12
use util:: errors:: CargoErrorKind ;
13
13
14
+ /// A builder object for an external process, similar to `std::process::Command`.
14
15
#[ derive( Clone , Debug ) ]
15
16
pub struct ProcessBuilder {
17
+ /// The program to execute.
16
18
program : OsString ,
19
+ /// A list of arguments to pass to the program.
17
20
args : Vec < OsString > ,
21
+ /// Any environment variables that should be set for the program.
18
22
env : HashMap < String , Option < OsString > > ,
23
+ /// Which directory to run the program from.
19
24
cwd : Option < OsString > ,
25
+ /// The `make` jobserver. See the [jobserver crate][jobserver_docs] for
26
+ /// more information.
27
+ ///
28
+ /// [jobserver_docs]: https://docs.rs/jobserver/0.1.6/jobserver/
20
29
jobserver : Option < Client > ,
21
30
}
22
31
@@ -33,70 +42,89 @@ impl fmt::Display for ProcessBuilder {
33
42
}
34
43
35
44
impl ProcessBuilder {
45
+ /// (chainable) Set the executable for the process.
36
46
pub fn program < T : AsRef < OsStr > > ( & mut self , program : T ) -> & mut ProcessBuilder {
37
47
self . program = program. as_ref ( ) . to_os_string ( ) ;
38
48
self
39
49
}
40
50
51
+ /// (chainable) Add an arg to the args list.
41
52
pub fn arg < T : AsRef < OsStr > > ( & mut self , arg : T ) -> & mut ProcessBuilder {
42
53
self . args . push ( arg. as_ref ( ) . to_os_string ( ) ) ;
43
54
self
44
55
}
45
56
57
+ /// (chainable) Add many args to the args list.
46
58
pub fn args < T : AsRef < OsStr > > ( & mut self , arguments : & [ T ] ) -> & mut ProcessBuilder {
47
59
self . args . extend ( arguments. iter ( ) . map ( |t| {
48
60
t. as_ref ( ) . to_os_string ( )
49
61
} ) ) ;
50
62
self
51
63
}
52
64
65
+ /// (chainable) Replace args with new args list
53
66
pub fn args_replace < T : AsRef < OsStr > > ( & mut self , arguments : & [ T ] ) -> & mut ProcessBuilder {
54
67
self . args = arguments. iter ( ) . map ( |t| {
55
68
t. as_ref ( ) . to_os_string ( )
56
69
} ) . collect ( ) ;
57
70
self
58
71
}
59
72
73
+ /// (chainable) Set the current working directory of the process
60
74
pub fn cwd < T : AsRef < OsStr > > ( & mut self , path : T ) -> & mut ProcessBuilder {
61
75
self . cwd = Some ( path. as_ref ( ) . to_os_string ( ) ) ;
62
76
self
63
77
}
64
78
79
+ /// (chainable) Set an environment variable for the process.
65
80
pub fn env < T : AsRef < OsStr > > ( & mut self , key : & str ,
66
81
val : T ) -> & mut ProcessBuilder {
67
82
self . env . insert ( key. to_string ( ) , Some ( val. as_ref ( ) . to_os_string ( ) ) ) ;
68
83
self
69
84
}
70
85
86
+ /// (chainable) Unset an environment variable for the process.
71
87
pub fn env_remove ( & mut self , key : & str ) -> & mut ProcessBuilder {
72
88
self . env . insert ( key. to_string ( ) , None ) ;
73
89
self
74
90
}
75
91
92
+ /// Get the executable name.
76
93
pub fn get_program ( & self ) -> & OsString {
77
94
& self . program
78
95
}
79
96
97
+ /// Get the program arguments
80
98
pub fn get_args ( & self ) -> & [ OsString ] {
81
99
& self . args
82
100
}
83
101
102
+ /// Get the current working directory for the process
84
103
pub fn get_cwd ( & self ) -> Option < & Path > {
85
104
self . cwd . as_ref ( ) . map ( Path :: new)
86
105
}
87
106
107
+ /// Get an environment variable as the process will see it (will inherit from environment
108
+ /// unless explicitally unset).
88
109
pub fn get_env ( & self , var : & str ) -> Option < OsString > {
89
110
self . env . get ( var) . cloned ( ) . or_else ( || Some ( env:: var_os ( var) ) )
90
111
. and_then ( |s| s)
91
112
}
92
113
114
+ /// Get all environment variables explicitally set or unset for the process (not inherited
115
+ /// vars).
93
116
pub fn get_envs ( & self ) -> & HashMap < String , Option < OsString > > { & self . env }
94
117
118
+ /// Set the `make` jobserver. See the [jobserver crate][jobserver_docs] for
119
+ /// more information.
120
+ ///
121
+ /// [jobserver_docs]: https://docs.rs/jobserver/0.1.6/jobserver/
95
122
pub fn inherit_jobserver ( & mut self , jobserver : & Client ) -> & mut Self {
96
123
self . jobserver = Some ( jobserver. clone ( ) ) ;
97
124
self
98
125
}
99
126
127
+ /// Run the process, waiting for completion, and mapping non-success exit codes to an error.
100
128
pub fn exec ( & self ) -> CargoResult < ( ) > {
101
129
let mut command = self . build_command ( ) ;
102
130
let exit = command. status ( ) . chain_err ( || {
@@ -114,6 +142,9 @@ impl ProcessBuilder {
114
142
}
115
143
}
116
144
145
+ /// On unix, executes the process using the unix syscall `execvp`, which will block this
146
+ /// process, and will only return if there is an error. On windows this is a synonym for
147
+ /// `exec`.
117
148
#[ cfg( unix) ]
118
149
pub fn exec_replace ( & self ) -> CargoResult < ( ) > {
119
150
use std:: os:: unix:: process:: CommandExt ;
@@ -125,11 +156,15 @@ impl ProcessBuilder {
125
156
& format ! ( "could not execute process `{}`" , self . debug_string( ) ) , None , None ) ) ) )
126
157
}
127
158
159
+ /// On unix, executes the process using the unix syscall `execvp`, which will block this
160
+ /// process, and will only return if there is an error. On windows this is a synonym for
161
+ /// `exec`.
128
162
#[ cfg( windows) ]
129
163
pub fn exec_replace ( & self ) -> CargoResult < ( ) > {
130
164
self . exec ( )
131
165
}
132
166
167
+ /// Execute the process, returning the stdio output, or an error if non-zero exit status.
133
168
pub fn exec_with_output ( & self ) -> CargoResult < Output > {
134
169
let mut command = self . build_command ( ) ;
135
170
@@ -149,6 +184,12 @@ impl ProcessBuilder {
149
184
}
150
185
}
151
186
187
+ /// Execute a command, passing each line of stdout and stderr to the supplied callbacks, which
188
+ /// can mutate the string data.
189
+ ///
190
+ /// If any invocations of these function return an error, it will be propagated.
191
+ ///
192
+ /// Optionally, output can be passed to errors using `print_output`
152
193
pub fn exec_with_streaming ( & self ,
153
194
on_stdout_line : & mut FnMut ( & str ) -> CargoResult < ( ) > ,
154
195
on_stderr_line : & mut FnMut ( & str ) -> CargoResult < ( ) > ,
@@ -226,6 +267,8 @@ impl ProcessBuilder {
226
267
Ok ( output)
227
268
}
228
269
270
+ /// Converts ProcessBuilder into a `std::process::Command`, and handles the jobserver if
271
+ /// present.
229
272
pub fn build_command ( & self ) -> Command {
230
273
let mut command = Command :: new ( & self . program ) ;
231
274
if let Some ( cwd) = self . get_cwd ( ) {
@@ -246,6 +289,7 @@ impl ProcessBuilder {
246
289
command
247
290
}
248
291
292
+ /// Get the command line for the process as a string.
249
293
fn debug_string ( & self ) -> String {
250
294
let mut program = format ! ( "{}" , self . program. to_string_lossy( ) ) ;
251
295
for arg in & self . args {
@@ -256,6 +300,7 @@ impl ProcessBuilder {
256
300
}
257
301
}
258
302
303
+ /// A helper function to create a ProcessBuilder.
259
304
pub fn process < T : AsRef < OsStr > > ( cmd : T ) -> ProcessBuilder {
260
305
ProcessBuilder {
261
306
program : cmd. as_ref ( ) . to_os_string ( ) ,
0 commit comments