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 "Type of {snp} should be snp, but is {node_type} instead"
65 );
66 for (succ, labels) in graph.labeled_successors(snp) {
67 let node_type = props.node_type(succ);
68 if node_type != NodeType::Revision && node_type != NodeType::Release {
69 continue;
70 }
71 for label in labels {
72 #[allow(clippy::collapsible_if)]
73 if let EdgeLabel::Branch(branch) = label {
74 if ref_name_ids.contains(&branch.label_name_id()) {
75 return Ok(Some(succ));
76 }
77 }
78 }
79 }
80 Ok(None)
81}
82
83pub fn list_root_revisions<G>(graph: &G) -> Result<Vec<NodeId>>
85where
86 G: SwhForwardGraph + SwhGraphWithProperties<Maps: properties::Maps> + Sync,
87{
88 let graph = Subgraph::with_node_constraint(graph, "rev".parse().unwrap());
89
90 let mut pl = concurrent_progress_logger!(
91 item_name = "rev",
92 display_memory = false,
93 expected_updates = graph.actual_num_nodes().ok(),
94 );
95 pl.start("Listing initial revs...");
96 Ok(graph
97 .par_iter_nodes(pl)
98 .filter(|&node| graph.successors(node).next().is_none())
99 .collect())
100}