backhopper_core/compat/
scope.rs1use std::collections::{BTreeMap, BTreeSet};
12use std::path::Path;
13use std::str::FromStr;
14
15use crate::model::names::{ModuleName, ProjectName, RecordName};
16use crate::model::snapshot::{Snapshot, state};
17
18#[derive(Debug, Clone, Default, PartialEq, Eq)]
20pub struct PinScope {
21 modules: BTreeSet<ModuleName>,
22 records: BTreeSet<RecordName>,
23 path_prefixes: Vec<String>,
24}
25
26impl PinScope {
27 pub fn from_snapshot(
28 project: ProjectName,
29 snapshot: &Snapshot<state::Canonical>,
30 extra_modules: impl IntoIterator<Item = ModuleName>,
31 ) -> Self {
32 let mut modules: BTreeSet<ModuleName> =
33 snapshot.modules().iter().map(|m| m.name.clone()).collect();
34 modules.extend(extra_modules);
35 let records: BTreeSet<RecordName> = snapshot.records().map(|r| r.name.clone()).collect();
36 Self {
37 modules,
38 records,
39 path_prefixes: vec![format!("deps/{project}/")],
40 }
41 }
42
43 pub fn contains_module(&self, module: &ModuleName) -> bool {
44 self.modules.contains(module)
45 }
46
47 pub fn contains_record(&self, record: &RecordName) -> bool {
48 self.records.contains(record)
49 }
50
51 pub fn modules(&self) -> &BTreeSet<ModuleName> {
52 &self.modules
53 }
54
55 pub fn records(&self) -> &BTreeSet<RecordName> {
56 &self.records
57 }
58
59 pub fn rewrite_path<'p>(&self, path: &'p Path) -> Option<&'p Path> {
62 let s = path.to_str()?;
63 for prefix in &self.path_prefixes {
64 if let Some(rest) = s.strip_prefix(prefix.as_str()) {
65 return Some(Path::new(rest));
66 }
67 }
68 if self.path_prefixes.is_empty() || !s.starts_with("deps/") {
69 return Some(path);
70 }
71 None
72 }
73}
74
75pub fn parse_module_names<'a>(raw: impl IntoIterator<Item = &'a String>) -> Vec<ModuleName> {
79 raw.into_iter()
80 .filter_map(|s| match ModuleName::from_str(s) {
81 Ok(name) => Some(name),
82 Err(e) => {
83 tracing::warn!(value = %s, error = %e, "ignoring invalid module name in config");
84 None
85 }
86 })
87 .collect()
88}
89
90#[derive(Debug, Clone, Default, PartialEq, Eq)]
92pub struct UntrackedTally {
93 counts: BTreeMap<ModuleName, usize>,
94}
95
96impl UntrackedTally {
97 pub fn record(&mut self, module: ModuleName) {
98 *self.counts.entry(module).or_insert(0) += 1;
99 }
100
101 pub fn into_map(self) -> BTreeMap<ModuleName, usize> {
102 self.counts
103 }
104}