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