use std::path::Path;
use thiserror::Error;
use crate::compress::CompressError;
use crate::graph::{build_project_ir, enrich_project_ir_code_bytes, GraphPersistenceOptions};
use crate::ir::ProjectIr;
use crate::pipeline::ScanOptions;
use crate::scanner::{scan_and_parse, FileScanConfig, ScannerError};
pub use crate::graph::ExtractOptions;
impl From<&ScanOptions> for crate::graph::ExtractOptions {
fn from(opts: &ScanOptions) -> Self {
Self {
verbose_imports: opts.graph.verbose_imports,
max_parse_warnings_per_file: opts.graph.max_parse_warnings_per_file,
compressor: opts.graph.compressor.clone(),
}
}
}
impl From<&GraphPersistenceOptions> for crate::graph::ExtractOptions {
fn from(opts: &GraphPersistenceOptions) -> Self {
Self {
verbose_imports: opts.verbose_imports,
max_parse_warnings_per_file: opts.max_parse_warnings_per_file,
compressor: opts.compressor.clone(),
}
}
}
#[derive(Debug, Error)]
pub enum ExtractError {
#[error("scan/parse failed: {0}")]
Scanner(#[from] ScannerError),
#[error("code compression failed: {0}")]
Compress(#[from] CompressError),
}
pub fn build_project_ir_from_files(
root: &Path,
files: &[crate::scanner::ParsedFile],
options: &ExtractOptions,
) -> ProjectIr {
build_project_ir(root, files, options)
}
pub fn scan_and_build_ir(
root: &Path,
options: &ExtractOptions,
scan: &ScanOptions,
) -> Result<ProjectIr, ExtractError> {
let mut config = FileScanConfig::new(root);
config.follow_symlinks = scan.follow_symlinks;
config.max_file_size = scan.max_file_size;
let files = scan_and_parse(&config)?;
let mut ir = build_project_ir_from_files(root, &files, options);
run_ir_compression(&mut ir, root, &files, &options.compressor)?;
Ok(ir)
}
fn run_ir_compression(
ir: &mut ProjectIr,
root: &Path,
files: &[crate::scanner::ParsedFile],
config: &crate::graph::CompressorConfig,
) -> Result<(), CompressError> {
if !config.enabled {
return Ok(());
}
if let Ok(handle) = tokio::runtime::Handle::try_current() {
return handle.block_on(enrich_project_ir_code_bytes(ir, root, files, config));
}
let rt = tokio::runtime::Runtime::new().expect("failed to create tokio runtime for compression");
rt.block_on(enrich_project_ir_code_bytes(ir, root, files, config))
}
pub async fn scan_and_build_ir_async(
root: &Path,
options: &ExtractOptions,
scan: &ScanOptions,
) -> Result<ProjectIr, ExtractError> {
let mut config = FileScanConfig::new(root);
config.follow_symlinks = scan.follow_symlinks;
config.max_file_size = scan.max_file_size;
let files = scan_and_parse(&config)?;
let mut ir = build_project_ir_from_files(root, &files, options);
enrich_project_ir_code_bytes(&mut ir, root, &files, &options.compressor).await?;
Ok(ir)
}
pub fn parse_files_to_ir(
root: &Path,
parse_targets: &[String],
options: &ExtractOptions,
scan: &ScanOptions,
) -> Result<ProjectIr, ExtractError> {
let mut config = FileScanConfig::new(root);
config.follow_symlinks = scan.follow_symlinks;
config.max_file_size = scan.max_file_size;
let paths: Vec<_> = parse_targets.iter().map(std::path::PathBuf::from).collect();
let files = crate::scanner_incremental::scan_and_parse_incremental_vector(&config, &paths)?;
let mut ir = build_project_ir_from_files(root, &files, options);
run_ir_compression(&mut ir, root, &files, &options.compressor)?;
Ok(ir)
}