1use anyhow::{Result, ensure};
9use dsi_progress_logger::{ProgressLog, concurrent_progress_logger};
10use rayon::prelude::*;
11
12use swh_graph::NodeType;
13use swh_graph::graph::*;
14use swh_graph::labels::{EdgeLabel, LabelNameId};
15use swh_graph::properties;
16use swh_graph::views::Subgraph;
17
18pub const HEAD_REF_NAMES: [&str; 2] = ["refs/heads/main", "refs/heads/master"];
22
23pub fn find_head_rev<G>(graph: &G, snp: NodeId) -> Result<Option<NodeId>>
26where
27 G: SwhLabeledForwardGraph + SwhGraphWithProperties,
28 <G as SwhGraphWithProperties>::LabelNames: properties::LabelNames,
29 <G as SwhGraphWithProperties>::Maps: properties::Maps,
30{
31 let props = graph.properties();
32 let head_ref_name_ids: Vec<LabelNameId> = HEAD_REF_NAMES
33 .into_iter()
34 .filter_map(|name| props.label_name_id(name.as_bytes()).ok())
35 .collect();
39 find_head_rev_by_refs(graph, snp, &head_ref_name_ids)
40}
41
42pub fn find_head_rev_by_refs<G>(
51 graph: &G,
52 snp: NodeId,
53 ref_name_ids: &[LabelNameId],
54) -> Result<Option<NodeId>>
55where
56 G: SwhLabeledForwardGraph + SwhGraphWithProperties,
57 <G as SwhGraphWithProperties>::Maps: properties::Maps,
58 <G as SwhGraphWithProperties>::LabelNames: properties::LabelNames,
59{
60 let props = graph.properties();
61 let node_type = props.node_type(snp);
62 ensure!(
63 node_type == NodeType::Snapshot,
64 "Cannot find head revision of {}: not a snapshot",
65 graph.properties().swhid(snp),
66 );
67 for (succ, labels) in graph.labeled_successors(snp) {
68 let node_type = props.node_type(succ);
69 if node_type != NodeType::Revision && node_type != NodeType::Release {
70 continue;
71 }
72 for label in labels {
73 #[allow(clippy::collapsible_if)]
74 if let EdgeLabel::Branch(branch) = label {
75 if ref_name_ids.contains(&branch.label_name_id()) {
76 return Ok(Some(succ));
77 }
78 }
79 }
80 }
81 Ok(None)
82}
83
84pub fn list_root_revisions<G>(graph: &G) -> Result<Vec<NodeId>>
86where
87 G: SwhForwardGraph + SwhGraphWithProperties<Maps: properties::Maps> + Sync,
88{
89 let graph = Subgraph::with_node_constraint(graph, "rev".parse().unwrap());
90
91 let mut pl = concurrent_progress_logger!(
92 item_name = "rev",
93 display_memory = false,
94 expected_updates = graph.actual_num_nodes().ok(),
95 );
96 pl.start("Listing initial revs...");
97 Ok(graph
98 .par_iter_nodes(pl)
99 .filter(|&node| graph.successors(node).next().is_none())
100 .collect())
101}