chj_rustbin/
whichgit.rs

1use std::{process::Command, str::Utf8Error};
2
3#[derive(Debug, thiserror::Error)]
4pub enum GitDirError {
5    #[error("Git does not seem to be available")]
6    NoGit,
7    #[error("can't decode Git path output as UTF-8")]
8    Utf8(#[from] Utf8Error),
9    #[error(
10        "Git exited with code {code} and error {:?}",
11        String::from_utf8_lossy(stderr)
12    )]
13    GitError { stderr: Vec<u8>, code: i32 },
14    #[error("expected a string from `git rev-parse --git-dir` ending with .git, but got: {0:?}")]
15    ExpectedDotGit(String),
16}
17
18/// Return None if cwd not in a Git repository, Some with the path if
19/// cwd is, and return an error if the path cannot be decoded as a
20/// string or Git is not available.
21pub fn git_working_dir() -> Result<Option<String>, GitDirError> {
22    let output = Command::new("git")
23        .args(&["rev-parse", "--git-dir"])
24        .output()
25        .map_err(|_| GitDirError::NoGit)?;
26
27    let code: i32 = output.status.code().unwrap_or(-1);
28
29    match code {
30        0 => {
31            // Path to git state dir
32            let dir = std::str::from_utf8(&output.stdout)?.trim();
33            // Make working dir path out of it
34            if let Some(wd) = dir.strip_suffix(".git") {
35                Ok(Some(wd.to_owned()))
36            } else {
37                Err(GitDirError::ExpectedDotGit(dir.to_owned()))
38            }
39        }
40        128 => Ok(None),
41        _ => Err(GitDirError::GitError {
42            stderr: output.stderr,
43            code,
44        }),
45    }
46}