Skip to main content

cargo_mate/sweeping/
mod.rs

1use anyhow::Result;
2use clap::{Parser, Subcommand};
3use colored::*;
4use std::path::PathBuf;
5#[derive(Parser, Debug)]
6#[command(name = "sweep")]
7#[command(about = "๐Ÿงน Sweep - Debug statement cleaner and code formatter")]
8pub struct SweepCli {
9    #[command(subcommand)]
10    command: SweepCommands,
11    #[arg(short, long)]
12    verbose: bool,
13}
14#[derive(Subcommand, Debug, Clone)]
15pub enum SweepCommands {
16    Scan {
17        #[arg(default_value = ".")]
18        path: PathBuf,
19        #[arg(long)]
20        include_tests: bool,
21        #[arg(long)]
22        include_examples: bool,
23        #[arg(long)]
24        export: Option<PathBuf>,
25    },
26    Sweep {
27        #[arg(default_value = ".")]
28        path: PathBuf,
29        #[arg(long)]
30        dry_run: bool,
31        #[arg(long)]
32        interactive: bool,
33        #[arg(long)]
34        prompt: bool,
35        #[arg(long)]
36        keep_main: bool,
37        #[arg(long)]
38        keep_tests: bool,
39        #[arg(long)]
40        keep_examples: bool,
41        #[arg(long)]
42        backup: bool,
43        #[arg(long)]
44        yes: bool,
45        #[arg(long)]
46        pristine: bool,
47        #[arg(long)]
48        format: bool,
49        #[arg(long)]
50        organize_imports: bool,
51        #[arg(long)]
52        add_docs: bool,
53        #[arg(long)]
54        fix_clippy: bool,
55    },
56    Convert {
57        #[arg(default_value = ".")]
58        path: PathBuf,
59        #[arg(long)]
60        println_level: Option<String>,
61        #[arg(long)]
62        eprintln_level: Option<String>,
63        #[arg(long)]
64        dry_run: bool,
65        #[arg(long)]
66        add_dependency: bool,
67    },
68    Analyze {
69        #[arg(default_value = ".")]
70        path: PathBuf,
71        #[arg(long, default_value = "10")]
72        top: usize,
73    },
74    Init { #[arg(long)] force: bool },
75    Help,
76}
77pub fn run_sweep(command: SweepCommands, verbose: bool) -> Result<()> {
78    match command {
79        SweepCommands::Scan { path, include_tests, include_examples, export } => {
80            println!("๐Ÿ” Scanning for print statements in: {}", path.display());
81            let sweeper = crate::sweeping::src::away::Sweeper::new();
82            let statements = sweeper
83                .scan_directory(&path, include_tests, include_examples)?;
84            if statements.is_empty() {
85                println!("{}", "โœจ Clean! No print statements found.".green());
86                return Ok(());
87            }
88            println!("\n{}\n", "๐Ÿ“‹ Scan Results".bold().blue());
89            println!("{}", "โ”€".repeat(60).dimmed());
90            for stmt in &statements {
91                sweeper.display_statement(stmt);
92            }
93            println!("\n{}: {}", "Total".bold(), statements.len());
94            if let Some(export_path) = export {
95                crate::sweeping::src::away::export_to_json(&statements, &export_path)?;
96                println!("๐Ÿ“„ Results exported to: {}", export_path.display());
97            }
98        }
99        SweepCommands::Sweep {
100            path,
101            dry_run,
102            interactive,
103            prompt,
104            keep_main,
105            keep_tests,
106            keep_examples,
107            backup,
108            yes,
109            pristine,
110            format,
111            organize_imports,
112            add_docs,
113            fix_clippy,
114        } => {
115            println!("๐Ÿงน Cleaning debug statements in: {}", path.display());
116            let sweeper = crate::sweeping::src::away::Sweeper::new();
117            let statements = sweeper.scan_directory(&path, !keep_tests, !keep_examples)?;
118            if statements.is_empty() {
119                println!("{}", "โœจ Already clean! No print statements found.".green());
120                return Ok(());
121            }
122            println!("Found {} print statements to process", statements.len());
123            if dry_run {
124                println!("{}", "๐Ÿ” DRY RUN - Showing what would be changed:".yellow());
125            }
126            let mut sweeper = crate::sweeping::src::away::Sweeper::new();
127            sweeper.load_config(&std::path::PathBuf::from(".sweep.toml"))?;
128            let options = crate::sweeping::src::away::SweepOptions {
129                dry_run,
130                interactive,
131                prompt,
132                keep_main,
133                keep_tests,
134                keep_examples,
135                backup,
136                yes,
137            };
138            sweeper
139                .sweep_files(
140                    statements,
141                    &options,
142                    &std::path::PathBuf::from(".sweep.toml"),
143                )?;
144        }
145        SweepCommands::Convert {
146            path,
147            println_level,
148            eprintln_level,
149            dry_run,
150            add_dependency,
151        } => {
152            println!(
153                "๐Ÿ”„ Converting print statements to logging in: {}", path.display()
154            );
155            let sweeper = crate::sweeping::src::away::Sweeper::new();
156            let statements = sweeper.scan_directory(&path, true, true)?;
157            if statements.is_empty() {
158                println!("{}", "โœจ No print statements found to convert!".green());
159                return Ok(());
160            }
161            let println_level = println_level
162                .map(|s| {
163                    match s.to_lowercase().as_str() {
164                        "trace" => crate::sweeping::src::away::LogLevel::Trace,
165                        "info" => crate::sweeping::src::away::LogLevel::Info,
166                        "warn" => crate::sweeping::src::away::LogLevel::Warn,
167                        "error" => crate::sweeping::src::away::LogLevel::Error,
168                        _ => crate::sweeping::src::away::LogLevel::Debug,
169                    }
170                })
171                .unwrap_or(crate::sweeping::src::away::LogLevel::Debug);
172            let eprintln_level = eprintln_level
173                .map(|s| {
174                    match s.to_lowercase().as_str() {
175                        "trace" => crate::sweeping::src::away::LogLevel::Trace,
176                        "info" => crate::sweeping::src::away::LogLevel::Info,
177                        "warn" => crate::sweeping::src::away::LogLevel::Warn,
178                        "error" => crate::sweeping::src::away::LogLevel::Error,
179                        _ => crate::sweeping::src::away::LogLevel::Error,
180                    }
181                })
182                .unwrap_or(crate::sweeping::src::away::LogLevel::Error);
183            let mut converted = 0;
184            let mut files_modified = 0;
185            for stmt in statements {
186                if !dry_run {
187                    if let Err(e) = crate::sweeping::src::away::convert_statement_in_file(
188                        &stmt.file,
189                        &stmt.content,
190                        &stmt.content,
191                    ) {
192                        eprintln!("Error converting {}: {}", stmt.file.display(), e);
193                        continue;
194                    }
195                    converted += 1;
196                    files_modified += 1;
197                } else {
198                    println!(
199                        "Would convert: {} at {}:{}", stmt.file.display(), stmt.line,
200                        stmt.column
201                    );
202                    converted += 1;
203                }
204            }
205            if dry_run {
206                println!(
207                    "{} Would convert {} statements across {} files", "๐Ÿ”".yellow(),
208                    converted, files_modified
209                );
210            } else {
211                println!(
212                    "{} Converted {} statements across {} files", "โœ…".green(),
213                    converted, files_modified
214                );
215            }
216        }
217        SweepCommands::Analyze { path, top } => {
218            println!("๐Ÿ“Š Analyzing print statement patterns in: {}", path.display());
219            let sweeper = crate::sweeping::src::away::Sweeper::new();
220            let statements = sweeper.scan_directory(&path, true, true)?;
221            if statements.is_empty() {
222                println!(
223                    "{}", "โœจ Perfectly clean! No print statements found.".green()
224                );
225                return Ok(());
226            }
227            let report = sweeper.analyze_patterns(&statements, top);
228            sweeper.display_report(&report);
229        }
230        SweepCommands::Init { force } => {
231            println!("โš™๏ธ  Initializing sweep configuration...");
232            let config_path = std::path::PathBuf::from(".sweep.toml");
233            if config_path.exists() && !force {
234                println!(
235                    "{} Config file already exists. Use --force to overwrite.", "โš ๏ธ"
236                    .yellow()
237                );
238                return Ok(());
239            }
240            crate::sweeping::src::away::create_default_config(&config_path)?;
241            println!(
242                "{} Configuration initialized at: {}", "โœ…".green(), config_path
243                .display()
244            );
245        }
246        SweepCommands::Help => {
247            println!("๐Ÿงน Sweep - Debug statement cleaner and code formatter");
248            println!("\nCommands:");
249            println!("  scan     - Scan for print statements");
250            println!("  sweep    - Clean debug statements");
251            println!("  convert  - Convert to logging");
252            println!("  analyze  - Analyze patterns");
253            println!("  init     - Initialize configuration");
254            println!("  help     - Show this help message");
255            return Ok(());
256        }
257    }
258    Ok(())
259}
260pub mod src;