use anyhow::{Result, bail, ensure};
use swh_graph::graph::*;
use swh_graph::labels::{EdgeLabel, VisitStatus};
use swh_graph::{NodeConstraint, NodeType, properties};
pub fn find_latest_snp<G>(graph: &G, ori: NodeId) -> Result<Option<(NodeId, u64)>>
where
G: SwhLabeledForwardGraph + SwhGraphWithProperties,
<G as SwhGraphWithProperties>::Maps: properties::Maps,
{
let props = graph.properties();
let node_type = props.node_type(ori);
ensure!(
node_type == NodeType::Origin,
"Type of {ori} should be ori, but is {node_type} instead"
);
let mut latest_snp: Option<(usize, u64)> = None;
for (succ, labels) in graph.labeled_successors(ori) {
let node_type = props.node_type(succ);
if node_type != NodeType::Snapshot {
continue;
}
for label in labels {
if let EdgeLabel::Visit(visit) = label {
if visit.status() != VisitStatus::Full {
continue;
}
let ts = visit.timestamp();
if let Some((_cur_snp, cur_ts)) = latest_snp {
if ts > cur_ts {
latest_snp = Some((succ, ts))
}
} else {
latest_snp = Some((succ, ts))
}
}
}
}
Ok(latest_snp)
}
pub fn peel_once<G>(graph: &G, node: NodeId) -> Result<Option<NodeId>>
where
G: SwhLabeledForwardGraph + SwhGraphWithProperties,
<G as SwhGraphWithProperties>::LabelNames: properties::LabelNames,
<G as SwhGraphWithProperties>::Maps: properties::Maps,
{
ensure!(!graph.is_transposed(), "Cannot peel on a transposed graph.");
let props = graph.properties();
let source_type = props.node_type(node);
match source_type {
NodeType::Content | NodeType::Directory => {
bail!("Cannot peel nodes of type {source_type}");
}
NodeType::Revision => {
for succ in graph.successors(node) {
if props.node_type(succ) == NodeType::Directory {
return Ok(Some(succ));
}
}
Ok(None)
}
NodeType::Release => {
if let Some(succ) = graph.successors(node).into_iter().next() {
return Ok(Some(succ));
}
Ok(None)
}
NodeType::Snapshot => {
if let Ok(Some(succ)) = vcs::find_head_rev(&graph, node) {
Ok(Some(succ))
} else {
for succ in graph.successors(node) {
let t = props.node_type(succ);
if t == NodeType::Revision || t == NodeType::Release {
return Ok(Some(succ));
}
}
Ok(None)
}
}
NodeType::Origin => {
find_latest_snp(&graph, node).map(|opt_node| opt_node.map(|(node, _ts)| node))
}
}
}
pub fn peel<G>(graph: &G, node: 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 source_type = props.node_type(node);
let mut current = node;
while props.node_type(current) == source_type {
match peel_once(graph, current)? {
Some(next) => current = next,
None => return Ok(None),
}
}
Ok(Some(current))
}
pub fn peel_until<G>(graph: &G, node: NodeId, target_type: NodeConstraint) -> Result<Option<NodeId>>
where
G: SwhLabeledForwardGraph + SwhGraphWithProperties,
<G as SwhGraphWithProperties>::LabelNames: properties::LabelNames,
<G as SwhGraphWithProperties>::Maps: properties::Maps,
{
let props = graph.properties();
let source_type = props.node_type(node);
if target_type.matches(source_type) {
return Ok(Some(node));
}
let Some(mut current) = peel_once(graph, node)? else {
return Ok(None);
};
loop {
let current_type = props.node_type(current);
if target_type.matches(current_type) {
return Ok(Some(current));
}
if current_type == NodeType::Release || current_type == NodeType::Revision {
match peel_once(graph, current)? {
Some(next) => current = next,
None => return Ok(None),
}
} else {
bail!("Cannot peel to {target_type}: stuck at node {current} of type {current_type}");
}
}
}
pub mod collections;
pub mod connectivity;
pub mod diff;
pub mod fs;
pub mod io;
pub mod labeling;
pub mod origins;
#[cfg(feature = "unstable_project_ids")]
pub mod project_ids;
mod root_directory;
pub use root_directory::find_root_dir;
pub mod vcs;
mod visit;
pub use visit::*;
pub use deprecated::*;
#[allow(deprecated)]
mod deprecated {
use std::collections::HashMap;
use swh_graph::labels::{LabelNameId, Permission};
use super::*;
#[doc(hidden)]
#[deprecated(since = "10.3.0", note = "use swh_graph_stdlib::vcs::HEAD_REF_NAMES")]
pub const HEAD_REF_NAMES: [&str; 2] = vcs::HEAD_REF_NAMES;
#[doc(hidden)]
#[deprecated(since = "10.3.0", note = "use swh_graph_stdlib::vcs::find_head_rev")]
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,
{
vcs::find_head_rev(graph, snp)
}
#[doc(hidden)]
#[deprecated(
since = "10.3.0",
note = "use swh_graph_stdlib::vcs::find_head_rev_by_refs"
)]
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,
{
vcs::find_head_rev_by_refs(graph, snp, ref_name_ids)
}
#[doc(hidden)]
#[deprecated(since = "10.3.0", note = "use swh_graph_stdlib::fs::FsTree")]
#[derive(Debug, Default, PartialEq)]
pub enum FsTree {
#[default]
Content,
Directory(HashMap<Vec<u8>, (FsTree, Option<Permission>)>),
Revision(NodeId),
}
impl From<fs::FsTree> for FsTree {
fn from(tree: fs::FsTree) -> Self {
match tree {
fs::FsTree::Content => FsTree::Content,
fs::FsTree::Directory(entries) => FsTree::Directory(
entries
.into_iter()
.map(|(name, (tree, perm))| (name, (tree.into(), perm)))
.collect(),
),
fs::FsTree::Revision(rev) => FsTree::Revision(rev),
}
}
}
#[doc(hidden)]
#[deprecated(since = "10.3.0", note = "use swh_graph_stdlib::fs::resolve_name")]
pub fn fs_resolve_name<G>(
graph: &G,
dir: NodeId,
name: impl AsRef<[u8]>,
) -> Result<Option<NodeId>>
where
G: SwhLabeledForwardGraph + SwhGraphWithProperties,
<G as SwhGraphWithProperties>::LabelNames: properties::LabelNames,
<G as SwhGraphWithProperties>::Maps: properties::Maps,
{
fs::resolve_name(graph, dir, name)
}
pub fn fs_resolve_name_by_id<G>(
graph: &G,
dir: NodeId,
name: LabelNameId,
) -> Result<Option<NodeId>>
where
G: SwhLabeledForwardGraph + SwhGraphWithProperties,
<G as SwhGraphWithProperties>::Maps: properties::Maps,
{
fs::resolve_name_by_id(graph, dir, name)
}
#[doc(hidden)]
#[deprecated(since = "10.3.0", note = "use swh_graph_stdlib::fs::resolve_path")]
pub fn fs_resolve_path<G>(
graph: &G,
dir: NodeId,
path: impl AsRef<[u8]>,
) -> Result<Option<NodeId>>
where
G: SwhLabeledForwardGraph + SwhGraphWithProperties,
<G as SwhGraphWithProperties>::LabelNames: properties::LabelNames,
<G as SwhGraphWithProperties>::Maps: properties::Maps,
{
fs::resolve_path(graph, dir, path)
}
#[doc(hidden)]
#[deprecated(
since = "10.3.0",
note = "use swh_graph_stdlib::fs::resolve_path_by_id"
)]
pub fn fs_resolve_path_by_id<G>(
graph: &G,
dir: NodeId,
path: &[LabelNameId],
) -> Result<Option<NodeId>>
where
G: SwhLabeledForwardGraph + SwhGraphWithProperties,
<G as SwhGraphWithProperties>::Maps: properties::Maps,
{
fs::resolve_path_by_id(graph, dir, path)
}
#[doc(hidden)]
#[deprecated(since = "10.3.0", note = "use swh_graph_stdlib::fs::ls_tree")]
pub fn fs_ls_tree<G>(graph: &G, dir: NodeId) -> Result<FsTree>
where
G: SwhLabeledForwardGraph + SwhGraphWithProperties,
<G as SwhGraphWithProperties>::LabelNames: properties::LabelNames,
<G as SwhGraphWithProperties>::Maps: properties::Maps,
{
fs::ls_tree(graph, dir).map(Into::into)
}
}