432 lines
14 KiB
Plaintext
432 lines
14 KiB
Plaintext
|
|
#!/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
|
||
|
|
}
|
||
|
|
}
|