evobench_tools/
git_tags.rs1use std::{collections::BTreeMap, str::FromStr, sync::Arc};
6
7use anyhow::{Context, Result, anyhow};
8use kstring::KString;
9use run_git::git::GitWorkingDir;
10use smallvec::{SmallVec, smallvec};
11
12use crate::{git::GitHash, warn};
13
14pub struct GitTag {
15 pub name: KString,
16 pub commit: Arc<GitHash>,
17}
18
19pub struct GitTags {
20 tags: Vec<GitTag>,
21 by_hash: BTreeMap<Arc<GitHash>, SmallVec<[u32; 1]>>,
23}
24
25impl GitTags {
26 pub fn from_dir(working_dir: &GitWorkingDir) -> Result<Self> {
27 let s = working_dir.git_stdout_string_trimmed(&[
28 "tag", "--list", ])?;
30 let mut tags = Vec::new();
31 let mut by_hash: BTreeMap<Arc<GitHash>, SmallVec<[u32; 1]>> = Default::default();
32 for name in s.split("\n") {
33 if let Some(commit) = working_dir
34 .git_rev_parse(name, true)
35 .with_context(|| anyhow!("resolving tag name {name:?}"))?
36 {
37 let commit = Arc::new(
38 GitHash::from_str(&commit)
39 .with_context(|| anyhow!("resolving tag name {name:?}"))?,
40 );
41 let id = u32::try_from(tags.len())
42 .context("getting tags, you appear to have more than u32::MAX tags")?;
43 match by_hash.entry(commit.clone()) {
44 std::collections::btree_map::Entry::Vacant(vacant_entry) => {
45 vacant_entry.insert(smallvec![id]);
46 }
47 std::collections::btree_map::Entry::Occupied(mut occupied_entry) => {
48 occupied_entry.get_mut().push(id);
49 }
50 }
51
52 let name = KString::from_ref(name);
53 tags.push(GitTag { name, commit });
54 } else {
55 warn!("could not resolve tag name {name:?} that we just got");
59 }
60 }
61 Ok(GitTags { tags, by_hash })
62 }
63
64 pub fn get_by_commit(&self, commit_id: &GitHash) -> impl ExactSizeIterator<Item = &str> {
67 if let Some(items) = self.by_hash.get(commit_id) {
68 &**items
69 } else {
70 &[]
71 }
72 .iter()
73 .map(|i| &*self.tags[usize::try_from(*i).expect("usize expected to be >= u32")].name)
74 }
75}