86 lines · 2.9 KB · Rust
RawDownload
use std::{    sync::atomic::{AtomicBool, Ordering},    time::Instant,}; use git_features::progress::Progress; use crate::{loose::Store, Write}; ///pub mod integrity {    /// The error returned by [`verify_integrity()`][super::Store::verify_integrity()].    #[derive(Debug, thiserror::Error)]    #[allow(missing_docs)]    pub enum Error {        #[error("{kind} object {id} could not be decoded")]        ObjectDecode {            source: git_object::decode::Error,            kind: git_object::Kind,            id: git_hash::ObjectId,        },        #[error("{kind} object {expected} wasn't re-encoded without change - new hash is {actual}")]        ObjectHashMismatch {            kind: git_object::Kind,            actual: git_hash::ObjectId,            expected: git_hash::ObjectId,        },        #[error("Objects were deleted during iteration - try again")]        Retry,        #[error("Interrupted")]        Interrupted,    }     /// The outcome returned by [`verify_integrity()`][super::Store::verify_integrity()].    #[derive(Debug, PartialEq, Eq, Hash, Ord, PartialOrd, Clone)]    #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]    pub struct Statistics {        /// The amount of loose objects we checked.        pub num_objects: usize,    }} impl Store {    /// Check all loose objects for their integrity checking their hash matches the actual data and by decoding them fully.    pub fn verify_integrity(        &self,        mut progress: impl Progress,        should_interrupt: &AtomicBool,    ) -> Result<integrity::Statistics, integrity::Error> {        let mut buf = Vec::new();        let sink = crate::sink(self.object_hash);         let mut num_objects = 0;        let start = Instant::now();        let mut progress = progress.add_child("Validating");        progress.init(None, git_features::progress::count("loose objects"));        for id in self.iter().filter_map(Result::ok) {            let object = self                .try_find(id, &mut buf)                .map_err(|_| integrity::Error::Retry)?                .ok_or(integrity::Error::Retry)?;            let actual_id = sink.write_buf(object.kind, object.data).expect("sink never fails");            if actual_id != id {                return Err(integrity::Error::ObjectHashMismatch {                    kind: object.kind,                    actual: actual_id,                    expected: id,                });            }            object.decode().map_err(|err| integrity::Error::ObjectDecode {                source: err,                kind: object.kind,                id,            })?;             progress.inc();            num_objects += 1;            if should_interrupt.load(Ordering::SeqCst) {                return Err(integrity::Error::Interrupted);            }        }        progress.show_throughput(start);         Ok(integrity::Statistics { num_objects })    }}