evobench_tools/
git_ext.rs

1//! Extension trait for `GitWorkingDir` from the `run-git` crate
2
3use std::str::FromStr;
4
5use anyhow::{Result, bail};
6use run_git::git::GitWorkingDir;
7
8use crate::serde_types::{
9    git_branch_name::GitBranchName, git_reference::GitReference, git_url::GitUrl,
10};
11
12pub trait MoreGitWorkingDir {
13    fn get_url(&self, remote_name: &str) -> Result<String>;
14    fn set_url(&self, remote_name: &str, url: &GitUrl) -> Result<()>;
15    fn fetch_references<R: AsRef<GitReference>, Rs: AsRef<[R]>>(
16        &self,
17        remote_name: &str,
18        tags: bool,
19        references: Rs,
20        quiet: bool,
21    ) -> Result<()>;
22    fn get_current_branch(&self) -> Result<Option<GitBranchName>>;
23}
24
25impl MoreGitWorkingDir for GitWorkingDir {
26    fn get_url(&self, remote_name: &str) -> Result<String> {
27        self.git_stdout_string_trimmed(&["remote", "get-url", remote_name])
28    }
29
30    fn set_url(&self, remote_name: &str, url: &GitUrl) -> Result<()> {
31        if self.git(&["remote", "set-url", remote_name, url.as_str()], false)? {
32            Ok(())
33        } else {
34            bail!(
35                "got error status from `git remote set-url {remote_name:?} {:?}`",
36                url.as_str()
37            )
38        }
39    }
40
41    /// Fetch branches (XXX does it do that?), optionally tags, and
42    /// optional explicit commit ids (generally references?)
43    fn fetch_references<R: AsRef<GitReference>, Rs: AsRef<[R]>>(
44        &self,
45        remote_name: &str,
46        fetch_all_tags: bool,
47        references: Rs,
48        quiet: bool,
49    ) -> Result<()> {
50        let mut args = vec!["fetch", remote_name];
51        if fetch_all_tags {
52            args.push("--tags");
53        }
54        let rs = references.as_ref();
55        for r in rs {
56            let reference = r.as_ref();
57            args.push(reference.as_ref());
58        }
59
60        // IIRC Git usually returns another exit code than 1 for
61        // actual errors, right? But to be sure:
62        if !self.git(&args, quiet)? {
63            bail!("git {args:?} was not successful");
64        }
65
66        Ok(())
67    }
68
69    /// Get the name of the currently checked-out branch, if any
70    /// (returns None if in detached HEAD state). TODO: just rename
71    /// upstream method and change return type.
72    fn get_current_branch(&self) -> Result<Option<GitBranchName>> {
73        Ok(self.git_branch_show_current()?.map(|s| {
74            GitBranchName::from_str(&s).expect("git always returns branch names for show-current")
75        }))
76    }
77}