@@ -10,9 +10,10 @@ use std::{
1010
1111use bstr:: { BString , ByteSlice } ;
1212
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()`].
1415pub 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`.
1617 pub command : OsString ,
1718 /// Additional information to be passed to the spawned command.
1819 pub context : Option < Context > ,
@@ -22,29 +23,29 @@ pub struct Prepare {
2223 pub stdout : std:: process:: Stdio ,
2324 /// The way standard error is configured.
2425 pub stderr : std:: process:: Stdio ,
25- /// The arguments to pass to the spawned process.
26+ /// The arguments to pass to the process being spawned .
2627 pub args : Vec < OsString > ,
27- /// environment variables to set in the spawned process.
28+ /// Environment variables to set for the spawned process.
2829 pub env : Vec < ( OsString , OsString ) > ,
2930 /// If `true`, we will use `shell_program` or `sh` to execute the `command`.
3031 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.
3335 pub quote_command : bool ,
3436 /// The name or path to the shell program to use instead of `sh`.
3537 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.
4140 ///
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 .
4443 ///
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'.
4849 pub allow_manual_arg_splitting : bool ,
4950}
5051
@@ -96,81 +97,119 @@ mod prepare {
9697
9798 /// Builder
9899 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+ ///
101104 /// If the command isn't valid UTF-8, a shell will always be used.
102105 ///
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+ ///
105110 ///
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.
107117 pub fn command_may_be_shell_script ( mut self ) -> Self {
108118 self . use_shell = self . command . to_str ( ) . map_or ( true , |cmd| {
109119 cmd. as_bytes ( ) . find_byteset ( b"|&;<>()$`\\ \" ' \t \n *?[#~=%" ) . is_some ( )
110120 } ) ;
111121 self
112122 }
113123
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()).
116128 ///
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.
119131 ///
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.)
121137 pub fn with_shell ( mut self ) -> Self {
122138 self . use_shell = true ;
123139 self
124140 }
125141
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.
127143 ///
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).
129154 pub fn with_quoted_command ( mut self ) -> Self {
130155 self . quote_command = true ;
131156 self
132157 }
133158
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).
135166 pub fn with_shell_program ( mut self , program : impl Into < OsString > ) -> Self {
136167 self . shell_program = Some ( program. into ( ) ) ;
137168 self
138169 }
139170
140171 /// 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.
143176 pub fn without_shell ( mut self ) -> Self {
144177 self . use_shell = false ;
145178 self
146179 }
147180
148181 /// Set additional `ctx` to be used when spawning the process.
149182 ///
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.
152185 pub fn with_context ( mut self , ctx : Context ) -> Self {
153186 self . context = Some ( ctx) ;
154187 self
155188 }
156189
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.
158196 ///
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.
161200 pub fn command_may_be_shell_script_allow_manual_argument_splitting ( mut self ) -> Self {
162201 self . allow_manual_arg_splitting = true ;
163202 self . command_may_be_shell_script ( )
164203 }
165204
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.
168207 pub fn command_may_be_shell_script_disallow_manual_argument_splitting ( mut self ) -> Self {
169208 self . allow_manual_arg_splitting = false ;
170209 self . command_may_be_shell_script ( )
171210 }
172211
173- /// Configure the process to use `stdio` for _stdin .
212+ /// Configure the process to use `stdio` for _stdin_ .
174213 pub fn stdin ( mut self , stdio : Stdio ) -> Self {
175214 self . stdin = stdio;
176215 self
@@ -180,7 +219,7 @@ mod prepare {
180219 self . stdout = stdio;
181220 self
182221 }
183- /// Configure the process to use `stdio` for _stderr .
222+ /// Configure the process to use `stdio` for _stderr_ .
184223 pub fn stderr ( mut self , stdio : Stdio ) -> Self {
185224 self . stderr = stdio;
186225 self
@@ -256,7 +295,7 @@ mod prepare {
256295 prep. command . push ( " \" $@\" " ) ;
257296 } else {
258297 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" ,
260299 prep. command
261300 ) ;
262301 }
0 commit comments