use std::{path::Path, sync::atomic::AtomicBool}; use gix::progress::DynNestedProgress; use crate::{ corpus, corpus::{Run, Task}, pack::verify::Algorithm, }; impl Task { pub fn perform( &self, run: &mut Run, repo: &Path, progress: &mut corpus::engine::ProgressItem, threads: Option, should_interrupt: &AtomicBool, ) { let start = std::time::Instant::now(); if let Err(err) = self.execute.execute(repo, progress, threads, should_interrupt) { run.error = Some(format!("{err:#?}")); } run.duration = start.elapsed(); } } /// Note that once runs have been recorded, the implementation must not change anymore to keep it comparable. /// If changes have be done, rather change the name of the owning task to start a new kind of task. pub(crate) trait Execute { fn execute( &self, repo: &Path, progress: &mut corpus::engine::ProgressItem, threads: Option, should_interrupt: &AtomicBool, ) -> anyhow::Result<()>; } pub(crate) static ALL: &[Task] = &[ #[cfg(feature = "archive")] Task { short_name: "SWTR", description: "stream worktree", execute_exclusive: false, execute: &WorktreeStream, }, Task { short_name: "OPNR", description: "open repository (isolated)", execute_exclusive: false, execute: &OpenRepo, }, Task { short_name: "POCN", description: "packed object count", execute_exclusive: false, execute: &CountPackedObjects, }, Task { short_name: "VERI", description: "verify object database", execute_exclusive: true, execute: &VerifyOdb, }, ]; #[cfg(feature = "archive")] struct WorktreeStream; #[cfg(feature = "archive")] impl Execute for WorktreeStream { fn execute( &self, repo: &Path, progress: &mut corpus::engine::ProgressItem, _threads: Option, should_interrupt: &AtomicBool, ) -> anyhow::Result<()> { use gix::Progress; let repo = gix::open_opts(repo, gix::open::Options::isolated())?; let (stream, _) = { let _span = gix::trace::coarse!("read index and create worktree stream"); repo.worktree_stream(repo.head_commit()?.tree_id()?)? }; progress.init(None, gix::progress::bytes()); std::io::copy( &mut stream.into_read(), &mut gix::features::interrupt::Write { inner: gix::features::progress::Write { inner: std::io::sink(), progress, }, should_interrupt, }, )?; Ok(()) } } struct OpenRepo; impl Execute for OpenRepo { fn execute( &self, repo: &Path, _progress: &mut corpus::engine::ProgressItem, _threads: Option, _should_interrupt: &AtomicBool, ) -> anyhow::Result<()> { gix::open_opts(repo, gix::open::Options::isolated())?; Ok(()) } } struct CountPackedObjects; impl Execute for CountPackedObjects { fn execute( &self, repo: &Path, _progress: &mut corpus::engine::ProgressItem, _threads: Option, _should_interrupt: &AtomicBool, ) -> anyhow::Result<()> { let repo = gix::open_opts(repo, gix::open::Options::isolated())?; repo.objects.packed_object_count()?; Ok(()) } } struct VerifyOdb; impl Execute for VerifyOdb { fn execute( &self, repo: &Path, progress: &mut corpus::engine::ProgressItem, threads: Option, should_interrupt: &AtomicBool, ) -> anyhow::Result<()> { let repo = gix::open_opts(repo, gix::open::Options::isolated())?; crate::repository::verify::integrity( repo, std::io::sink(), progress.add_child("integrity".into()), should_interrupt, crate::repository::verify::Context { output_statistics: None, thread_limit: threads, verify_mode: Default::default(), algorithm: Algorithm::LessTime, }, )?; Ok(()) } }