//! Wraps invocation of the `git` subprocess, mirroring the pattern used by //! the sibling Go implementation (and Gitea itself, in modules/git/gitcmd): //! a small builder around a process-spawning API with a fixed baseline //! environment, used both for one-shot commands and for long-lived piped //! subprocesses wired into a network transport. use std::path::Path; use std::process::Stdio; use anyhow::{bail, Result}; use tokio::process::{Child, Command}; /// baseline environment variables always set for git subprocesses, on top /// of whatever the process already inherited, to keep behavior deterministic /// and free of surprise user/system git config interference. fn command(args: &[&str]) -> Command { let mut cmd = Command::new("git"); cmd.args(args); cmd.env("GIT_CONFIG_NOSYSTEM", "1"); cmd.env("GIT_TERMINAL_PROMPT", "0"); cmd.env("LC_ALL", "C"); cmd } /// Runs a git command to completion and returns its stdout, failing on a /// non-zero exit status. pub async fn run_captured(dir: &Path, args: &[&str]) -> Result> { let output = command(args).current_dir(dir).output().await?; if !output.status.success() { bail!("git {args:?}: {}", String::from_utf8_lossy(&output.stderr)); } Ok(output.stdout) } /// Runs a git command to completion, discarding stdout, failing on a /// non-zero exit status. pub async fn run(dir: &Path, args: &[&str]) -> Result<()> { run_captured(dir, args).await.map(|_| ()) } /// Spawns a git command with stdin/stdout/stderr piped for interactive use /// (the smart-HTTP and SSH transports stream into/out of these directly). /// /// `dir` sets the working directory when present; when absent, callers are /// expected to pass any repo path as a plain argument instead (used by the /// SSH transport, mirroring the Go implementation's `cmd/serv.go`-style /// invocation of `git upload-pack ` without a chdir). pub fn spawn_piped(dir: Option<&Path>, args: &[&str], extra_env: &[(String, String)]) -> Result { let mut cmd = command(args); if let Some(dir) = dir { cmd.current_dir(dir); } cmd.stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped()); for (key, value) in extra_env { cmd.env(key, value); } Ok(cmd.spawn()?) }