xensec_internal_tools/
githelp.rs1use crate::prelude::*;
6
7#[derive(Debug)]
8pub enum RefSpec<'r> {
9 Def,
10 Refname(&'r str),
11 Tree(&'r git2::Tree<'r>),
12}
13impl Default for RefSpec<'_> { fn default() -> Self { RefSpec::Def } }
14
15pub trait Repo {
16 fn g2(&self) -> &git2::Repository;
17 fn dir(&self) -> &str;
18 fn cfg(&self) -> &Config;
19
20 fn def_refname(&self) -> &str;
21
22 #[throws(AE)]
23 fn get_tree_maybe(&self, refname: &str) -> Option<git2::Tree> {
24 let tree = (||{
25 let oid = match self.g2().refname_to_id(refname) {
26 Err(e) if e.code() == git2::ErrorCode::NotFound => return Ok(None),
27 x => x.context("resolve ref")?,
28 };
29 let commit = self.g2().find_commit(oid).context("get commit")?;
30 let tree = commit.tree().context("get tree")?;
31 Ok::<_,AE>(Some(tree))
32 })().with_context(|| refname.to_string())?;
33 tree
34 }
35
36 #[throws(AE)]
37 fn get_tree<'r>(&'r self, refspec: RefSpec<'r>) -> git2::Tree<'r> {
38 let refname = match refspec {
39 RefSpec::Def => self.def_refname(),
40 RefSpec::Refname(n) => n,
41 RefSpec::Tree(t) => return t.clone(),
42 };
43 self.get_tree_maybe(refname)?
44 .ok_or_else(|| anyhow!("ref {:?} not found", refname))?
45 }
46
47 #[throws(AE)]
48 fn file(&self, refspec: RefSpec, path: &str) -> Option<String> {
49 let tree = self.get_tree(refspec)?;
50 (||{
51 let ent = match tree.get_path(path.as_ref()) {
52 Err(e) if e.code() == git2::ErrorCode::NotFound => return Ok(None),
53 x => x,
54 }.context("get_path")?;
55 let obj = ent.to_object(self.g2()).context("to_object")?;
56 let blob = obj.into_blob()
57 .map_err(|e| anyhow!("not a blob, but {:?}", &e.kind()))?;
58 let r = str::from_utf8(blob.content()).context("from_utf8")?;
59 Ok::<_,AE>(Some(r.to_owned()))
60 })()
61 .with_context(|| path.to_string())
62 .context("look up path")?
63 }
64
65 #[throws(AE)]
66 fn files(&self, refspec: RefSpec, path: &str) -> Vec<String> {
67 let tree = self.get_tree(refspec)?;
68 (||{
69 let ent = tree.get_path(path.as_ref()).context("get_path")?;
70 let obj = ent.to_object(self.g2()).context("to_object")?;
71 let tree = obj.into_tree()
72 .map_err(|e| anyhow!("not a tree, but {:?}", &e.kind()))?;
73 tree.iter().map(|ent| Ok::<_,AE>(
74 ent.name()
75 .ok_or_else(|| anyhow!("bad entry in {}, not utf-8: {:?}",
76 path, ent.name_bytes()))?
77 .to_owned()
78 ))
79 .collect::<Result<Vec<_>,_>>()
80 })()
81 .with_context(|| path.to_string())
82 .context("enumerate dir")?
83 }
84
85 #[throws(AE)]
86 fn run_git(&mut self, want: bool, doing: &str,
87 u: &mut dyn FnMut(&mut Command) -> Result<(), AE>) {
88 let mut cmd = if want {
89 self.cfg().git_command()?
90 } else if log_enabled!(log::Level::Debug) {
91 let mut cmd = Command::new("sh");
92 cmd.args(&["-c",r#"exec >&2; echo "$*";"#,"-","# git"]);
93 cmd
94 } else {
95 let mut cmd = Command::new("true");
96 cmd.arg("--");
97 cmd
98 };
99
100 cmd.current_dir(self.dir());
101 if let Some(v) = &self.cfg().git_ssh_command {
102 cmd.env("GIT_SSH_COMMAND", v);
103 }
104
105 u(&mut cmd)?;
106
107 let show = format!("cmd {:?}", &cmd);
108
109 if want { debug!("{}, {}", &doing, &show); }
110
111 let st = cmd.status().context("spawn git")?;
112 if ! st.success() { throw!(
113 anyhow!("git failed: {}", st)
114 .context(show.clone())
115 .context(self.dir().to_owned())
116 ) }
117 }
118}
119
120impl cache::Cache {
121 #[throws(AE)]
122 pub fn run_git_fetch_pull(&mut self, refresh: RefreshKind,
123 repo: &mut dyn Repo,
124 args1: &[&str],
125 remote_name: &str,
126 branch_pats: &[&str],
127 extra_refspecs: &[&str])
128 -> Option<RefreshingToken>
129 {
130 let want = self.cfg.want_refresh(refresh, None);
131
132 repo.run_git(want.is_some(), "updating", &mut |cmd: &mut Command| {
133
134 cmd.args(args1);
135 if ! log_enabled!(log::Level::Debug) { cmd.arg("--quiet"); }
136
137 cmd.arg(remote_name);
138 for pat in branch_pats {
139 cmd.arg(format!(
140 "+refs/heads/{pat}:refs/remotes/{remote}/{pat}",
141 pat=pat, remote=remote_name,
142 ));
143 }
144 cmd.args(extra_refspecs);
145
146 Ok::<_,AE>(())
147 })
148 .context("update from remote git repo")?;
149
150 want
151 }
152}