provisioning/tools/build/clean-build.nu

432 lines
14 KiB
Plaintext
Raw Normal View History

2025-10-07 11:12:02 +01:00
#!/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
}
}