1use std::io;
7use std::path::Path;
8use std::process::Command;
9
10pub mod aliases;
11pub mod attr;
12pub mod cat_file;
13pub mod config;
14pub mod diff_index;
15pub mod endpoint;
16pub mod extension;
17pub mod http_options;
18pub mod path;
19pub mod pktline;
20pub mod refs;
21pub mod rev_list;
22pub mod scanner;
23
24pub use attr::AttrSet;
25pub use cat_file::{BlobContent, CatFileBatch, CatFileBatchCheck, CatFileHeader};
26pub use config::ConfigScope;
27pub use diff_index::{DiffEntry, diff_index};
28pub use endpoint::{
29 EndpointError, EndpointInfo, SshInfo, derive_lfs_url, endpoint_for_remote, looks_like_url,
30 parse_ssh_url, resolve_endpoint,
31};
32pub use extension::{ExtensionConfig, list_extensions};
33pub use http_options::HttpOptions;
34pub use path::{git_dir, lfs_alternate_dirs, lfs_dir};
35pub use rev_list::{RevListEntry, rev_list, rev_list_with_args};
36pub use scanner::{
37 PointerEntry, TreeBlob, scan_pointers, scan_pointers_with_args, scan_tree, scan_tree_blobs,
38};
39
40#[derive(Debug, thiserror::Error)]
41pub enum Error {
42 #[error("io error invoking git: {0}")]
43 Io(#[from] io::Error),
44 #[error("git: {0}")]
45 Failed(String),
46}
47
48pub(crate) fn run_git(cwd: &Path, args: &[&str]) -> Result<String, Error> {
50 let out = Command::new("git").arg("-C").arg(cwd).args(args).output()?;
51 if !out.status.success() {
52 return Err(Error::Failed(
53 String::from_utf8_lossy(&out.stderr).trim().to_owned(),
54 ));
55 }
56 Ok(String::from_utf8(out.stdout)
57 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?
58 .trim()
59 .to_owned())
60}
61
62#[cfg(test)]
63pub(crate) mod tests {
64 pub mod commit_helper {
68 use std::path::Path;
69 use std::process::Command;
70
71 use tempfile::TempDir;
72
73 pub fn init_repo() -> TempDir {
76 let tmp = TempDir::new().unwrap();
77 run(tmp.path(), &["init", "--quiet", "--initial-branch=main"]);
78 run(tmp.path(), &["config", "user.email", "test@example.com"]);
79 run(tmp.path(), &["config", "user.name", "test"]);
80 run(tmp.path(), &["config", "commit.gpgsign", "false"]);
83 tmp
84 }
85
86 pub fn commit_file(repo: &TempDir, path: &str, content: &[u8]) {
90 std::fs::write(repo.path().join(path), content).unwrap();
91 run(repo.path(), &["add", path]);
92 run(
93 repo.path(),
94 &["commit", "--quiet", "-m", &format!("add {path}")],
95 );
96 }
97
98 pub fn head_oid(repo: &TempDir) -> String {
100 let out = Command::new("git")
101 .arg("-C")
102 .arg(repo.path())
103 .args(["rev-parse", "HEAD"])
104 .output()
105 .unwrap();
106 assert!(out.status.success());
107 String::from_utf8_lossy(&out.stdout).trim().to_owned()
108 }
109
110 fn run(cwd: &Path, args: &[&str]) {
111 let status = Command::new("git")
112 .arg("-C")
113 .arg(cwd)
114 .args(args)
115 .status()
116 .unwrap();
117 assert!(status.success(), "git {args:?} failed");
118 }
119 }
120}