@@ -42,6 +42,8 @@ pub struct Command {
42
42
stdin : Option < Stdio > ,
43
43
stdout : Option < Stdio > ,
44
44
stderr : Option < Stdio > ,
45
+
46
+ spawned : bool ,
45
47
}
46
48
47
49
// passed back to std::process with the pipes connected to the child, if any
@@ -93,6 +95,8 @@ impl Command {
93
95
stdin : None ,
94
96
stdout : None ,
95
97
stderr : None ,
98
+
99
+ spawned : false ,
96
100
}
97
101
}
98
102
@@ -153,14 +157,20 @@ impl Command {
153
157
None
154
158
}
155
159
156
- fn setup_io ( & self , default : Stdio , needs_stdin : bool ) -> io:: Result < ( StdioPipes , ChildPipes ) > {
157
- let null = Stdio :: Null ;
158
- let default_stdin = if needs_stdin { & default } else { & null } ;
159
- let stdin = self . stdin . as_ref ( ) . unwrap_or ( default_stdin) ;
160
- let stdout = self . stdout . as_ref ( ) . unwrap_or ( & default) ;
161
- let stderr = self . stderr . as_ref ( ) . unwrap_or ( & default) ;
160
+ fn setup_io (
161
+ & mut self ,
162
+ mut default : Stdio ,
163
+ needs_stdin : bool ,
164
+ ) -> io:: Result < ( StdioPipes , ChildPipes ) > {
165
+ let mut null = Stdio :: Null ;
166
+ let default_stdin = if needs_stdin { & mut default } else { & mut null } ;
167
+ let stdin = self . stdin . as_mut ( ) . unwrap_or ( default_stdin) ;
162
168
let ( their_stdin, our_stdin) = stdin. to_child_stdio ( true ) ?;
169
+
170
+ let stdout = self . stdout . as_mut ( ) . unwrap_or ( & mut default) ;
163
171
let ( their_stdout, our_stdout) = stdout. to_child_stdio ( false ) ?;
172
+
173
+ let stderr = self . stderr . as_mut ( ) . unwrap_or ( & mut default) ;
164
174
let ( their_stderr, our_stderr) = stderr. to_child_stdio ( false ) ?;
165
175
let ours = StdioPipes { stdin : our_stdin, stdout : our_stdout, stderr : our_stderr } ;
166
176
let theirs = ChildPipes { stdin : their_stdin, stdout : their_stdout, stderr : their_stderr } ;
@@ -172,7 +182,16 @@ impl Command {
172
182
default : Stdio ,
173
183
needs_stdin : bool ,
174
184
) -> io:: Result < ( Process , StdioPipes ) > {
185
+ // TODO: add support for multiple spawns.
186
+ // this requires `dups` or `clone` for files.
187
+ // the reason its like that is that `Stdio::Fd` must be moved
188
+ // so we need a way to clone the file
189
+ if self . spawned {
190
+ return Err ( io:: Error :: new ( io:: ErrorKind :: Other , "Command can only be spawned once" ) ) ;
191
+ }
192
+
175
193
let ( ours, theirs) = self . setup_io ( default, needs_stdin) ?;
194
+ self . spawned = true ;
176
195
177
196
// setup 3 mappings as the max, and only use what's needed
178
197
let mut file_mappings = [ SpawnFileMapping { src_fd : 0 , dst_fd : 0 } ; 3 ] ;
@@ -212,8 +231,8 @@ impl Command {
212
231
}
213
232
214
233
impl Stdio {
215
- pub fn to_child_stdio ( & self , readable : bool ) -> io:: Result < ( ChildStdio , Option < AnonPipe > ) > {
216
- match * self {
234
+ pub fn to_child_stdio ( & mut self , readable : bool ) -> io:: Result < ( ChildStdio , Option < AnonPipe > ) > {
235
+ match self {
217
236
Stdio :: Inherit => Ok ( ( ChildStdio :: Inherit , None ) ) ,
218
237
219
238
// Make sure that the source descriptors are not an stdio
@@ -223,7 +242,16 @@ impl Stdio {
223
242
// parent's stdout, and the child's stdout to be the parent's
224
243
// stderr. No matter which we dup first, the second will get
225
244
// overwritten prematurely.
226
- Stdio :: Fd ( ref fd) => {
245
+ Stdio :: Fd ( _) => {
246
+ // replace self with inherit
247
+ // TODO: this is not good, replace with `dups` or cloning the file somehow
248
+ let fd = core:: mem:: replace ( self , Stdio :: Inherit ) ;
249
+
250
+ let fd = match fd {
251
+ Stdio :: Fd ( fd) => fd,
252
+ _ => unreachable ! ( ) ,
253
+ } ;
254
+
227
255
if fd. as_raw_fd ( ) <= FD_STDERR {
228
256
// TODO: add support for passing stdio fds
229
257
Err ( io:: Error :: new (
@@ -232,7 +260,7 @@ impl Stdio {
232
260
) )
233
261
} else {
234
262
// move the fd
235
- Ok ( ( ChildStdio :: Explicit ( fd. as_raw_fd ( ) ) , None ) )
263
+ Ok ( ( ChildStdio :: Explicit ( fd. into_raw_fd ( ) ) , None ) )
236
264
}
237
265
}
238
266
0 commit comments