use anyhow::{Result, ensure};
use dsi_progress_logger::{ProgressLog, concurrent_progress_logger};
use rayon::prelude::*;
use swh_graph::NodeType;
use swh_graph::graph::*;
use swh_graph::labels::{EdgeLabel, LabelNameId};
use swh_graph::properties;
use swh_graph::views::Subgraph;
pub const HEAD_REF_NAMES: [&str; 2] = ["refs/heads/main", "refs/heads/master"];
pub fn find_head_rev<G>(graph: &G, snp: NodeId) -> Result<Option<NodeId>>
where
G: SwhLabeledForwardGraph + SwhGraphWithProperties,
<G as SwhGraphWithProperties>::LabelNames: properties::LabelNames,
<G as SwhGraphWithProperties>::Maps: properties::Maps,
{
let props = graph.properties();
let head_ref_name_ids: Vec<LabelNameId> = HEAD_REF_NAMES
.into_iter()
.filter_map(|name| props.label_name_id(name.as_bytes()).ok())
.collect();
find_head_rev_by_refs(graph, snp, &head_ref_name_ids)
}
pub fn find_head_rev_by_refs<G>(
graph: &G,
snp: NodeId,
ref_name_ids: &[LabelNameId],
) -> Result<Option<NodeId>>
where
G: SwhLabeledForwardGraph + SwhGraphWithProperties,
<G as SwhGraphWithProperties>::Maps: properties::Maps,
<G as SwhGraphWithProperties>::LabelNames: properties::LabelNames,
{
let props = graph.properties();
let node_type = props.node_type(snp);
ensure!(
node_type == NodeType::Snapshot,
"Type of {snp} should be snp, but is {node_type} instead"
);
for (succ, labels) in graph.labeled_successors(snp) {
let node_type = props.node_type(succ);
if node_type != NodeType::Revision && node_type != NodeType::Release {
continue;
}
for label in labels {
#[allow(clippy::collapsible_if)]
if let EdgeLabel::Branch(branch) = label {
if ref_name_ids.contains(&branch.label_name_id()) {
return Ok(Some(succ));
}
}
}
}
Ok(None)
}
pub fn list_root_revisions<G>(graph: &G) -> Result<Vec<NodeId>>
where
G: SwhForwardGraph + SwhGraphWithProperties<Maps: properties::Maps> + Sync,
{
let graph = Subgraph::with_node_constraint(graph, "rev".parse().unwrap());
let mut pl = concurrent_progress_logger!(
item_name = "rev",
display_memory = false,
expected_updates = graph.actual_num_nodes().ok(),
);
pl.start("Listing initial revs...");
Ok(graph
.par_iter_nodes(pl)
.filter(|&node| graph.successors(node).next().is_none())
.collect())
}