diff --git a/src/analyze/api.rs b/src/analyze/api.rs new file mode 100644 index 0000000..e5fa879 --- /dev/null +++ b/src/analyze/api.rs @@ -0,0 +1,188 @@ +//! Public API for the analyze module. +//! +//! This module provides the main library entry points for programmatic usage +//! of the analyze functionality without CLI dependencies. +//! +//! # Examples +//! +//! ## Analyze Text for Known Errors +//! +//! ```rust,no_run +//! use dx_scope::{ +//! AnalyzeOptions, AnalyzeInput, AutoApprove, FoundConfig, +//! }; +//! use dx_scope::analyze::process_input; +//! +//! #[tokio::main] +//! async fn main() -> anyhow::Result<()> { +//! // Load configuration +//! let working_dir = std::env::current_dir()?; +//! let config = FoundConfig::empty(working_dir); +//! +//! // Prepare input +//! let log_content = std::fs::read_to_string("error.log")?; +//! let lines: Vec = log_content.lines().map(|s| s.to_string()).collect(); +//! let input = AnalyzeInput::from_lines(lines); +//! +//! // Configure options +//! let options = AnalyzeOptions::new( +//! config.known_error.clone(), +//! config.working_dir.clone(), +//! ); +//! +//! // Run analysis with auto-approve for fixes +//! let interaction = AutoApprove; +//! let status = process_input(&options, input, &interaction).await?; +//! +//! match status { +//! dx_scope::AnalyzeStatus::NoKnownErrorsFound => { +//! println!("No errors detected"); +//! } +//! dx_scope::AnalyzeStatus::KnownErrorFoundFixSucceeded => { +//! println!("Error found and fixed!"); +//! } +//! _ => println!("Error handling completed: {:?}", status), +//! } +//! +//! Ok(()) +//! } +//! ``` + +use crate::analyze::options::{AnalyzeInput, AnalyzeOptions}; +use crate::internal::prompts::UserInteraction; +use crate::shared::analyze::{AnalyzeStatus, process_lines as process_lines_internal}; +use anyhow::Result; +use std::io::Cursor; +use tokio::io::BufReader; +use tracing::{debug, info}; + +/// Process input for known errors and optionally run fixes. +/// +/// This is the main library entry point for analyzing text/logs programmatically. +/// It scans the input for known error patterns and can automatically apply fixes. +/// +/// # Arguments +/// +/// * `options` - Analyze options containing known errors and working directory +/// * `input` - Input source (file, stdin, or in-memory lines) +/// * `interaction` - Implementation of `UserInteraction` for fix prompts (use `AutoApprove` or `DenyAll`) +/// +/// # Returns +/// +/// Returns `AnalyzeStatus` indicating the outcome: +/// - `NoKnownErrorsFound` - No matches found +/// - `KnownErrorFoundNoFixFound` - Error matched but no fix available +/// - `KnownErrorFoundUserDenied` - User declined to run the fix +/// - `KnownErrorFoundFixFailed` - Fix was attempted but failed +/// - `KnownErrorFoundFixSucceeded` - Fix was successfully applied +/// +/// # Examples +/// +/// ## Analyze In-Memory Text +/// +/// ```rust +/// use dx_scope::{AnalyzeOptions, AnalyzeInput, AutoApprove}; +/// use dx_scope::analyze::process_input; +/// +/// let lines = vec![ +/// "Building project...".to_string(), +/// "error: dependency not found".to_string(), +/// ]; +/// let input = AnalyzeInput::from_lines(lines); +/// let options = AnalyzeOptions::default(); +/// // Call: process_input(&options, input, &AutoApprove).await +/// ``` +/// +/// ## Analyze a File +/// +/// ```rust +/// use dx_scope::{AnalyzeOptions, AnalyzeInput, DenyAll}; +/// use dx_scope::analyze::process_input; +/// +/// let options = AnalyzeOptions::default(); +/// let input = AnalyzeInput::from_file("/var/log/build.log"); +/// // Call: process_input(&options, input, &DenyAll).await +/// ``` +pub async fn process_input( + options: &AnalyzeOptions, + input: AnalyzeInput, + interaction: &U, +) -> Result +where + U: UserInteraction, +{ + debug!("Starting analyze with input type: {:?}", input); + + match input { + AnalyzeInput::File(path) => { + info!("Analyzing file: {:?}", path); + let file = tokio::fs::File::open(&path).await?; + let reader = BufReader::new(file); + process_lines_internal( + &options.known_errors, + &options.working_dir, + reader, + interaction, + ) + .await + } + AnalyzeInput::Stdin => { + info!("Analyzing stdin"); + let stdin = tokio::io::stdin(); + let reader = BufReader::new(stdin); + process_lines_internal( + &options.known_errors, + &options.working_dir, + reader, + interaction, + ) + .await + } + AnalyzeInput::Lines(lines) => { + info!("Analyzing {} lines from memory", lines.len()); + let text = lines.join("\n"); + let cursor = Cursor::new(text); + let reader = BufReader::new(cursor); + process_lines_internal( + &options.known_errors, + &options.working_dir, + reader, + interaction, + ) + .await + } + } +} + +/// Analyze text content directly for known errors. +/// +/// Convenience function for analyzing a string without creating an `AnalyzeInput`. +/// +/// # Arguments +/// +/// * `options` - Analyze options containing known errors and working directory +/// * `text` - Text content to analyze +/// * `interaction` - Implementation of `UserInteraction` for fix prompts +/// +/// # Examples +/// +/// ```rust +/// use dx_scope::{AnalyzeOptions, DenyAll}; +/// use dx_scope::analyze::process_text; +/// +/// let log_output = "error: compilation failed\nSome other output"; +/// let options = AnalyzeOptions::default(); +/// // Call: process_text(&options, log_output, &DenyAll).await +/// ``` +pub async fn process_text( + options: &AnalyzeOptions, + text: &str, + interaction: &U, +) -> Result +where + U: UserInteraction, +{ + let lines: Vec = text.lines().map(|s| s.to_string()).collect(); + let input = AnalyzeInput::from_lines(lines); + process_input(options, input, interaction).await +} diff --git a/src/analyze/mod.rs b/src/analyze/mod.rs index 37630a6..d474a3c 100644 --- a/src/analyze/mod.rs +++ b/src/analyze/mod.rs @@ -1,6 +1,15 @@ +mod api; mod cli; mod error; +pub mod options; pub mod prelude { pub use super::cli::{AnalyzeArgs, analyze_root}; } + +// Re-export key types for library usage +pub use crate::shared::analyze::{AnalyzeStatus, process_lines, report_result}; +pub use options::{AnalyzeInput, AnalyzeOptions}; + +// Public API functions +pub use api::{process_input, process_text}; diff --git a/src/lib.rs b/src/lib.rs index 46c9a24..5d5cd1c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,6 +25,14 @@ pub use internal::prompts::{AutoApprove, DenyAll, UserInteraction}; // Re-export CLI implementation for interactive applications pub use cli::InquireInteraction; +// Re-export analyze types at crate root +pub use analyze::{AnalyzeInput, AnalyzeOptions}; +pub use shared::analyze::AnalyzeStatus; + +// Re-export config types at crate root +pub use shared::config::ConfigLoadOptions; +pub use shared::prelude::FoundConfig; + /// Preferred way to output data to users. This macro will write the output to tracing for debugging /// and to stdout using the global stdout writer. Because we use the stdout writer, the calls /// will all be async.