Skip to main content

git_valet/
git_helpers.rs

1//! Git command wrappers for both the main repo and the valet bare repo.
2
3use anyhow::{Context, Result, bail};
4use std::path::{Path, PathBuf};
5use std::process::{Command, Output};
6
7use crate::config::ValetConfig;
8
9/// Converts a Path to a UTF-8 string, with a descriptive error on failure.
10pub fn path_str(path: &Path) -> Result<&str> {
11    path.to_str().with_context(|| format!("Path contains invalid UTF-8: {}", path.display()))
12}
13
14/// Runs a git command in the main repo and checks exit status
15pub fn git(args: &[&str], work_tree: &Path) -> Result<Output> {
16    let out = Command::new("git")
17        .args(args)
18        .current_dir(work_tree)
19        .output()
20        .context("Failed to execute git")?;
21    if !out.status.success() {
22        let stderr = String::from_utf8_lossy(&out.stderr);
23        bail!("git {} failed: {}", args.first().unwrap_or(&""), stderr.trim());
24    }
25    Ok(out)
26}
27
28/// Runs a git command against the valet bare repo + work-tree (does not check exit status)
29pub fn sgit(args: &[&str], config: &ValetConfig) -> Result<Output> {
30    let out = Command::new("git")
31        .arg("--git-dir")
32        .arg(&config.bare_path)
33        .arg("--work-tree")
34        .arg(&config.work_tree)
35        .args(args)
36        .output()
37        .context("Failed to execute valet git")?;
38    Ok(out)
39}
40
41/// Returns the stdout of a git command as a String
42pub fn git_output(args: &[&str], work_tree: &Path) -> Result<String> {
43    let out = git(args, work_tree)?;
44    Ok(String::from_utf8_lossy(&out.stdout).trim().to_string())
45}
46
47/// Returns the origin remote URL of the current repo
48pub fn get_origin(work_tree: &Path) -> Result<String> {
49    git_output(&["remote", "get-url", "origin"], work_tree)
50        .context("Could not get remote origin. Does this repo have an 'origin' remote?")
51}
52
53/// Returns the absolute path of the current repo's .git directory
54pub fn get_git_dir(work_tree: &Path) -> Result<PathBuf> {
55    let s = git_output(&["rev-parse", "--absolute-git-dir"], work_tree)?;
56    Ok(PathBuf::from(s))
57}
58
59/// Returns the root of the current git repo
60pub fn get_work_tree() -> Result<PathBuf> {
61    let out = Command::new("git")
62        .args(["rev-parse", "--show-toplevel"])
63        .output()
64        .context("Not inside a git repository")?;
65    let s = String::from_utf8_lossy(&out.stdout).trim().to_string();
66    if s.is_empty() {
67        bail!("Not inside a git repository");
68    }
69    Ok(PathBuf::from(s))
70}
71
72/// Loads the valet config from the current repo
73pub fn load_config() -> Result<ValetConfig> {
74    let work_tree = get_work_tree()?;
75    let origin = get_origin(&work_tree)?;
76    crate::config::load(&origin)
77}