1use std::io;
7use std::path::Path;
8use std::process::Command;
9
10pub mod attr;
11pub mod cat_file;
12pub mod config;
13pub mod diff_index;
14pub mod endpoint;
15pub mod path;
16pub mod pktline;
17pub mod refs;
18pub mod rev_list;
19pub mod scanner;
20
21pub use attr::AttrSet;
22pub use cat_file::{BlobContent, CatFileBatch, CatFileBatchCheck, CatFileHeader};
23pub use config::ConfigScope;
24pub use diff_index::{DiffEntry, diff_index};
25pub use endpoint::{EndpointError, derive_lfs_url, endpoint_for_remote};
26pub use path::{git_dir, lfs_dir};
27pub use rev_list::{RevListEntry, rev_list};
28pub use scanner::{PointerEntry, TreeBlob, scan_pointers, scan_tree, scan_tree_blobs};
29
30#[derive(Debug, thiserror::Error)]
31pub enum Error {
32 #[error("io error invoking git: {0}")]
33 Io(#[from] io::Error),
34 #[error("git: {0}")]
35 Failed(String),
36}
37
38pub(crate) fn run_git(cwd: &Path, args: &[&str]) -> Result<String, Error> {
40 let out = Command::new("git").arg("-C").arg(cwd).args(args).output()?;
41 if !out.status.success() {
42 return Err(Error::Failed(
43 String::from_utf8_lossy(&out.stderr).trim().to_owned(),
44 ));
45 }
46 Ok(String::from_utf8(out.stdout)
47 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?
48 .trim()
49 .to_owned())
50}
51
52#[cfg(test)]
53pub(crate) mod tests {
54 pub mod commit_helper {
58 use std::path::Path;
59 use std::process::Command;
60
61 use tempfile::TempDir;
62
63 pub fn init_repo() -> TempDir {
66 let tmp = TempDir::new().unwrap();
67 run(tmp.path(), &["init", "--quiet", "--initial-branch=main"]);
68 run(tmp.path(), &["config", "user.email", "test@example.com"]);
69 run(tmp.path(), &["config", "user.name", "test"]);
70 run(tmp.path(), &["config", "commit.gpgsign", "false"]);
73 tmp
74 }
75
76 pub fn commit_file(repo: &TempDir, path: &str, content: &[u8]) {
80 std::fs::write(repo.path().join(path), content).unwrap();
81 run(repo.path(), &["add", path]);
82 run(repo.path(), &["commit", "--quiet", "-m", &format!("add {path}")]);
83 }
84
85 pub fn head_oid(repo: &TempDir) -> String {
87 let out = Command::new("git")
88 .arg("-C")
89 .arg(repo.path())
90 .args(["rev-parse", "HEAD"])
91 .output()
92 .unwrap();
93 assert!(out.status.success());
94 String::from_utf8_lossy(&out.stdout).trim().to_owned()
95 }
96
97 fn run(cwd: &Path, args: &[&str]) {
98 let status = Command::new("git").arg("-C").arg(cwd).args(args).status().unwrap();
99 assert!(status.success(), "git {args:?} failed");
100 }
101 }
102}