13
13
// limitations under the License.
14
14
15
15
mod flags;
16
+ mod options;
16
17
mod util;
17
18
18
- use std:: collections:: HashMap ;
19
- use std:: env;
20
19
use std:: fs:: { copy, OpenOptions } ;
21
20
use std:: process:: { exit, Command , Stdio } ;
22
21
23
- use flags:: { Flags , ParseOutcome } ;
24
- use util:: * ;
25
-
26
- fn environment_block (
27
- environment_file_block : HashMap < String , String > ,
28
- stamp_mappings : & [ ( String , String ) ] ,
29
- subst_mappings : & [ ( String , String ) ] ,
30
- ) -> HashMap < String , String > {
31
- // Taking all environment variables from the current process
32
- // and sending them down to the child process
33
- let mut environment_variables: HashMap < String , String > = std:: env:: vars ( ) . collect ( ) ;
34
- // Have the last values added take precedence over the first.
35
- // This is simpler than needing to track duplicates and explicitly override
36
- // them.
37
- environment_variables. extend ( environment_file_block. into_iter ( ) ) ;
38
- for ( f, replace_with) in stamp_mappings {
39
- for value in environment_variables. values_mut ( ) {
40
- let from = format ! ( "{{{}}}" , f) ;
41
- let new = value. replace ( from. as_str ( ) , replace_with) ;
42
- * value = new;
43
- }
44
- }
45
- for ( f, replace_with) in subst_mappings {
46
- for value in environment_variables. values_mut ( ) {
47
- let from = format ! ( "${{{}}}" , f) ;
48
- let new = value. replace ( from. as_str ( ) , replace_with) ;
49
- * value = new;
50
- }
51
- }
52
- environment_variables
53
- }
54
-
55
- fn prepare_args ( mut args : Vec < String > , subst_mappings : & [ ( String , String ) ] ) -> Vec < String > {
56
- for ( f, replace_with) in subst_mappings {
57
- for arg in args. iter_mut ( ) {
58
- let from = format ! ( "${{{}}}" , f) ;
59
- let new = arg. replace ( from. as_str ( ) , replace_with) ;
60
- * arg = new;
61
- }
62
- }
63
- args
64
- }
22
+ use crate :: options:: options;
65
23
66
24
fn main ( ) {
67
- // Process argument list until -- is encountered.
68
- // Everything after is sent to the child process.
69
- let mut subst_mapping_raw = None ;
70
- let mut volatile_status_file_raw = None ;
71
- let mut env_file_raw = None ;
72
- let mut arg_file_raw = None ;
73
- let mut touch_file_raw = None ;
74
- let mut copy_output_raw = None ;
75
- let mut stdout_file_raw = None ;
76
- let mut stderr_file_raw = None ;
77
- let mut flags = Flags :: new ( ) ;
78
- flags. define_repeated_flag ( "--subst" , "" , & mut subst_mapping_raw) ;
79
- flags. define_flag ( "--volatile-status-file" , "" , & mut volatile_status_file_raw) ;
80
- flags. define_repeated_flag ( "--env-file" , "" , & mut env_file_raw) ;
81
- flags. define_repeated_flag ( "--arg-file" , "" , & mut arg_file_raw) ;
82
- flags. define_flag ( "--touch-file" , "" , & mut touch_file_raw) ;
83
- flags. define_repeated_flag ( "--copy-output" , "" , & mut copy_output_raw) ;
84
- flags. define_flag (
85
- "--stdout-file" ,
86
- "Redirect subprocess stdout in this file." ,
87
- & mut stdout_file_raw,
88
- ) ;
89
- flags. define_flag (
90
- "--stderr-file" ,
91
- "Redirect subprocess stderr in this file." ,
92
- & mut stderr_file_raw,
93
- ) ;
94
- let mut child_args = match flags
95
- . parse ( env:: args ( ) . collect ( ) )
96
- . expect ( "flag parse error" )
97
- {
98
- ParseOutcome :: Help ( help) => {
99
- eprintln ! ( "{}" , help) ;
100
- return ;
101
- }
102
- ParseOutcome :: Parsed ( p) => p,
25
+ let opts = match options ( ) {
26
+ Err ( err) => panic ! ( "process wrapper error: {}" , err) ,
27
+ Ok ( v) => v,
103
28
} ;
104
- let subst_mappings: Vec < ( String , String ) > = subst_mapping_raw
105
- . unwrap_or_default ( )
106
- . into_iter ( )
107
- . map ( |arg| {
108
- let ( key, val) = arg. split_once ( '=' ) . unwrap_or_else ( || {
109
- panic ! (
110
- "process wrapper error: empty key for substitution '{}'" ,
111
- arg
112
- )
113
- } ) ;
114
- let v = if val == "${pwd}" {
115
- std:: env:: current_dir ( )
116
- . unwrap ( )
117
- . to_str ( )
118
- . unwrap ( )
119
- . to_string ( )
120
- } else {
121
- val. to_owned ( )
122
- } ;
123
- ( key. to_owned ( ) , v)
124
- } )
125
- . collect ( ) ;
126
- let stamp_mappings =
127
- volatile_status_file_raw. map_or_else ( Vec :: new, |s| read_stamp_status_to_array ( s) . unwrap ( ) ) ;
128
- let environment_file_block: HashMap < String , String > = env_file_raw
129
- . unwrap_or_default ( )
130
- . into_iter ( )
131
- . flat_map ( |path| -> Vec < ( String , String ) > {
132
- let lines = read_file_to_array ( path) . unwrap ( ) ;
133
- lines
134
- . into_iter ( )
135
- . map ( |l| {
136
- let splits = l
137
- . split_once ( '=' )
138
- . expect ( "process wrapper error: environment file invalid" ) ;
139
- ( splits. 0 . to_owned ( ) , splits. 1 . to_owned ( ) )
140
- } )
141
- . collect ( )
142
- } )
143
- . collect ( ) ;
144
- let mut file_arguments: Vec < String > = arg_file_raw
145
- . unwrap_or_default ( )
146
- . into_iter ( )
147
- . flat_map ( |path| read_file_to_array ( path) . unwrap ( ) )
148
- . collect ( ) ;
149
- // Process --copy-output
150
- let copy_output = copy_output_raw. map ( |co| {
151
- if co. len ( ) != 2 {
152
- panic ! (
153
- "process wrapper error: \" --copy-output\" needs exactly 2 parameters, {} provided" ,
154
- co. len( )
155
- )
156
- }
157
- let copy_source = & co[ 0 ] ;
158
- let copy_dest = & co[ 1 ] ;
159
- if copy_source == copy_dest {
160
- panic ! (
161
- "process wrapper error: \" --copy-output\" source ({}) and dest ({}) need to be different." ,
162
- copy_source, copy_dest
163
- )
164
- }
165
- ( copy_source. to_owned ( ) , copy_dest. to_owned ( ) )
166
- } ) ;
167
- child_args. append ( & mut file_arguments) ;
168
- let child_args = prepare_args ( child_args, & subst_mappings) ;
169
-
170
- let ( exec_path, args) = child_args. split_first ( ) . expect ( "process wrapper error: at least one argument after -- is required (the child process path) but none found." ) ;
171
- let vars = environment_block ( environment_file_block, & stamp_mappings, & subst_mappings) ;
172
-
173
- let status = Command :: new ( exec_path)
174
- . args ( args)
29
+ let status = Command :: new ( opts. executable )
30
+ . args ( opts. child_arguments )
175
31
. env_clear ( )
176
- . envs ( vars )
177
- . stdout ( if let Some ( stdout_file) = stdout_file_raw {
32
+ . envs ( opts . child_environment )
33
+ . stdout ( if let Some ( stdout_file) = opts . stdout_file {
178
34
OpenOptions :: new ( )
179
35
. create ( true )
180
36
. truncate ( true )
@@ -185,7 +41,7 @@ fn main() {
185
41
} else {
186
42
Stdio :: inherit ( )
187
43
} )
188
- . stderr ( if let Some ( stderr_file) = stderr_file_raw {
44
+ . stderr ( if let Some ( stderr_file) = opts . stderr_file {
189
45
OpenOptions :: new ( )
190
46
. create ( true )
191
47
. truncate ( true )
@@ -200,14 +56,14 @@ fn main() {
200
56
. expect ( "process wrapper error: failed to spawn child process" ) ;
201
57
202
58
if status. success ( ) {
203
- if let Some ( tf) = touch_file_raw {
59
+ if let Some ( tf) = opts . touch_file {
204
60
OpenOptions :: new ( )
205
61
. create ( true )
206
62
. write ( true )
207
63
. open ( tf)
208
64
. expect ( "process wrapper error: failed to create touch file" ) ;
209
65
}
210
- if let Some ( ( copy_source, copy_dest) ) = copy_output {
66
+ if let Some ( ( copy_source, copy_dest) ) = opts . copy_output {
211
67
copy ( & copy_source, & copy_dest) . unwrap_or_else ( |_| {
212
68
panic ! (
213
69
"process wrapper error: failed to copy {} into {}" ,
0 commit comments