gitai/git/
metadata.rs

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