1mod 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}