pub(crate) mod compact;
pub(crate) mod descriptor;
pub(crate) use compact::{
CompactSink, LoadedCompactSummary, fold_cached, fold_loaded, scan_cached_files,
};
pub(crate) use descriptor::scan_all_cached_files;
use crate::models::ExtensionType;
use anyhow::Result;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScanFailure {
pub provider: ExtensionType,
pub source: PathBuf,
pub error: String,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ScanDiagnostics {
pub candidates: usize,
pub parsed: usize,
pub failures: Vec<ScanFailure>,
}
impl ScanDiagnostics {
pub fn has_failures(&self) -> bool {
!self.failures.is_empty()
}
pub fn all_failed(&self) -> bool {
self.candidates > 0 && self.parsed == 0
}
pub fn partially_failed(&self) -> bool {
self.parsed > 0 && self.has_failures()
}
pub(crate) fn record_failure(&mut self, provider: ExtensionType, source: &Path, error: String) {
self.failures.push(ScanFailure {
provider,
source: source.to_path_buf(),
error,
});
}
pub(crate) fn record_hard_failure(
&mut self,
provider: ExtensionType,
source: &Path,
error: String,
) {
log::warn!(
"failed to collect {} session from {}: {}",
provider,
source.display(),
error
);
self.record_failure(provider, source, error);
}
pub(crate) fn finalize(&mut self) {
self.failures.sort_by(|left, right| {
left.provider
.scan_rank()
.cmp(&right.provider.scan_rank())
.then_with(|| left.source.cmp(&right.source))
.then_with(|| left.error.cmp(&right.error))
});
}
}
pub fn build_scan_pool(threads: usize) -> Result<rayon::ThreadPool> {
rayon::ThreadPoolBuilder::new()
.num_threads(threads.max(1))
.thread_name(|index| format!("vct-scan-{index}"))
.build()
.map_err(Into::into)
}