@@ -10,9 +10,10 @@ use std::{
10
10
11
11
use bstr:: { BString , ByteSlice } ;
12
12
13
- /// A structure to keep settings to use when invoking a command via [`spawn()`][Prepare::spawn()], after creating it with [`prepare()`].
13
+ /// A structure to keep settings to use when invoking a command via [`spawn()`][Prepare::spawn()],
14
+ /// after creating it with [`prepare()`].
14
15
pub struct Prepare {
15
- /// The command to invoke ( either with or without shell depending on `use_shell`.
16
+ /// The command to invoke, either directly or with a shell depending on `use_shell`.
16
17
pub command : OsString ,
17
18
/// Additional information to be passed to the spawned command.
18
19
pub context : Option < Context > ,
@@ -22,29 +23,29 @@ pub struct Prepare {
22
23
pub stdout : std:: process:: Stdio ,
23
24
/// The way standard error is configured.
24
25
pub stderr : std:: process:: Stdio ,
25
- /// The arguments to pass to the spawned process.
26
+ /// The arguments to pass to the process being spawned .
26
27
pub args : Vec < OsString > ,
27
- /// environment variables to set in the spawned process.
28
+ /// Environment variables to set for the spawned process.
28
29
pub env : Vec < ( OsString , OsString ) > ,
29
30
/// If `true`, we will use `shell_program` or `sh` to execute the `command`.
30
31
pub use_shell : bool ,
31
- /// If `true`, `command` is assumed to be a command or path to the program to execute, and it will be shell-quoted
32
- /// to assure it will be executed as is and without splitting across whitespace.
32
+ /// If `true`, `command` is assumed to be a command or path to the program to execute, and it
33
+ /// will be shell-quoted to assure it will be executed as is and without splitting across
34
+ /// whitespace.
33
35
pub quote_command : bool ,
34
36
/// The name or path to the shell program to use instead of `sh`.
35
37
pub shell_program : Option < OsString > ,
36
- /// If `true` (default `true` on windows and `false` everywhere else)
37
- /// we will see if it's safe to manually invoke `command` after splitting
38
- /// its arguments as a shell would do.
39
- /// Note that outside of windows, it's generally not advisable as this
40
- /// removes support for literal shell scripts with shell-builtins.
38
+ /// If `true` (default `true` on Windows and `false` everywhere else) we will see if it's safe
39
+ /// to manually invoke `command` after splitting its arguments as a shell would do.
41
40
///
42
- /// This mimics the behaviour we see with `git` on windows, which also
43
- /// won't invoke the shell there at all .
41
+ /// Note that outside of Windows, it's generally not advisable as this removes support for
42
+ /// literal shell scripts with shell-builtins .
44
43
///
45
- /// Only effective if `use_shell` is `true` as well, as the shell will
46
- /// be used as a fallback if it's not possible to split arguments as
47
- /// the command-line contains 'scripting'.
44
+ /// This mimics the behaviour we see with `git` on Windows, which also won't invoke the shell
45
+ /// there at all.
46
+ ///
47
+ /// Only effective if `use_shell` is `true` as well, as the shell will be used as a fallback if
48
+ /// it's not possible to split arguments as the command-line contains 'scripting'.
48
49
pub allow_manual_arg_splitting : bool ,
49
50
}
50
51
@@ -96,81 +97,119 @@ mod prepare {
96
97
97
98
/// Builder
98
99
impl Prepare {
99
- /// If called, the command will be checked for characters that are typical for shell scripts, and if found will use `sh` to execute it
100
- /// or whatever is set as [`with_shell_program()`](Self::with_shell_program()).
100
+ /// If called, the command will be checked for characters that are typical for shell
101
+ /// scripts, and if found will use `sh` to execute it or whatever is set as
102
+ /// [`with_shell_program()`](Self::with_shell_program()).
103
+ ///
101
104
/// If the command isn't valid UTF-8, a shell will always be used.
102
105
///
103
- /// If a shell is used, then arguments given here with [arg()](Self::arg) or [args()](Self::args) will be substituted via `"$@"` if it's not
104
- /// already present in the command.
106
+ /// If a shell is used, then arguments given here with [arg()](Self::arg) or
107
+ /// [args()](Self::args) will be substituted via `"$@"` if it's not already present in the
108
+ /// command.
109
+ ///
105
110
///
106
- /// If this method is not called, commands are always executed verbatim, without the use of a shell.
111
+ /// The [`command_may_be_shell_script_allow_manual_argument_splitting()`](Self::command_may_be_shell_script_allow_manual_argument_splitting())
112
+ /// and [`command_may_be_shell_script_disallow_manual_argument_splitting()`](Self::command_may_be_shell_script_disallow_manual_argument_splitting())
113
+ /// methods also call this method.
114
+ ///
115
+ /// If neither this method nor [`with_shell()`](Self::with_shell()) is called, commands are
116
+ /// always executed verbatim and directly, without the use of a shell.
107
117
pub fn command_may_be_shell_script ( mut self ) -> Self {
108
118
self . use_shell = self . command . to_str ( ) . map_or ( true , |cmd| {
109
119
cmd. as_bytes ( ) . find_byteset ( b"|&;<>()$`\\ \" ' \t \n *?[#~=%" ) . is_some ( )
110
120
} ) ;
111
121
self
112
122
}
113
123
114
- /// If called, unconditionally use a shell to execute the command and its arguments, and `sh` to execute it,
115
- /// or whatever is set as [`with_shell_program()`](Self::with_shell_program()).
124
+ /// If called, unconditionally use a shell to execute the command and its arguments.
125
+ ///
126
+ /// This uses `sh` to execute it, or whatever is set as
127
+ /// [`with_shell_program()`](Self::with_shell_program()).
116
128
///
117
- /// If a shell is used, then arguments given here with [arg()](Self::arg) or [args()](Self::args) will be substituted via `"$@"` if it's not
118
- /// already present in the command.
129
+ /// Arguments given here with [arg()](Self::arg) or [args()](Self::args) will be
130
+ /// substituted via `"$@"` if it's not already present in the command.
119
131
///
120
- /// If this method is not called, commands are always executed verbatim, without the use of a shell.
132
+ /// If neither this method nor
133
+ /// [`command_may_be_shell_script()`](Self::command_may_be_shell_script()) is called,
134
+ /// commands are always executed verbatim and directly, without the use of a shell. (But
135
+ /// see [`command_may_be_shell_script()`](Self::command_may_be_shell_script()) on other
136
+ /// methods that call that method.)
121
137
pub fn with_shell ( mut self ) -> Self {
122
138
self . use_shell = true ;
123
139
self
124
140
}
125
141
126
- /// If [`with_shell()`](Self::with_shell()) is set, then quote the command to assure its path is left intact.
142
+ /// Quote the command if it is run in a shell, so its path is left intact.
127
143
///
128
- /// Note that this should not be used if the command is a script - quoting is only the right choice if it's known to be a program path.
144
+ /// This is only meaningful if the command has been arranged to run in a shell, either
145
+ /// unconditionally with [`with_shell()`](Self::with_shell()), or conditionally with
146
+ /// [`command_may_be_shell_script()`](Self::command_may_be_shell_script()).
147
+ ///
148
+ /// Note that this should not be used if the command is a script - quoting is only the
149
+ /// right choice if it's known to be a program path.
150
+ ///
151
+ /// Note also that this does not affect arguments passed with [arg()](Self::arg) or
152
+ /// [args()](Self::args), which do not have to be quoted by the *caller* because they are
153
+ /// passed as `"$@"` positional parameters (`"$1"`, `"$2"`, and so on).
129
154
pub fn with_quoted_command ( mut self ) -> Self {
130
155
self . quote_command = true ;
131
156
self
132
157
}
133
158
134
- /// Set the name or path to the shell `program` to use if a shell is to be used, to avoid using the default shell which is `sh`.
159
+ /// Set the name or path to the shell `program` to use if a shell is to be used, to avoid
160
+ /// using the default shell which is `sh`.
161
+ ///
162
+ /// Note that that shells that are not Bourne-style cannot be expected to work correctly,
163
+ /// because POSIX shell syntax is assumed when searching for and conditionally adding
164
+ /// `"$@"` to receive arguments, where applicable (and in the behaviour of
165
+ /// [`with_quoted_command()`](Self::with_quoted_command()), if called).
135
166
pub fn with_shell_program ( mut self , program : impl Into < OsString > ) -> Self {
136
167
self . shell_program = Some ( program. into ( ) ) ;
137
168
self
138
169
}
139
170
140
171
/// Unconditionally turn off using the shell when spawning the command.
141
- /// Note that not using the shell is the default so an effective use of this method
142
- /// is some time after [`command_may_be_shell_script()`](Prepare::command_may_be_shell_script()) was called.
172
+ ///
173
+ /// Note that not using the shell is the default. So an effective use of this method
174
+ /// is some time after [`command_may_be_shell_script()`](Self::command_may_be_shell_script())
175
+ /// or [`with_shell()`](Self::with_shell()) was called.
143
176
pub fn without_shell ( mut self ) -> Self {
144
177
self . use_shell = false ;
145
178
self
146
179
}
147
180
148
181
/// Set additional `ctx` to be used when spawning the process.
149
182
///
150
- /// Note that this is a must for most kind of commands that `git` usually spawns,
151
- /// as at least they need to know the correct `git` repository to function.
183
+ /// Note that this is a must for most kind of commands that `git` usually spawns, as at
184
+ /// least they need to know the correct Git repository to function.
152
185
pub fn with_context ( mut self , ctx : Context ) -> Self {
153
186
self . context = Some ( ctx) ;
154
187
self
155
188
}
156
189
157
- /// Like [`command_may_be_shell_script()`](Prepare::command_may_be_shell_script()), but try to split arguments by hand if this can be safely done without a shell.
190
+ /// Like [`command_may_be_shell_script()`](Self::command_may_be_shell_script()), but try to
191
+ /// split arguments by hand if this can be safely done without a shell.
192
+ ///
193
+ /// This is useful on platforms where spawning processes is slow, or where many processes
194
+ /// have to be spawned in a row which should be sped up. Manual argument splitting is
195
+ /// enabled by default on Windows only.
158
196
///
159
- /// This is useful on platforms where spawning processes is slow, or where many processes have to be spawned in a raw which should be sped up.
160
- /// Manual argument splitting is enabled by default on Windows only.
197
+ /// Note that this does *not* check for the use of possible shell builtins. Commands may
198
+ /// fail or behave differently if they are available as shell builtins and no corresponding
199
+ /// external command exists, or the external command behaves differently.
161
200
pub fn command_may_be_shell_script_allow_manual_argument_splitting ( mut self ) -> Self {
162
201
self . allow_manual_arg_splitting = true ;
163
202
self . command_may_be_shell_script ( )
164
203
}
165
204
166
- /// Like [`command_may_be_shell_script()`](Prepare ::command_may_be_shell_script()), but don't allow to bypass the shell even if manual argument splitting
167
- /// can be performed safely.
205
+ /// Like [`command_may_be_shell_script()`](Self ::command_may_be_shell_script()), but don't
206
+ /// allow to bypass the shell even if manual argument splitting can be performed safely.
168
207
pub fn command_may_be_shell_script_disallow_manual_argument_splitting ( mut self ) -> Self {
169
208
self . allow_manual_arg_splitting = false ;
170
209
self . command_may_be_shell_script ( )
171
210
}
172
211
173
- /// Configure the process to use `stdio` for _stdin .
212
+ /// Configure the process to use `stdio` for _stdin_ .
174
213
pub fn stdin ( mut self , stdio : Stdio ) -> Self {
175
214
self . stdin = stdio;
176
215
self
@@ -180,7 +219,7 @@ mod prepare {
180
219
self . stdout = stdio;
181
220
self
182
221
}
183
- /// Configure the process to use `stdio` for _stderr .
222
+ /// Configure the process to use `stdio` for _stderr_ .
184
223
pub fn stderr ( mut self , stdio : Stdio ) -> Self {
185
224
self . stderr = stdio;
186
225
self
@@ -256,7 +295,7 @@ mod prepare {
256
295
prep. command . push ( " \" $@\" " ) ;
257
296
} else {
258
297
gix_trace:: debug!(
259
- "Will not add '$@ ' to '{:?}' as it seems to contain it already" ,
298
+ "Will not add '\" $@ \" ' to '{:?}' as it seems to contain '$@' already" ,
260
299
prep. command
261
300
) ;
262
301
}
0 commit comments