#[allow(clippy::too_many_arguments)]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub async fn handle_refactor_docs(
project_path: PathBuf,
include_docs: bool,
include_root: bool,
additional_dirs: Vec<PathBuf>,
format: RefactorDocsOutputFormat,
dry_run: bool,
temp_patterns: Vec<String>,
status_patterns: Vec<String>,
artifact_patterns: Vec<String>,
custom_patterns: Vec<String>,
min_age_days: u32,
max_size_mb: u64,
recursive: bool,
preserve_patterns: Vec<String>,
output: Option<PathBuf>,
auto_remove: bool,
backup: bool,
backup_dir: PathBuf,
perf: bool,
) -> Result<()> {
let start_time = std::time::Instant::now();
let scan_dirs =
collect_scan_directories(&project_path, include_root, include_docs, additional_dirs);
let all_patterns = combine_patterns(
temp_patterns,
status_patterns,
artifact_patterns,
custom_patterns,
);
let mut result = perform_cruft_scan(
&scan_dirs,
&all_patterns,
&preserve_patterns,
min_age_days,
max_size_mb,
recursive,
)
.await?;
result =
handle_processing_modes(result, format, dry_run, auto_remove, backup, &backup_dir).await?;
output_results(&result, format, dry_run, perf, start_time.elapsed(), output).await?;
handle_exit_code(&result, auto_remove, dry_run);
Ok(())
}
fn collect_scan_directories(
project_path: &Path,
include_root: bool,
include_docs: bool,
additional_dirs: Vec<PathBuf>,
) -> Vec<PathBuf> {
let mut scan_dirs = Vec::new();
if include_root {
scan_dirs.push(project_path.to_path_buf());
}
if include_docs {
let docs_dir = project_path.join("docs");
if docs_dir.exists() {
scan_dirs.push(docs_dir);
}
}
scan_dirs.extend(additional_dirs);
scan_dirs
}
fn combine_patterns(
temp_patterns: Vec<String>,
status_patterns: Vec<String>,
artifact_patterns: Vec<String>,
custom_patterns: Vec<String>,
) -> Vec<(String, FileCategory)> {
let mut all_patterns = Vec::new();
all_patterns.extend(
temp_patterns
.into_iter()
.map(|p| (p, FileCategory::TemporaryScript)),
);
all_patterns.extend(
status_patterns
.into_iter()
.map(|p| (p, FileCategory::StatusReport)),
);
all_patterns.extend(
artifact_patterns
.into_iter()
.map(|p| (p, FileCategory::BuildArtifact)),
);
all_patterns.extend(
custom_patterns
.into_iter()
.map(|p| (p, FileCategory::CustomPattern)),
);
all_patterns
}
async fn perform_cruft_scan(
scan_dirs: &[PathBuf],
all_patterns: &[(String, FileCategory)],
preserve_patterns: &[String],
min_age_days: u32,
max_size_mb: u64,
recursive: bool,
) -> Result<RefactorDocsResult> {
let mut result = scan_for_cruft(
scan_dirs,
all_patterns,
preserve_patterns,
min_age_days,
max_size_mb * 1024 * 1024, recursive,
)
.await?;
result
.cruft_files
.sort_by_key(|b| std::cmp::Reverse(b.size_bytes));
Ok(result)
}
async fn handle_processing_modes(
mut result: RefactorDocsResult,
format: RefactorDocsOutputFormat,
dry_run: bool,
auto_remove: bool,
backup: bool,
backup_dir: &Path,
) -> Result<RefactorDocsResult> {
result = handle_interactive_processing(result, format, dry_run, auto_remove).await?;
handle_backup_processing(&result, backup, dry_run, auto_remove, backup_dir).await?;
handle_file_removal_processing(&result, dry_run, auto_remove, format).await?;
Ok(result)
}
async fn handle_interactive_processing(
result: RefactorDocsResult,
format: RefactorDocsOutputFormat,
dry_run: bool,
auto_remove: bool,
) -> Result<RefactorDocsResult> {
if should_use_interactive_mode(format, dry_run, auto_remove) {
handle_interactive_mode(result).await
} else {
Ok(result)
}
}
fn should_use_interactive_mode(
format: RefactorDocsOutputFormat,
dry_run: bool,
auto_remove: bool,
) -> bool {
format == RefactorDocsOutputFormat::Interactive && !dry_run && !auto_remove
}
async fn handle_backup_processing(
result: &RefactorDocsResult,
backup: bool,
dry_run: bool,
auto_remove: bool,
backup_dir: &Path,
) -> Result<()> {
if should_create_backup(backup, dry_run, &result.cruft_files, auto_remove) {
create_backup(&result.cruft_files, backup_dir).await?;
}
Ok(())
}
fn should_create_backup(
backup: bool,
dry_run: bool,
cruft_files: &[CruftFile],
auto_remove: bool,
) -> bool {
backup && !dry_run && (!cruft_files.is_empty() || auto_remove)
}
async fn handle_file_removal_processing(
result: &RefactorDocsResult,
dry_run: bool,
auto_remove: bool,
format: RefactorDocsOutputFormat,
) -> Result<()> {
if should_remove_files(dry_run, auto_remove, format) {
remove_files(&result.cruft_files).await?;
}
Ok(())
}
fn should_remove_files(dry_run: bool, auto_remove: bool, format: RefactorDocsOutputFormat) -> bool {
!dry_run && (auto_remove || format == RefactorDocsOutputFormat::Interactive)
}
async fn output_results(
result: &RefactorDocsResult,
format: RefactorDocsOutputFormat,
dry_run: bool,
perf: bool,
elapsed: std::time::Duration,
output: Option<PathBuf>,
) -> Result<()> {
let output_content = format_output(result, format, dry_run, perf, elapsed)?;
if let Some(output_path) = output {
tokio::fs::write(output_path, &output_content).await?;
} else {
println!("{output_content}");
}
Ok(())
}
fn handle_exit_code(result: &RefactorDocsResult, auto_remove: bool, dry_run: bool) {
if !result.cruft_files.is_empty() && !auto_remove && !dry_run {
std::process::exit(1); }
}