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,69 @@ 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+ InheritFile ( File ) ,
3644}
3745
3846impl 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+ }
4157 }
4258
43- pub fn arg ( & mut self , _arg : & OsStr ) { }
59+ pub fn arg ( & mut self , arg : & OsStr ) {
60+ self . args . push ( arg. to_owned ( ) ) ;
61+ }
4462
4563 pub fn env_mut ( & mut self ) -> & mut CommandEnv {
4664 & mut self . env
4765 }
4866
49- pub fn cwd ( & mut self , _dir : & OsStr ) { }
67+ pub fn cwd ( & mut self , dir : & OsStr ) {
68+ self . cwd = Some ( dir. to_owned ( ) ) ;
69+ }
5070
51- pub fn stdin ( & mut self , _stdin : Stdio ) { }
71+ pub fn stdin ( & mut self , stdin : Stdio ) {
72+ self . stdin = Some ( stdin) ;
73+ }
5274
53- pub fn stdout ( & mut self , _stdout : Stdio ) { }
75+ pub fn stdout ( & mut self , stdout : Stdio ) {
76+ self . stdout = Some ( stdout) ;
77+ }
5478
55- pub fn stderr ( & mut self , _stderr : Stdio ) { }
79+ pub fn stderr ( & mut self , stderr : Stdio ) {
80+ self . stderr = Some ( stderr) ;
81+ }
5682
5783 pub fn get_program ( & self ) -> & OsStr {
58- panic ! ( "unsupported" )
84+ & self . program
5985 }
6086
6187 pub fn get_args ( & self ) -> CommandArgs < ' _ > {
62- CommandArgs { _p : PhantomData }
88+ let mut iter = self . args . iter ( ) ;
89+ iter. next ( ) ;
90+ CommandArgs { iter }
6391 }
6492
6593 pub fn get_envs ( & self ) -> CommandEnvs < ' _ > {
6694 self . env . iter ( )
6795 }
6896
6997 pub fn get_current_dir ( & self ) -> Option < & Path > {
70- None
98+ self . cwd . as_ref ( ) . map ( |cs| Path :: new ( cs ) )
7199 }
72100
73101 pub fn spawn (
@@ -91,31 +119,83 @@ impl From<AnonPipe> for Stdio {
91119
92120impl From < io:: Stdout > for Stdio {
93121 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
97123 }
98124}
99125
100126impl From < io:: Stderr > for Stdio {
101127 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
105129 }
106130}
107131
108132impl 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)
113135 }
114136}
115137
116138impl 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+ }
119199 }
120200}
121201
@@ -217,23 +297,30 @@ impl Process {
217297}
218298
219299pub struct CommandArgs < ' a > {
220- _p : PhantomData < & ' a ( ) > ,
300+ iter : crate :: slice :: Iter < ' a , OsString > ,
221301}
222302
223303impl < ' a > Iterator for CommandArgs < ' a > {
224304 type Item = & ' a OsStr ;
225305 fn next ( & mut self ) -> Option < & ' a OsStr > {
226- None
306+ self . iter . next ( ) . map ( |os| & * * os )
227307 }
228308 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
229- ( 0 , Some ( 0 ) )
309+ self . iter . size_hint ( )
230310 }
231311}
232312
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+ }
234321
235322impl < ' a > fmt:: Debug for CommandArgs < ' a > {
236323 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
237- f. debug_list ( ) . finish ( )
324+ f. debug_list ( ) . entries ( self . iter . clone ( ) ) . finish ( )
238325 }
239326}
0 commit comments