Skip to main content

lechange_core/
lib.rs

1//! # LeChange Core
2//!
3//! Ultra-fast Git change detection library with zero-cost abstractions.
4//!
5//! This library provides high-performance git diff operations using:
6//! - **GATs (Generic Associated Types)** for zero-cost async
7//! - **Lifetimes over Arc** for zero-copy string handling
8//! - **String interning** for path deduplication
9//! - **Rayon** for CPU-bound parallel processing
10//! - **Tokio** for async I/O operations
11//!
12//! ## Example
13//!
14//! ```no_run
15//! use lechange_core::{InputConfig, detect_changes};
16//! use std::borrow::Cow;
17//!
18//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
19//! let config = InputConfig {
20//!     base_sha: Some(Cow::Borrowed("HEAD^")),
21//!     sha: Some(Cow::Borrowed("HEAD")),
22//!     ..Default::default()
23//! };
24//!
25//! let result = detect_changes(config).await?;
26//! println!("Changed files: {}", result.all_files.len());
27//! # Ok(())
28//! # }
29//! ```
30
31#![warn(missing_docs, rust_2018_idioms)]
32
33pub mod coordination;
34pub mod error;
35pub mod file_ops;
36pub mod git;
37pub mod http;
38pub mod interner;
39pub mod output;
40pub mod patterns;
41pub mod platform;
42pub mod types;
43
44pub use error::{Error, Result};
45pub use interner::StringInterner;
46pub use types::{
47    ChangeType, ChangedFile, CiDecision, DiffResult, FailureTrackingLevel, GroupDeployAction,
48    GroupDeployDecision, GroupDeployReason, InputConfig, InternedString, ProcessedResult,
49};
50
51/// Detect changed files between two git references
52///
53/// This is the main entry point for the library. It handles:
54/// - SHA resolution
55/// - Diff computation
56/// - Pattern filtering
57/// - Submodule processing
58/// - Symlink detection
59/// - Workflow intelligence
60///
61/// Returns a `ProcessedResult` with index-based partitioning for both
62/// filtered and unfiltered file sets.
63///
64/// # Example
65///
66/// ```no_run
67/// use lechange_core::{InputConfig, detect_changes};
68/// use std::borrow::Cow;
69///
70/// # async fn example() -> lechange_core::Result<()> {
71/// let config = InputConfig {
72///     base_sha: Some(Cow::Borrowed("main")),
73///     sha: Some(Cow::Borrowed("HEAD")),
74///     ..Default::default()
75/// };
76///
77/// let result = detect_changes(config).await?;
78/// println!("Files changed: {}", result.all_files.len());
79/// # Ok(())
80/// # }
81/// ```
82pub async fn detect_changes(config: InputConfig<'_>) -> Result<ProcessedResult> {
83    // Initialize string interner with reasonable capacity
84    let interner = StringInterner::with_capacity(2048);
85
86    // Open git repository
87    let repo = git::repository::GitRepository::discover(".")?;
88
89    // Ensure sufficient depth if configured
90    if config.fetch_depth > 0 {
91        repo.ensure_depth(config.fetch_depth).await?;
92    }
93
94    // Create processor and run
95    let processor = coordination::processor::FileProcessor::new(&repo, &interner, &config);
96    let result = processor.process().await?;
97
98    Ok(result)
99}
100
101/// Synchronous variant of `detect_changes`
102///
103/// This creates a new Tokio runtime and blocks on the async version.
104/// Prefer the async version if you're already in an async context.
105pub fn detect_changes_sync(config: InputConfig<'_>) -> Result<ProcessedResult> {
106    tokio::runtime::Runtime::new()
107        .map_err(|e| Error::Runtime(e.to_string()))?
108        .block_on(detect_changes(config))
109}
110
111#[cfg(test)]
112mod tests {
113    #[test]
114    fn test_library_version() {
115        // Smoke test to ensure library compiles
116        let _ = env!("CARGO_PKG_VERSION");
117    }
118}