use std::path::{Path, PathBuf};
use anyhow::Result;
use super::delta::{compute_delta, WatchDelta};
use crate::engine::{AnalysisConfig, AnalysisEngine, AnalysisResult};
pub enum WatchReanalysis {
Delta(WatchDelta),
Error(String),
Unchanged,
}
pub struct WatchEngine {
engine: AnalysisEngine,
config: AnalysisConfig,
last_result: Option<AnalysisResult>,
iteration: u32,
session_dir: PathBuf,
}
impl WatchEngine {
pub fn new(repo_path: &Path, config: AnalysisConfig) -> Result<Self> {
let engine = AnalysisEngine::new(repo_path)?;
let session_dir = crate::cache::cache_dir(repo_path).join("session");
Ok(Self {
engine,
config,
last_result: None,
iteration: 0,
session_dir,
})
}
pub fn initial_analyze(&mut self) -> Result<AnalysisResult> {
let result = self.engine.analyze(&self.config)?;
let _ = self.engine.save(&self.session_dir);
self.last_result = Some(result.clone());
Ok(result)
}
pub fn reanalyze(&mut self, changed_files: &[PathBuf]) -> WatchReanalysis {
let start = std::time::Instant::now();
crate::parsers::clear_structural_fingerprint_cache();
match self.engine.analyze(&self.config) {
Ok(result) => {
let delta = compute_delta(
&result,
self.last_result.as_ref(),
changed_files.to_vec(),
start.elapsed(),
);
self.last_result = Some(result);
self.iteration += 1;
if self.iteration.is_multiple_of(10) {
let _ = self.save();
}
if delta.new_findings.is_empty() && delta.fixed_findings.is_empty() {
WatchReanalysis::Unchanged
} else {
WatchReanalysis::Delta(delta)
}
}
Err(e) => WatchReanalysis::Error(format!("{:#}", e)),
}
}
pub fn last_result(&self) -> Option<&AnalysisResult> {
self.last_result.as_ref()
}
pub fn save(&self) -> Result<()> {
self.engine.save(&self.session_dir)?;
Ok(())
}
}