1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Copyright (C) 2024  The Software Heritage developers
// See the AUTHORS file at the top-level directory of this distribution
// License: GNU General Public License version 3, or any later version
// See top-level LICENSE file for more information

//! Standard library to work on Software Heritage compressed graph in Rust

use anyhow::{ensure, Result};

use crate::graph::*;
use crate::labels::{EdgeLabel, VisitStatus};
use crate::properties;
use crate::NodeType;

/// Given a graph and an origin node in it, return the node id and timestamp
/// (as a number of seconds since Epoch) of the most recent snapshot of that
/// origin, if it exists.
///
/// Note: only visit with status `Full` are considered when selecting
/// snapshots.
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"
    );
    // Most recent snapshot thus far, as an optional (node_id, timestamp) pair
    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)
}

mod fs;
pub use fs::*;

mod vcs;
pub use vcs::*;

mod visit;
pub use visit::*;

mod root_directory;
pub use root_directory::find_root_dir;