1- use crate :: ffi:: OsStr ;
1+ use crate :: ffi:: { OsStr , OsString } ;
22use crate :: fmt;
33use crate :: io;
4- use crate :: marker:: PhantomData ;
54use crate :: num:: NonZero ;
65use crate :: path:: Path ;
76use crate :: sys:: fs:: File ;
@@ -16,7 +15,14 @@ pub use crate::ffi::OsString as EnvKey;
1615////////////////////////////////////////////////////////////////////////////////
1716
1817pub struct Command {
18+ program : OsString ,
19+ args : Vec < OsString > ,
1920 env : CommandEnv ,
21+
22+ cwd : Option < OsString > ,
23+ stdin : Option < Stdio > ,
24+ stdout : Option < Stdio > ,
25+ stderr : Option < Stdio > ,
2026}
2127
2228// passed back to std::process with the pipes connected to the child, if any
@@ -27,47 +33,70 @@ pub struct StdioPipes {
2733 pub stderr : Option < AnonPipe > ,
2834}
2935
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 ) ]
3237pub enum Stdio {
3338 Inherit ,
3439 Null ,
3540 MakePipe ,
41+ ParentStdout ,
42+ ParentStderr ,
43+ #[ allow( dead_code) ] // This variant exists only for the Debug impl
44+ InheritFile ( File ) ,
3645}
3746
3847impl Command {
39- pub fn new ( _program : & OsStr ) -> Command {
40- Command { env : Default :: default ( ) }
48+ pub fn new ( program : & OsStr ) -> Command {
49+ Command {
50+ program : program. to_owned ( ) ,
51+ args : vec ! [ program. to_owned( ) ] ,
52+ env : Default :: default ( ) ,
53+ cwd : None ,
54+ stdin : None ,
55+ stdout : None ,
56+ stderr : None ,
57+ }
4158 }
4259
43- pub fn arg ( & mut self , _arg : & OsStr ) { }
60+ pub fn arg ( & mut self , arg : & OsStr ) {
61+ self . args . push ( arg. to_owned ( ) ) ;
62+ }
4463
4564 pub fn env_mut ( & mut self ) -> & mut CommandEnv {
4665 & mut self . env
4766 }
4867
49- pub fn cwd ( & mut self , _dir : & OsStr ) { }
68+ pub fn cwd ( & mut self , dir : & OsStr ) {
69+ self . cwd = Some ( dir. to_owned ( ) ) ;
70+ }
5071
51- pub fn stdin ( & mut self , _stdin : Stdio ) { }
72+ pub fn stdin ( & mut self , stdin : Stdio ) {
73+ self . stdin = Some ( stdin) ;
74+ }
5275
53- pub fn stdout ( & mut self , _stdout : Stdio ) { }
76+ pub fn stdout ( & mut self , stdout : Stdio ) {
77+ self . stdout = Some ( stdout) ;
78+ }
5479
55- pub fn stderr ( & mut self , _stderr : Stdio ) { }
80+ pub fn stderr ( & mut self , stderr : Stdio ) {
81+ self . stderr = Some ( stderr) ;
82+ }
5683
5784 pub fn get_program ( & self ) -> & OsStr {
58- panic ! ( "unsupported" )
85+ & self . program
5986 }
6087
6188 pub fn get_args ( & self ) -> CommandArgs < ' _ > {
62- CommandArgs { _p : PhantomData }
89+ let mut iter = self . args . iter ( ) ;
90+ iter. next ( ) ;
91+ CommandArgs { iter }
6392 }
6493
6594 pub fn get_envs ( & self ) -> CommandEnvs < ' _ > {
6695 self . env . iter ( )
6796 }
6897
6998 pub fn get_current_dir ( & self ) -> Option < & Path > {
70- None
99+ self . cwd . as_ref ( ) . map ( |cs| Path :: new ( cs ) )
71100 }
72101
73102 pub fn spawn (
@@ -91,31 +120,83 @@ impl From<AnonPipe> for Stdio {
91120
92121impl From < io:: Stdout > for Stdio {
93122 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" )
123+ Stdio :: ParentStdout
97124 }
98125}
99126
100127impl From < io:: Stderr > for Stdio {
101128 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" )
129+ Stdio :: ParentStderr
105130 }
106131}
107132
108133impl 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" )
134+ fn from ( file : File ) -> Stdio {
135+ Stdio :: InheritFile ( file)
113136 }
114137}
115138
116139impl fmt:: Debug for Command {
117- fn fmt ( & self , _f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
118- Ok ( ( ) )
140+ // show all attributes
141+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
142+ if f. alternate ( ) {
143+ let mut debug_command = f. debug_struct ( "Command" ) ;
144+ debug_command. field ( "program" , & self . program ) . field ( "args" , & self . args ) ;
145+ if !self . env . is_unchanged ( ) {
146+ debug_command. field ( "env" , & self . env ) ;
147+ }
148+
149+ if self . cwd . is_some ( ) {
150+ debug_command. field ( "cwd" , & self . cwd ) ;
151+ }
152+
153+ if self . stdin . is_some ( ) {
154+ debug_command. field ( "stdin" , & self . stdin ) ;
155+ }
156+ if self . stdout . is_some ( ) {
157+ debug_command. field ( "stdout" , & self . stdout ) ;
158+ }
159+ if self . stderr . is_some ( ) {
160+ debug_command. field ( "stderr" , & self . stderr ) ;
161+ }
162+
163+ debug_command. finish ( )
164+ } else {
165+ if let Some ( ref cwd) = self . cwd {
166+ write ! ( f, "cd {cwd:?} && " ) ?;
167+ }
168+ if self . env . does_clear ( ) {
169+ write ! ( f, "env -i " ) ?;
170+ // Altered env vars will be printed next, that should exactly work as expected.
171+ } else {
172+ // Removed env vars need the command to be wrapped in `env`.
173+ let mut any_removed = false ;
174+ for ( key, value_opt) in self . get_envs ( ) {
175+ if value_opt. is_none ( ) {
176+ if !any_removed {
177+ write ! ( f, "env " ) ?;
178+ any_removed = true ;
179+ }
180+ write ! ( f, "-u {} " , key. to_string_lossy( ) ) ?;
181+ }
182+ }
183+ }
184+ // Altered env vars can just be added in front of the program.
185+ for ( key, value_opt) in self . get_envs ( ) {
186+ if let Some ( value) = value_opt {
187+ write ! ( f, "{}={value:?} " , key. to_string_lossy( ) ) ?;
188+ }
189+ }
190+ if self . program != self . args [ 0 ] {
191+ write ! ( f, "[{:?}] " , self . program) ?;
192+ }
193+ write ! ( f, "{:?}" , self . args[ 0 ] ) ?;
194+
195+ for arg in & self . args [ 1 ..] {
196+ write ! ( f, " {:?}" , arg) ?;
197+ }
198+ Ok ( ( ) )
199+ }
119200 }
120201}
121202
@@ -217,23 +298,30 @@ impl Process {
217298}
218299
219300pub struct CommandArgs < ' a > {
220- _p : PhantomData < & ' a ( ) > ,
301+ iter : crate :: slice :: Iter < ' a , OsString > ,
221302}
222303
223304impl < ' a > Iterator for CommandArgs < ' a > {
224305 type Item = & ' a OsStr ;
225306 fn next ( & mut self ) -> Option < & ' a OsStr > {
226- None
307+ self . iter . next ( ) . map ( |os| & * * os )
227308 }
228309 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
229- ( 0 , Some ( 0 ) )
310+ self . iter . size_hint ( )
230311 }
231312}
232313
233- impl < ' a > ExactSizeIterator for CommandArgs < ' a > { }
314+ impl < ' a > ExactSizeIterator for CommandArgs < ' a > {
315+ fn len ( & self ) -> usize {
316+ self . iter . len ( )
317+ }
318+ fn is_empty ( & self ) -> bool {
319+ self . iter . is_empty ( )
320+ }
321+ }
234322
235323impl < ' a > fmt:: Debug for CommandArgs < ' a > {
236324 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
237- f. debug_list ( ) . finish ( )
325+ f. debug_list ( ) . entries ( self . iter . clone ( ) ) . finish ( )
238326 }
239327}
0 commit comments