Skip to main content

heddle_core/fsck/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2//! Repository integrity checks.
3
4mod bridge;
5mod objects;
6mod refs;
7mod state;
8#[cfg(test)]
9mod tests;
10
11use ::objects::{HeddleError, error::Result};
12use schemars::JsonSchema;
13use serde::Serialize;
14
15use crate::{ExecutionContext, HeddleReport, MachineOutputKind, ReportContract, schema_for_report};
16
17#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
18pub struct FsckOptions {
19    pub full: bool,
20    pub thorough: bool,
21    pub bridge: bool,
22}
23
24#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
25pub struct FsckReport {
26    pub valid: bool,
27    pub errors: Vec<FsckError>,
28    pub warnings: Vec<String>,
29    pub objects_checked: usize,
30    pub bridge_checked: bool,
31}
32
33impl FsckReport {
34    pub const CONTRACT: ReportContract = ReportContract {
35        schema_name: "fsck",
36        machine_output_kind: MachineOutputKind::Json,
37        output_discriminator: None,
38        schema: schema_for_report::<FsckReport>,
39    };
40}
41
42impl HeddleReport for FsckReport {
43    const CONTRACT: ReportContract = FsckReport::CONTRACT;
44}
45
46#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
47pub struct FsckError {
48    pub kind: String,
49    pub message: String,
50    pub object: Option<String>,
51}
52
53fn make_error(kind: &str, message: &str, object: Option<String>) -> FsckError {
54    FsckError {
55        kind: kind.to_string(),
56        message: message.to_string(),
57        object,
58    }
59}
60
61pub fn fsck(ctx: &ExecutionContext, opts: FsckOptions) -> Result<FsckReport> {
62    let repo = ctx.require_repo()?;
63
64    let mut errors: Vec<FsckError> = Vec::new();
65    let mut warnings: Vec<String> = Vec::new();
66    let mut objects_checked: usize = 0;
67
68    state::check_states(repo, &mut errors, &mut objects_checked, opts.thorough)?;
69
70    if opts.full {
71        objects::check_tree_objects(repo, &mut errors, &mut warnings, &mut objects_checked)?;
72    }
73
74    refs::check_refs(repo, &mut errors, &mut warnings)?;
75    refs::check_merge_state(repo, &mut warnings)?;
76    if opts.bridge {
77        bridge::check_bridge(repo, &mut errors, &mut warnings, &mut objects_checked)?;
78    }
79
80    let valid = errors.is_empty();
81
82    Ok(FsckReport {
83        valid,
84        errors,
85        warnings,
86        objects_checked,
87        bridge_checked: opts.bridge,
88    })
89}
90
91fn invalid_fsck_config(message: impl Into<String>) -> HeddleError {
92    HeddleError::Config(message.into())
93}