#!/usr/bin/env nu # Build cleanup tool - cleans build artifacts and temporary files # # Cleans: # - Rust target directories # - Distribution artifacts # - Temporary build files # - Cache directories # - Test artifacts use std log def main [ --scope: string = "build" # Cleanup scope: build, dist, cache, temp, all --dry-run: bool = false # Show what would be cleaned without actually doing it --force: bool = false # Force cleanup without confirmation --exclude: string = "" # Comma-separated patterns to exclude --verbose: bool = false # Enable verbose logging ] -> record { let repo_root = ($env.PWD | path dirname | path dirname | path dirname) let cleanup_config = { scope: ($scope | split row "," | each { str trim }) dry_run: $dry_run force: $force exclude_patterns: ($exclude | if $in == "" { [] } else { $in | split row "," | each { str trim } }) verbose: $verbose repo_root: $repo_root } log info $"Starting cleanup with config: ($cleanup_config)" let cleanup_results = [] # Determine cleanup categories let cleanup_categories = if "all" in $cleanup_config.scope { ["build", "dist", "cache", "temp"] } else { $cleanup_config.scope } # Run cleanup for each category for category in $cleanup_categories { let category_result = match $category { "build" => { clean_build_artifacts $cleanup_config } "dist" => { clean_distribution_artifacts $cleanup_config } "cache" => { clean_cache_directories $cleanup_config } "temp" => { clean_temporary_files $cleanup_config } _ => { log warning $"Unknown cleanup category: ($category)" { category: $category, status: "skipped", reason: "unknown category" } } } let cleanup_results = ($cleanup_results | append $category_result) } let summary = { total_categories: ($cleanup_results | length) successful_categories: ($cleanup_results | where status == "success" | length) skipped_categories: ($cleanup_results | where status == "skipped" | length) total_size_cleaned: ($cleanup_results | get size_cleaned | math sum) total_files_cleaned: ($cleanup_results | get files_cleaned | math sum) cleanup_config: $cleanup_config results: $cleanup_results } if $cleanup_config.dry_run { log info $"Dry run completed - would clean ($summary.total_files_cleaned) files totaling ($summary.total_size_cleaned) bytes" } else { log info $"Cleanup completed successfully - cleaned ($summary.total_files_cleaned) files totaling ($summary.total_size_cleaned) bytes" } return $summary } # Clean build artifacts def clean_build_artifacts [cleanup_config: record] -> record { log info "Cleaning build artifacts..." let start_time = (date now) let mut cleaned_files = 0 let mut cleaned_size = 0 # Find all Rust target directories let rust_projects = find_rust_projects $cleanup_config.repo_root for project in $rust_projects { let target_dir = ($project.path | path join "target") if ($target_dir | path exists) and (not (should_exclude $target_dir $cleanup_config.exclude_patterns)) { let dir_info = get_directory_info $target_dir if $cleanup_config.verbose { log info $"Found Rust target directory: ($target_dir) (($dir_info.files) files, ($dir_info.size) bytes)" } if not $cleanup_config.dry_run { if $cleanup_config.force or (confirm_deletion $target_dir "Rust target directory") { rm -rf $target_dir log info $"Cleaned: ($target_dir)" } } $cleaned_files = $cleaned_files + $dir_info.files $cleaned_size = $cleaned_size + $dir_info.size } } # Clean other build artifacts let build_artifacts = [ "*.o" "*.a" "*.so" "*.dylib" "*.dll" "*.pdb" "*.exe.debug" "Cargo.lock.bak" ] for pattern in $build_artifacts { let found_files = find $cleanup_config.repo_root -name $pattern -type f for file in $found_files { if not (should_exclude $file $cleanup_config.exclude_patterns) { let file_size = (ls $file | get 0.size) if $cleanup_config.verbose { log info $"Found build artifact: ($file) (($file_size) bytes)" } if not $cleanup_config.dry_run { if $cleanup_config.force or (confirm_deletion $file "build artifact") { rm $file log info $"Cleaned: ($file)" } } $cleaned_files = $cleaned_files + 1 $cleaned_size = $cleaned_size + $file_size } } } { category: "build" status: "success" files_cleaned: $cleaned_files size_cleaned: $cleaned_size duration: ((date now) - $start_time) } } # Clean distribution artifacts def clean_distribution_artifacts [cleanup_config: record] -> record { log info "Cleaning distribution artifacts..." let start_time = (date now) let mut cleaned_files = 0 let mut cleaned_size = 0 # Clean dist directory let dist_dir = ($cleanup_config.repo_root | path join "dist") if ($dist_dir | path exists) and (not (should_exclude $dist_dir $cleanup_config.exclude_patterns)) { let dir_info = get_directory_info $dist_dir if $cleanup_config.verbose { log info $"Found distribution directory: ($dist_dir) (($dir_info.files) files, ($dir_info.size) bytes)" } if not $cleanup_config.dry_run { if $cleanup_config.force or (confirm_deletion $dist_dir "distribution directory") { rm -rf $dist_dir log info $"Cleaned: ($dist_dir)" } } $cleaned_files = $cleaned_files + $dir_info.files $cleaned_size = $cleaned_size + $dir_info.size } # Clean packaged distributions let package_patterns = [ "*.tar.gz" "*.zip" "*.deb" "*.rpm" "*.msi" "*.dmg" ] for pattern in $package_patterns { let found_files = find $cleanup_config.repo_root -name $pattern -type f -maxdepth 2 for file in $found_files { if not (should_exclude $file $cleanup_config.exclude_patterns) { let file_size = (ls $file | get 0.size) if $cleanup_config.verbose { log info $"Found package file: ($file) (($file_size) bytes)" } if not $cleanup_config.dry_run { if $cleanup_config.force or (confirm_deletion $file "package file") { rm $file log info $"Cleaned: ($file)" } } $cleaned_files = $cleaned_files + 1 $cleaned_size = $cleaned_size + $file_size } } } { category: "dist" status: "success" files_cleaned: $cleaned_files size_cleaned: $cleaned_size duration: ((date now) - $start_time) } } # Clean cache directories def clean_cache_directories [cleanup_config: record] -> record { log info "Cleaning cache directories..." let start_time = (date now) let mut cleaned_files = 0 let mut cleaned_size = 0 # Cache directories to clean let cache_dirs = [ ($cleanup_config.repo_root | path join ".cache") ($cleanup_config.repo_root | path join "target" "debug" "incremental") ($cleanup_config.repo_root | path join "target" "release" "incremental") ($env.HOME | path join ".cargo" "registry" "cache") ] for cache_dir in $cache_dirs { if ($cache_dir | path exists) and (not (should_exclude $cache_dir $cleanup_config.exclude_patterns)) { let dir_info = get_directory_info $cache_dir if $cleanup_config.verbose { log info $"Found cache directory: ($cache_dir) (($dir_info.files) files, ($dir_info.size) bytes)" } if not $cleanup_config.dry_run { if $cleanup_config.force or (confirm_deletion $cache_dir "cache directory") { rm -rf $cache_dir log info $"Cleaned: ($cache_dir)" } } $cleaned_files = $cleaned_files + $dir_info.files $cleaned_size = $cleaned_size + $dir_info.size } } { category: "cache" status: "success" files_cleaned: $cleaned_files size_cleaned: $cleaned_size duration: ((date now) - $start_time) } } # Clean temporary files def clean_temporary_files [cleanup_config: record] -> record { log info "Cleaning temporary files..." let start_time = (date now) let mut cleaned_files = 0 let mut cleaned_size = 0 # Temporary file patterns let temp_patterns = [ "*~" "*.tmp" "*.bak" "*.swp" ".DS_Store" "Thumbs.db" "*.log" "core.*" "nohup.out" ] for pattern in $temp_patterns { let found_files = find $cleanup_config.repo_root -name $pattern -type f for file in $found_files { if not (should_exclude $file $cleanup_config.exclude_patterns) { let file_size = (ls $file | get 0.size) if $cleanup_config.verbose { log info $"Found temporary file: ($file) (($file_size) bytes)" } if not $cleanup_config.dry_run { if $cleanup_config.force or (confirm_deletion $file "temporary file") { rm $file log info $"Cleaned: ($file)" } } $cleaned_files = $cleaned_files + 1 $cleaned_size = $cleaned_size + $file_size } } } # Clean empty directories let empty_dirs = find $cleanup_config.repo_root -type d -empty for empty_dir in $empty_dirs { if not (should_exclude $empty_dir $cleanup_config.exclude_patterns) { if $cleanup_config.verbose { log info $"Found empty directory: ($empty_dir)" } if not $cleanup_config.dry_run { if $cleanup_config.force or (confirm_deletion $empty_dir "empty directory") { rmdir $empty_dir log info $"Cleaned: ($empty_dir)" } } $cleaned_files = $cleaned_files + 1 } } { category: "temp" status: "success" files_cleaned: $cleaned_files size_cleaned: $cleaned_size duration: ((date now) - $start_time) } } # Find all Rust projects in the repository def find_rust_projects [repo_root: string] -> list { find $repo_root -name "Cargo.toml" -type f | each {|cargo_file| { path: ($cargo_file | path dirname) cargo_file: $cargo_file } } } # Get directory information (file count and total size) def get_directory_info [dir: string] -> record { if not ($dir | path exists) { return { files: 0, size: 0 } } let files = try { find $dir -type f | length } catch { 0 } let size = try { find $dir -type f | each {|file| ls $file | get 0.size } | math sum } catch { 0 } return { files: $files, size: ($size | if $in == null { 0 } else { $in }) } } # Check if a path should be excluded based on patterns def should_exclude [path: string, patterns: list] -> bool { if ($patterns | length) == 0 { return false } return ($patterns | any {|pattern| $path =~ $pattern }) } # Confirm deletion with user (unless forced) def confirm_deletion [path: string, type: string] -> bool { let response = (input $"Delete ($type): ($path)? [y/N] ") return ($response | str downcase | str starts-with "y") } # Show what would be cleaned without actually cleaning def "main preview" [ --scope: string = "build" # Preview scope: build, dist, cache, temp, all --exclude: string = "" # Comma-separated patterns to exclude ] { main --scope $scope --exclude $exclude --dry-run --verbose } # Show cleanup statistics def "main stats" [] { let repo_root = ($env.PWD | path dirname | path dirname | path dirname) let rust_targets = find_rust_projects $repo_root | each {|project| let target_dir = ($project.path | path join "target") if ($target_dir | path exists) { let info = get_directory_info $target_dir { project: ($project.path | path basename), target_size: $info.size, files: $info.files } } else { { project: ($project.path | path basename), target_size: 0, files: 0 } } } let dist_dir = ($repo_root | path join "dist") let dist_info = if ($dist_dir | path exists) { get_directory_info $dist_dir } else { { files: 0, size: 0 } } { repository_root: $repo_root rust_projects: ($rust_targets | length) total_target_size: ($rust_targets | get target_size | math sum) total_target_files: ($rust_targets | get files | math sum) distribution_size: $dist_info.size distribution_files: $dist_info.files projects: $rust_targets } }