···11use std::ffi::OsStr;2233+pub trait CommandExt {44+ /// Insert or update an environment variable mapping if, and only if,55+ /// `val` is [`Some`].66+ fn option_env<K, V>(&mut self, key: K, val: Option<V>) -> &mut Self77+ where88+ K: AsRef<OsStr>,99+ V: AsRef<OsStr>;1010+1111+ /// Append an argument if, and only if, `arg` is [`Some`].1212+ fn option_arg<V>(&mut self, arg: Option<V>) -> &mut Self1313+ where1414+ V: AsRef<OsStr>;1515+}1616+1717+impl<T: SetEnv + SetArg> CommandExt for T {1818+ fn option_env<K, V>(&mut self, key: K, val: Option<V>) -> &mut Self1919+ where2020+ K: AsRef<OsStr>,2121+ V: AsRef<OsStr>,2222+ {2323+ if let Some(val) = val {2424+ self.env(key, val);2525+ }2626+ self2727+ }2828+2929+ fn option_arg<V>(&mut self, arg: Option<V>) -> &mut Self3030+ where3131+ V: AsRef<OsStr>,3232+ {3333+ if let Some(arg) = arg {3434+ self.arg(arg);3535+ }3636+ self3737+ }3838+}3939+340trait SetEnv {441 fn env<K, V>(&mut self, key: K, val: V) -> &mut Self542 where···6124impl_set_env!(std::process::Command);6225impl_set_env!(tokio::process::Command);63266464-pub trait SetOptionEnv {6565- /// Inserts or updates an environment variable mapping if, and only if,6666- /// `val` is [`Some`].6767- fn option_env<K, V>(&mut self, key: K, val: Option<V>) -> &mut Self6868- where6969- K: AsRef<OsStr>,7070- V: AsRef<OsStr>;7171-}7272-7373-impl<T: SetEnv> SetOptionEnv for T {7474- fn option_env<K, V>(&mut self, key: K, val: Option<V>) -> &mut Self7575- where7676- K: AsRef<OsStr>,7777- V: AsRef<OsStr>,7878- {7979- if let Some(val) = val {8080- self.env(key, val);8181- }8282- self8383- }8484-}8585-8627trait SetArg {8728 fn arg<V>(&mut self, arg: V) -> &mut Self8829 where···8368impl_set_arg!(std::process::Command);8469impl_set_arg!(tokio::process::Command);85708686-pub trait SetOptionArg {8787- fn option_arg<V>(&mut self, arg: Option<V>) -> &mut Self8888- where8989- V: AsRef<OsStr>;9090-}9191-9292-impl<T: SetArg> SetOptionArg for T {9393- fn option_arg<V>(&mut self, arg: Option<V>) -> &mut Self9494- where9595- V: AsRef<OsStr>,9696- {9797- if let Some(arg) = arg {9898- self.arg(arg);9999- }100100- self101101- }102102-}103103-104104-pub trait TraceProcessCompletion {7171+pub trait ChildExt {10572 fn wait_with_completion_trace(self) -> impl Future<Output = ()>;10673}10774108108-impl TraceProcessCompletion for tokio::process::Child {7575+impl ChildExt for tokio::process::Child {10976 async fn wait_with_completion_trace(self) {11077 use std::process::Output;11178···116119 Err(error) => {117120 tracing::error!(?error);118121 }119119- }120120- }121121-}122122-123123-pub async fn await_child(child: tokio::process::Child) -> bool {124124- match child.wait_with_output().await {125125- Ok(output) if output.status.success() => {126126- if !output.stderr.is_empty() {127127- let stderr = std::str::from_utf8(&output.stderr).unwrap_or("non-utf8 in stderr");128128- tracing::warn!("git child process completed with errors. stderr:\n{stderr}");129129- }130130- true131131- }132132- Ok(output) => {133133- let status = output.status;134134- if let Ok(stderr) = std::str::from_utf8(&output.stderr) {135135- tracing::error!(136136- ?status,137137- "error waiting for git child process. stderr:\n{stderr}"138138- )139139- } else {140140- tracing::error!(141141- ?status,142142- "error waiting for git child process. stderr:\n{:?}\n{}",143143- &output.stderr,144144- String::from_utf8_lossy(&output.stderr)145145- )146146- }147147- false148148- }149149- Err(error) => {150150- tracing::error!(?error);151151- false152122 }153123 }154124}
+1-2
crates/gordian-knot/src/model/repository.rs
···2929use serde::Deserialize;30303131use super::Knot;3232-use crate::command::SetOptionArg as _;3333-use crate::command::SetOptionEnv as _;3232+use crate::command::CommandExt as _;3433use crate::model::convert;3534use crate::model::errors;3635use crate::model::nicediff;
···1212use tokio::net::unix::pipe::Sender;1313use tokio::net::unix::pipe::pipe as async_pipe;14141515-use crate::command::SetOptionEnv as _;1616-use crate::command::TraceProcessCompletion as _;1515+use crate::command::ChildExt as _;1616+use crate::command::CommandExt as _;1717use crate::extractors::GitProtocol;1818use crate::extractors::request_id::RequestId;1919use crate::model::Knot;
···88use tokio::io::AsyncWriteExt as _;99use tokio::net::unix::pipe::Sender;10101111-use crate::command::SetOptionEnv as _;1212-use crate::command::TraceProcessCompletion as _;1111+use crate::command::ChildExt as _;1212+use crate::command::CommandExt as _;1313use crate::extractors::GitProtocol;1414use crate::extractors::request_id::RequestId;1515use crate::model::Knot;
+2-2
crates/gordian-knot/src/public/git/upload_pack.rs
···1111use tokio::net::unix::pipe::Sender;1212use tokio::net::unix::pipe::pipe as async_pipe;13131414-use crate::command::SetOptionEnv as _;1515-use crate::command::TraceProcessCompletion;1414+use crate::command::ChildExt;1515+use crate::command::CommandExt as _;1616use crate::extractors::GitProtocol;1717use crate::extractors::request_id::RequestId;1818use crate::model::Knot;