Skip to main content

heddle_core/fsck/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2//! Repository integrity checks.
3
4mod git_projection;
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 git_projection: 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 git_projection_checked: bool,
31    pub repair_target: Option<String>,
32    pub repaired: bool,
33    pub repairs: Vec<FsckRepair>,
34}
35
36impl FsckReport {
37    pub const CONTRACT: ReportContract = ReportContract {
38        schema_name: "fsck",
39        machine_output_kind: MachineOutputKind::Json,
40        output_discriminator: None,
41        schema: schema_for_report::<FsckReport>,
42    };
43}
44
45impl HeddleReport for FsckReport {
46    const CONTRACT: ReportContract = FsckReport::CONTRACT;
47}
48
49#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
50pub struct FsckRepair {
51    pub name: String,
52    pub repaired: bool,
53    pub detail: String,
54    pub count: usize,
55}
56
57#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
58pub struct FsckError {
59    pub kind: String,
60    pub message: String,
61    pub object: Option<String>,
62}
63
64fn make_error(kind: &str, message: &str, object: Option<String>) -> FsckError {
65    FsckError {
66        kind: kind.to_string(),
67        message: message.to_string(),
68        object,
69    }
70}
71
72pub fn fsck(ctx: &ExecutionContext, opts: FsckOptions) -> Result<FsckReport> {
73    let repo = ctx.require_repo()?;
74
75    let mut errors: Vec<FsckError> = Vec::new();
76    let mut warnings: Vec<String> = Vec::new();
77    let mut objects_checked: usize = 0;
78
79    state::check_states(repo, &mut errors, &mut objects_checked, opts.thorough)?;
80
81    if opts.full {
82        objects::check_tree_objects(repo, &mut errors, &mut warnings, &mut objects_checked)?;
83    }
84
85    refs::check_refs(repo, &mut errors, &mut warnings)?;
86    refs::check_merge_state(repo, &mut warnings)?;
87    if opts.git_projection {
88        git_projection::check_git_projection(
89            repo,
90            &mut errors,
91            &mut warnings,
92            &mut objects_checked,
93        )?;
94    }
95
96    let valid = errors.is_empty();
97
98    Ok(FsckReport {
99        valid,
100        errors,
101        warnings,
102        objects_checked,
103        git_projection_checked: opts.git_projection,
104        repair_target: None,
105        repaired: false,
106        repairs: Vec::new(),
107    })
108}
109
110fn invalid_fsck_config(message: impl Into<String>) -> HeddleError {
111    HeddleError::Config(message.into())
112}