1use std::path::Path;
4use std::process::Command;
5
6use crate::{Error, require};
7
8pub fn cmd(dir: &Path, args: &[&str]) -> Result<String, Error> {
10 cmd_with_env(dir, args, &[])
11}
12
13pub fn cmd_with_env(dir: &Path, args: &[&str], env: &[(&str, &str)]) -> Result<String, Error> {
18 require("git")?;
19
20 let has_askpass = env.iter().any(|(k, _)| *k == "GIT_ASKPASS");
21
22 let mut command = Command::new("git");
23 if has_askpass {
24 command.args(["-c", "credential.helper="]);
25 }
26 command.args(args).current_dir(dir);
27 for (k, v) in env {
28 command.env(k, v);
29 }
30 let output = command.output()?;
31
32 if !output.status.success() {
33 let stderr = String::from_utf8_lossy(&output.stderr).to_string();
34 return Err(Error::CommandFailed {
35 cmd: format!("git {}", args.first().unwrap_or(&"")),
36 detail: stderr,
37 });
38 }
39
40 Ok(String::from_utf8_lossy(&output.stdout).to_string())
41}
42
43pub fn clone_shallow(url: &str, dest: &Path, branch: &str) -> Result<(), Error> {
45 clone_shallow_with_env(url, dest, branch, &[])
46}
47
48pub fn clone_shallow_with_env(
50 url: &str,
51 dest: &Path,
52 branch: &str,
53 env: &[(&str, &str)],
54) -> Result<(), Error> {
55 require("git")?;
56
57 let has_askpass = env.iter().any(|(k, _)| *k == "GIT_ASKPASS");
58
59 let mut command = Command::new("git");
60 if has_askpass {
61 command.args(["-c", "credential.helper="]);
62 }
63 command.args([
64 "clone",
65 "--depth",
66 "1",
67 "--branch",
68 branch,
69 url,
70 &dest.to_string_lossy(),
71 ]);
72 for (k, v) in env {
73 command.env(k, v);
74 }
75 let output = command.output()?;
76
77 if !output.status.success() {
78 let stderr = String::from_utf8_lossy(&output.stderr).to_string();
79 return Err(Error::CommandFailed {
80 cmd: "git clone".to_string(),
81 detail: stderr,
82 });
83 }
84
85 Ok(())
86}
87
88pub fn clone_local(source: &Path, dest: &Path, branch: &str) -> Result<(), Error> {
90 require("git")?;
91
92 let output = Command::new("git")
93 .args([
94 "clone",
95 "--branch",
96 branch,
97 "--single-branch",
98 &source.to_string_lossy(),
99 &dest.to_string_lossy(),
100 ])
101 .output()?;
102
103 if !output.status.success() {
104 let stderr = String::from_utf8_lossy(&output.stderr).to_string();
105 return Err(Error::CommandFailed {
106 cmd: "git clone (local)".to_string(),
107 detail: stderr,
108 });
109 }
110
111 Ok(())
112}
113
114pub fn checkout_new_branch(dir: &Path, branch: &str) -> Result<(), Error> {
116 cmd(dir, &["checkout", "-b", branch])?;
117 Ok(())
118}
119
120pub fn config_set(dir: &Path, key: &str, value: &str) -> Result<(), Error> {
122 cmd(dir, &["config", key, value])?;
123 Ok(())
124}