1use std::{path::Path, process::Command};
4
5use clingwrap::runner::{CommandError, CommandRunner};
6
7pub fn is_git(dirname: &Path) -> bool {
9 dirname.exists() && git_head(dirname).is_ok()
10}
11
12pub fn git_head(dirname: &Path) -> Result<String, GitError> {
14 let stdout = git(&["rev-parse", "HEAD"], dirname)?;
15 let head = stdout.trim().into();
16 Ok(head)
17}
18
19pub fn git_is_clean(dirname: &Path) -> bool {
21 if let Ok(stdout) = git(&["status", "--short"], dirname) {
22 stdout.is_empty()
23 } else {
24 false }
26}
27
28fn git(args: &[&str], dirname: &Path) -> Result<String, GitError> {
30 let mut cmd = Command::new("git");
31 cmd.args(args).current_dir(dirname);
32
33 let mut runner = CommandRunner::new(cmd);
34 runner.capture_stdout();
35 runner.capture_stderr();
36 runner
37 .execute()
38 .map_err(GitError::Execute)
39 .map(|output| String::from_utf8_lossy(&output.stdout).into())
40}
41
42#[derive(Debug, thiserror::Error)]
44pub enum GitError {
45 #[error("failed to run git")]
47 Execute(#[source] CommandError),
48}