use std::path::{Path, PathBuf};
use thiserror::Error;
use crate::graph::{
cleanup_incremental_targets_in_neo4j, persist_files_to_neo4j, GraphError, GraphPersistenceOptions,
Neo4jConfig,
};
use crate::scanner::{scan_and_parse, FileScanConfig, ScannerError};
use crate::scanner_incremental::scan_and_parse_incremental_vector;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParsingMode {
Bootstrap,
IncrementalVector,
}
#[derive(Debug, Clone)]
pub struct ScanOptions {
pub follow_symlinks: bool,
pub max_file_size: Option<u64>,
pub graph: GraphPersistenceOptions,
}
impl Default for ScanOptions {
fn default() -> Self {
Self {
follow_symlinks: false,
max_file_size: Some(2 * 1024 * 1024),
graph: GraphPersistenceOptions::default(),
}
}
}
#[derive(Debug, Clone)]
pub struct PipelineReport {
pub mode: ParsingMode,
pub parsed_files: usize,
pub cleanup_targets: usize,
}
#[derive(Debug, Error)]
pub enum PipelineError {
#[error("scan/parse failed: {0}")]
Scanner(#[from] ScannerError),
#[error("neo4j persistence failed: {0}")]
Graph(#[from] GraphError),
}
fn build_scan_config(root: &Path, options: &ScanOptions) -> FileScanConfig {
let mut config = FileScanConfig::new(root);
config.follow_symlinks = options.follow_symlinks;
config.max_file_size = options.max_file_size;
config
}
pub async fn run_bootstrap_pipeline(
root: &Path,
options: &ScanOptions,
neo4j_cfg: Option<&Neo4jConfig>,
clean: bool,
) -> Result<PipelineReport, PipelineError> {
let config = build_scan_config(root, options);
let parsed_files = scan_and_parse(&config)?;
if let Some(cfg) = neo4j_cfg {
persist_files_to_neo4j(
cfg,
root,
&parsed_files,
clean,
options.follow_symlinks,
&options.graph,
)
.await?;
}
Ok(PipelineReport {
mode: ParsingMode::Bootstrap,
parsed_files: parsed_files.len(),
cleanup_targets: 0,
})
}
pub async fn run_incremental_vector_pipeline(
root: &Path,
options: &ScanOptions,
neo4j_cfg: Option<&Neo4jConfig>,
parse_targets: &[String],
cleanup_targets: &[String],
) -> Result<PipelineReport, PipelineError> {
let config = build_scan_config(root, options);
let parse_target_paths: Vec<PathBuf> = parse_targets.iter().map(PathBuf::from).collect();
let parsed_files = scan_and_parse_incremental_vector(&config, &parse_target_paths)?;
if let Some(cfg) = neo4j_cfg {
cleanup_incremental_targets_in_neo4j(cfg, root, cleanup_targets).await?;
persist_files_to_neo4j(
cfg,
root,
&parsed_files,
false,
options.follow_symlinks,
&options.graph,
)
.await?;
}
Ok(PipelineReport {
mode: ParsingMode::IncrementalVector,
parsed_files: parsed_files.len(),
cleanup_targets: cleanup_targets.len(),
})
}