1
- use crate :: ffi:: OsStr ;
1
+ use crate :: ffi:: { OsStr , OsString } ;
2
2
use crate :: fmt;
3
3
use crate :: io;
4
- use crate :: marker:: PhantomData ;
5
4
use crate :: num:: NonZero ;
6
5
use crate :: path:: Path ;
7
6
use crate :: sys:: fs:: File ;
@@ -16,7 +15,14 @@ pub use crate::ffi::OsString as EnvKey;
16
15
////////////////////////////////////////////////////////////////////////////////
17
16
18
17
pub struct Command {
18
+ program : OsString ,
19
+ args : Vec < OsString > ,
19
20
env : CommandEnv ,
21
+
22
+ cwd : Option < OsString > ,
23
+ stdin : Option < Stdio > ,
24
+ stdout : Option < Stdio > ,
25
+ stderr : Option < Stdio > ,
20
26
}
21
27
22
28
// passed back to std::process with the pipes connected to the child, if any
@@ -27,47 +33,69 @@ pub struct StdioPipes {
27
33
pub stderr : Option < AnonPipe > ,
28
34
}
29
35
30
- // FIXME: This should be a unit struct, so we can always construct it
31
- // The value here should be never used, since we cannot spawn processes.
36
+ #[ derive( Debug ) ]
32
37
pub enum Stdio {
33
38
Inherit ,
34
39
Null ,
35
40
MakePipe ,
41
+ ParentStdout ,
42
+ ParentStderr ,
43
+ InheritFile ( File ) ,
36
44
}
37
45
38
46
impl Command {
39
- pub fn new ( _program : & OsStr ) -> Command {
40
- Command { env : Default :: default ( ) }
47
+ pub fn new ( program : & OsStr ) -> Command {
48
+ Command {
49
+ program : program. to_owned ( ) ,
50
+ args : vec ! [ program. to_owned( ) ] ,
51
+ env : Default :: default ( ) ,
52
+ cwd : None ,
53
+ stdin : None ,
54
+ stdout : None ,
55
+ stderr : None ,
56
+ }
41
57
}
42
58
43
- pub fn arg ( & mut self , _arg : & OsStr ) { }
59
+ pub fn arg ( & mut self , arg : & OsStr ) {
60
+ self . args . push ( arg. to_owned ( ) ) ;
61
+ }
44
62
45
63
pub fn env_mut ( & mut self ) -> & mut CommandEnv {
46
64
& mut self . env
47
65
}
48
66
49
- pub fn cwd ( & mut self , _dir : & OsStr ) { }
67
+ pub fn cwd ( & mut self , dir : & OsStr ) {
68
+ self . cwd = Some ( dir. to_owned ( ) ) ;
69
+ }
50
70
51
- pub fn stdin ( & mut self , _stdin : Stdio ) { }
71
+ pub fn stdin ( & mut self , stdin : Stdio ) {
72
+ self . stdin = Some ( stdin) ;
73
+ }
52
74
53
- pub fn stdout ( & mut self , _stdout : Stdio ) { }
75
+ pub fn stdout ( & mut self , stdout : Stdio ) {
76
+ self . stdout = Some ( stdout) ;
77
+ }
54
78
55
- pub fn stderr ( & mut self , _stderr : Stdio ) { }
79
+ pub fn stderr ( & mut self , stderr : Stdio ) {
80
+ self . stderr = Some ( stderr) ;
81
+ }
56
82
57
83
pub fn get_program ( & self ) -> & OsStr {
58
- panic ! ( "unsupported" )
84
+ & self . program
59
85
}
60
86
61
87
pub fn get_args ( & self ) -> CommandArgs < ' _ > {
62
- CommandArgs { _p : PhantomData }
88
+ let mut iter = self . args . iter ( ) ;
89
+ iter. next ( ) ;
90
+ CommandArgs { iter }
63
91
}
64
92
65
93
pub fn get_envs ( & self ) -> CommandEnvs < ' _ > {
66
94
self . env . iter ( )
67
95
}
68
96
69
97
pub fn get_current_dir ( & self ) -> Option < & Path > {
70
- None
98
+ self . cwd . as_ref ( ) . map ( |cs| Path :: new ( cs ) )
71
99
}
72
100
73
101
pub fn spawn (
@@ -91,31 +119,83 @@ impl From<AnonPipe> for Stdio {
91
119
92
120
impl From < io:: Stdout > for Stdio {
93
121
fn from ( _: io:: Stdout ) -> Stdio {
94
- // FIXME: This is wrong.
95
- // Instead, the Stdio we have here should be a unit struct.
96
- panic ! ( "unsupported" )
122
+ Stdio :: ParentStdout
97
123
}
98
124
}
99
125
100
126
impl From < io:: Stderr > for Stdio {
101
127
fn from ( _: io:: Stderr ) -> Stdio {
102
- // FIXME: This is wrong.
103
- // Instead, the Stdio we have here should be a unit struct.
104
- panic ! ( "unsupported" )
128
+ Stdio :: ParentStderr
105
129
}
106
130
}
107
131
108
132
impl From < File > for Stdio {
109
- fn from ( _file : File ) -> Stdio {
110
- // FIXME: This is wrong.
111
- // Instead, the Stdio we have here should be a unit struct.
112
- panic ! ( "unsupported" )
133
+ fn from ( file : File ) -> Stdio {
134
+ Stdio :: InheritFile ( file)
113
135
}
114
136
}
115
137
116
138
impl fmt:: Debug for Command {
117
- fn fmt ( & self , _f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
118
- Ok ( ( ) )
139
+ // show all attributes
140
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
141
+ if f. alternate ( ) {
142
+ let mut debug_command = f. debug_struct ( "Command" ) ;
143
+ debug_command. field ( "program" , & self . program ) . field ( "args" , & self . args ) ;
144
+ if !self . env . is_unchanged ( ) {
145
+ debug_command. field ( "env" , & self . env ) ;
146
+ }
147
+
148
+ if self . cwd . is_some ( ) {
149
+ debug_command. field ( "cwd" , & self . cwd ) ;
150
+ }
151
+
152
+ if self . stdin . is_some ( ) {
153
+ debug_command. field ( "stdin" , & self . stdin ) ;
154
+ }
155
+ if self . stdout . is_some ( ) {
156
+ debug_command. field ( "stdout" , & self . stdout ) ;
157
+ }
158
+ if self . stderr . is_some ( ) {
159
+ debug_command. field ( "stderr" , & self . stderr ) ;
160
+ }
161
+
162
+ debug_command. finish ( )
163
+ } else {
164
+ if let Some ( ref cwd) = self . cwd {
165
+ write ! ( f, "cd {cwd:?} && " ) ?;
166
+ }
167
+ if self . env . does_clear ( ) {
168
+ write ! ( f, "env -i " ) ?;
169
+ // Altered env vars will be printed next, that should exactly work as expected.
170
+ } else {
171
+ // Removed env vars need the command to be wrapped in `env`.
172
+ let mut any_removed = false ;
173
+ for ( key, value_opt) in self . get_envs ( ) {
174
+ if value_opt. is_none ( ) {
175
+ if !any_removed {
176
+ write ! ( f, "env " ) ?;
177
+ any_removed = true ;
178
+ }
179
+ write ! ( f, "-u {} " , key. to_string_lossy( ) ) ?;
180
+ }
181
+ }
182
+ }
183
+ // Altered env vars can just be added in front of the program.
184
+ for ( key, value_opt) in self . get_envs ( ) {
185
+ if let Some ( value) = value_opt {
186
+ write ! ( f, "{}={value:?} " , key. to_string_lossy( ) ) ?;
187
+ }
188
+ }
189
+ if self . program != self . args [ 0 ] {
190
+ write ! ( f, "[{:?}] " , self . program) ?;
191
+ }
192
+ write ! ( f, "{:?}" , self . args[ 0 ] ) ?;
193
+
194
+ for arg in & self . args [ 1 ..] {
195
+ write ! ( f, " {:?}" , arg) ?;
196
+ }
197
+ Ok ( ( ) )
198
+ }
119
199
}
120
200
}
121
201
@@ -217,23 +297,30 @@ impl Process {
217
297
}
218
298
219
299
pub struct CommandArgs < ' a > {
220
- _p : PhantomData < & ' a ( ) > ,
300
+ iter : crate :: slice :: Iter < ' a , OsString > ,
221
301
}
222
302
223
303
impl < ' a > Iterator for CommandArgs < ' a > {
224
304
type Item = & ' a OsStr ;
225
305
fn next ( & mut self ) -> Option < & ' a OsStr > {
226
- None
306
+ self . iter . next ( ) . map ( |os| & * * os )
227
307
}
228
308
fn size_hint ( & self ) -> ( usize , Option < usize > ) {
229
- ( 0 , Some ( 0 ) )
309
+ self . iter . size_hint ( )
230
310
}
231
311
}
232
312
233
- impl < ' a > ExactSizeIterator for CommandArgs < ' a > { }
313
+ impl < ' a > ExactSizeIterator for CommandArgs < ' a > {
314
+ fn len ( & self ) -> usize {
315
+ self . iter . len ( )
316
+ }
317
+ fn is_empty ( & self ) -> bool {
318
+ self . iter . is_empty ( )
319
+ }
320
+ }
234
321
235
322
impl < ' a > fmt:: Debug for CommandArgs < ' a > {
236
323
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
237
- f. debug_list ( ) . finish ( )
324
+ f. debug_list ( ) . entries ( self . iter . clone ( ) ) . finish ( )
238
325
}
239
326
}
0 commit comments