git_iris/git/
metadata.rs

1use crate::context::ProjectMetadata;
2use crate::file_analyzers;
3use crate::log_debug;
4use anyhow::Result;
5use futures::future::join_all;
6use std::path::Path;
7use tokio::task;
8
9/// Analyzes a single file and extracts its metadata
10pub async fn analyze_file(file_path: &str) -> Option<ProjectMetadata> {
11    let file_name = Path::new(file_path)
12        .file_name()
13        .and_then(|name| name.to_str())
14        .unwrap_or_default();
15
16    let analyzer: Box<dyn file_analyzers::FileAnalyzer + Send + Sync> =
17        file_analyzers::get_analyzer(file_name);
18
19    log_debug!("Analyzing file: {}", file_path);
20
21    if file_analyzers::should_exclude_file(file_path) {
22        log_debug!("File excluded: {}", file_path);
23        None
24    } else if let Ok(content) = tokio::fs::read_to_string(file_path).await {
25        let metadata = analyzer.extract_metadata(file_name, &content);
26        log_debug!("Extracted metadata for {}: {:?}", file_name, metadata);
27        Some(metadata)
28    } else {
29        log_debug!("Failed to read file: {}", file_path);
30        None
31    }
32}
33
34/// Extracts project metadata from a collection of files
35///
36/// Uses a batch processing approach to limit concurrent tasks
37pub async fn extract_project_metadata(
38    changed_files: &[String],
39    batch_size: usize,
40) -> Result<ProjectMetadata> {
41    log_debug!(
42        "Getting project metadata for {} changed files",
43        changed_files.len()
44    );
45
46    let mut combined_metadata = ProjectMetadata::default();
47    let mut any_file_analyzed = false;
48
49    // Process files in batches to limit concurrent tasks
50    for chunk in changed_files.chunks(batch_size) {
51        let metadata_futures = chunk.iter().map(|file_path| {
52            let file_path = file_path.clone();
53            task::spawn(async move { analyze_file(&file_path).await })
54        });
55
56        let batch_results = join_all(metadata_futures).await;
57
58        for metadata in batch_results.into_iter().flatten().flatten() {
59            log_debug!("Merging metadata: {:?}", metadata);
60            combined_metadata.merge(metadata);
61            any_file_analyzed = true;
62        }
63    }
64
65    log_debug!("Final combined metadata: {:?}", combined_metadata);
66
67    if !any_file_analyzed {
68        log_debug!("No files were analyzed!");
69        combined_metadata.language = Some("Unknown".to_string());
70    } else if combined_metadata.language.is_none() {
71        combined_metadata.language = Some("Unknown".to_string());
72    }
73
74    Ok(combined_metadata)
75}