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
18pub 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 let dir = std::str::from_utf8(&output.stdout)?.trim();
33 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}