summaryrefslogtreecommitdiffstats
path: root/vendor/gix-command/src/lib.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
commit10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch)
treebdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/gix-command/src/lib.rs
parentReleasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff)
downloadrustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz
rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/gix-command/src/lib.rs')
-rw-r--r--vendor/gix-command/src/lib.rs141
1 files changed, 141 insertions, 0 deletions
diff --git a/vendor/gix-command/src/lib.rs b/vendor/gix-command/src/lib.rs
new file mode 100644
index 000000000..9e662b016
--- /dev/null
+++ b/vendor/gix-command/src/lib.rs
@@ -0,0 +1,141 @@
+//! Launch commands very similarly to `Command`, but with `git` specific capabilities and adjustments.
+#![deny(rust_2018_idioms, missing_docs)]
+#![forbid(unsafe_code)]
+
+use std::ffi::OsString;
+
+/// A structure to keep settings to use when invoking a command via [`spawn()`][Prepare::spawn()], after creating it with [`prepare()`].
+pub struct Prepare {
+ /// The command to invoke (either with or without shell depending on `use_shell`.
+ pub command: OsString,
+ /// The way standard input is configured.
+ pub stdin: std::process::Stdio,
+ /// The way standard output is configured.
+ pub stdout: std::process::Stdio,
+ /// The way standard error is configured.
+ pub stderr: std::process::Stdio,
+ /// The arguments to pass to the spawned process.
+ pub args: Vec<OsString>,
+ /// environment variables to set in the spawned process.
+ pub env: Vec<(OsString, OsString)>,
+ /// If `true`, we will use `sh` to execute the `command`.
+ pub use_shell: bool,
+}
+
+mod prepare {
+ use std::{
+ ffi::OsString,
+ process::{Command, Stdio},
+ };
+
+ use bstr::ByteSlice;
+
+ use crate::Prepare;
+
+ /// Builder
+ impl Prepare {
+ /// If called, the command will not be executed directly, but with `sh`.
+ ///
+ /// This also allows to pass shell scripts as command, or use commands that contain arguments which are subsequently
+ /// parsed by `sh`.
+ pub fn with_shell(mut self) -> Self {
+ self.use_shell = self.command.to_str().map_or(true, |cmd| {
+ cmd.as_bytes().find_byteset(b"|&;<>()$`\\\"' \t\n*?[#~=%").is_some()
+ });
+ self
+ }
+
+ /// Unconditionally turn off using the shell when spawning the command.
+ /// Note that not using the shell is the default so an effective use of this method
+ /// is some time after [`with_shell()`][Prepare::with_shell()] was called.
+ pub fn without_shell(mut self) -> Self {
+ self.use_shell = false;
+ self
+ }
+
+ /// Configure the process to use `stdio` for _stdin.
+ pub fn stdin(mut self, stdio: Stdio) -> Self {
+ self.stdin = stdio;
+ self
+ }
+ /// Configure the process to use `stdio` for _stdout_.
+ pub fn stdout(mut self, stdio: Stdio) -> Self {
+ self.stdout = stdio;
+ self
+ }
+ /// Configure the process to use `stdio` for _stderr.
+ pub fn stderr(mut self, stdio: Stdio) -> Self {
+ self.stderr = stdio;
+ self
+ }
+
+ /// Add `arg` to the list of arguments to call the command with.
+ pub fn arg(mut self, arg: impl Into<OsString>) -> Self {
+ self.args.push(arg.into());
+ self
+ }
+
+ /// Add `args` to the list of arguments to call the command with.
+ pub fn args(mut self, args: impl IntoIterator<Item = impl Into<OsString>>) -> Self {
+ self.args
+ .append(&mut args.into_iter().map(Into::into).collect::<Vec<_>>());
+ self
+ }
+
+ /// Add `key` with `value` to the environment of the spawned command.
+ pub fn env(mut self, key: impl Into<OsString>, value: impl Into<OsString>) -> Self {
+ self.env.push((key.into(), value.into()));
+ self
+ }
+ }
+
+ /// Finalization
+ impl Prepare {
+ /// Spawn the command as configured.
+ pub fn spawn(self) -> std::io::Result<std::process::Child> {
+ Command::from(self).spawn()
+ }
+ }
+
+ impl From<Prepare> for Command {
+ fn from(mut prep: Prepare) -> Command {
+ let mut cmd = if prep.use_shell {
+ let mut cmd = Command::new(if cfg!(windows) { "sh" } else { "/bin/sh" });
+ cmd.arg("-c");
+ if !prep.args.is_empty() {
+ prep.command.push(" \"$@\"")
+ }
+ cmd.arg(prep.command);
+ cmd.arg("--");
+ cmd
+ } else {
+ Command::new(prep.command)
+ };
+ cmd.stdin(prep.stdin)
+ .stdout(prep.stdout)
+ .stderr(prep.stderr)
+ .envs(prep.env)
+ .args(prep.args);
+ cmd
+ }
+ }
+}
+
+/// Prepare `cmd` for [spawning][std::process::Command::spawn()] by configuring it with various builder methods.
+///
+/// Note that the default IO is configured for typical API usage, that is
+///
+/// - `stdin` is null to prevent blocking unexpectedly on consumption of stdin
+/// - `stdout` is captured for consumption by the caller
+/// - `stderr` is inherited to allow the command to provide context to the user
+pub fn prepare(cmd: impl Into<OsString>) -> Prepare {
+ Prepare {
+ command: cmd.into(),
+ stdin: std::process::Stdio::null(),
+ stdout: std::process::Stdio::piped(),
+ stderr: std::process::Stdio::inherit(),
+ args: Vec::new(),
+ env: Vec::new(),
+ use_shell: false,
+ }
+}