gitoxide_core/commitgraph/
verify.rs

1use crate::OutputFormat;
2
3/// A general purpose context for many operations provided here
4pub struct Context<W1: std::io::Write, W2: std::io::Write> {
5    /// A stream to which to output errors
6    pub err: W2,
7    /// A stream to which to output operation results
8    pub out: W1,
9    pub output_statistics: Option<OutputFormat>,
10}
11
12impl Default for Context<Vec<u8>, Vec<u8>> {
13    fn default() -> Self {
14        Context {
15            err: Vec::new(),
16            out: Vec::new(),
17            output_statistics: None,
18        }
19    }
20}
21
22pub(crate) mod function {
23    use std::{io, path::Path};
24
25    use anyhow::{Context as AnyhowContext, Result};
26    use gix::commitgraph::{verify::Outcome, Graph};
27
28    use crate::OutputFormat;
29
30    pub fn verify<W1, W2>(
31        path: impl AsRef<Path>,
32        super::Context {
33            err: _err,
34            mut out,
35            output_statistics,
36        }: super::Context<W1, W2>,
37    ) -> Result<gix::commitgraph::verify::Outcome>
38    where
39        W1: io::Write,
40        W2: io::Write,
41    {
42        let g = Graph::at(path.as_ref()).with_context(|| "Could not open commit graph")?;
43
44        #[allow(clippy::unnecessary_wraps, unknown_lints)]
45        fn noop_processor(_commit: &gix::commitgraph::file::Commit<'_>) -> std::result::Result<(), std::fmt::Error> {
46            Ok(())
47        }
48        let stats = g
49            .verify_integrity(noop_processor)
50            .with_context(|| "Verification failure")?;
51
52        #[cfg_attr(not(feature = "serde"), allow(clippy::single_match))]
53        match output_statistics {
54            Some(OutputFormat::Human) => drop(print_human_output(&mut out, &stats)),
55            #[cfg(feature = "serde")]
56            Some(OutputFormat::Json) => serde_json::to_writer_pretty(out, &stats)?,
57            _ => {}
58        }
59
60        Ok(stats)
61    }
62
63    fn print_human_output(out: &mut impl io::Write, stats: &Outcome) -> io::Result<()> {
64        writeln!(out, "number of commits with the given number of parents")?;
65        let mut parent_counts: Vec<_> = stats.parent_counts.iter().map(|(a, b)| (*a, *b)).collect();
66        parent_counts.sort_by_key(|e| e.0);
67        for (parent_count, commit_count) in parent_counts.into_iter() {
68            writeln!(out, "\t{parent_count:>2}: {commit_count}")?;
69        }
70        writeln!(out, "\t->: {}", stats.num_commits)?;
71
72        write!(out, "\nlongest path length between two commits: ")?;
73        if let Some(n) = stats.longest_path_length {
74            writeln!(out, "{n}")?;
75        } else {
76            writeln!(out, "unknown")?;
77        }
78
79        Ok(())
80    }
81}