/****************************************************************************** __ ____ __ / / ___ ____ _/ __/_____________ _/ /__ / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ (C)opyright 2025, Leafscale, LLC - https://www.leafscale.com Project: Zygaena Filename: clean.reef Authors: Chris Tusa License: Description: Clean command - remove build artifacts and caches ******************************************************************************/ module commands.clean import sys.args import sys.process import io.file import io.dir import io.path import core.str import core.config import types import util.color import exitcodes as ec import core.result as res export fn execute(): int end export fn execute(): int let argc = args.count() if argc < 3 print_usage() return ec.EXIT_USAGE() end if let subcommand = args.get(2) // Load config let cfg = config.load() if subcommand == "status" return show_status(cfg) elif subcommand == "sources" return clean_sources(cfg) elif subcommand == "packages" return clean_packages(cfg) elif subcommand == "build" return clean_build(cfg) elif subcommand == "all" return clean_all(cfg) else color.print_error("Unknown subcommand: " + subcommand) print_usage() return ec.EXIT_USAGE() end if end execute fn show_status(cfg: config.Config): int color.print_action("Build artifact status:") println("") // Built packages let packages_dir = config.get_packages_dir(cfg) let pkg_count = count_files(packages_dir, ".pkg.tar.xz") mut pkg_protected = "" if config.get_keep_packages(cfg) pkg_protected = " [protected]" end if println(" Packages (" + packages_dir + "):" + pkg_protected) println(" " + int_to_str(pkg_count) + " built package(s)") // Source tarballs let sources_dir = config.get_sources_dir(cfg) let src_count = count_files(sources_dir, "") mut src_protected = "" if config.get_keep_sources(cfg) src_protected = " [protected]" end if println(" Sources (" + sources_dir + "):" + src_protected) println(" " + int_to_str(src_count) + " source archive(s)") // Build workspace let build_dir = config.get_build_dir(cfg) let build_count = count_subdirs(build_dir) println(" Build (" + build_dir + "):") println(" " + int_to_str(build_count) + " build workspace(s)") return ec.EXIT_SUCCESS() end show_status fn clean_sources(cfg: config.Config): int // Respect keep_sources config unless --force is passed if config.get_keep_sources(cfg) and not args.has_flag("force") color.print_warning("Source cache is configured to be preserved (keep_sources = true)") color.print_info("Use --force to override") return ec.EXIT_SUCCESS() end if let sources_dir = config.get_sources_dir(cfg) color.print_action("Cleaning source archives...") println(" Location: " + sources_dir) if not dir.dir_exists(sources_dir) color.print_info("No sources directory to clean") return ec.EXIT_SUCCESS() end if let cmd = "rm -rf \"" + sources_dir + "\"/*" let pid = process.process_spawn_shell(cmd) if pid > 0 process.process_wait(pid) end if color.print_success("Source archives cleaned") return ec.EXIT_SUCCESS() end clean_sources fn clean_packages(cfg: config.Config): int // Respect keep_packages config unless --force is passed if config.get_keep_packages(cfg) and not args.has_flag("force") color.print_warning("Package cache is configured to be preserved (keep_packages = true)") color.print_info("Use --force to override") return ec.EXIT_SUCCESS() end if let packages_dir = config.get_packages_dir(cfg) color.print_action("Cleaning built packages...") println(" Location: " + packages_dir) if not dir.dir_exists(packages_dir) color.print_info("No packages directory to clean") return ec.EXIT_SUCCESS() end if let cmd = "rm -rf \"" + packages_dir + "\"/*" let pid = process.process_spawn_shell(cmd) if pid > 0 process.process_wait(pid) end if color.print_success("Built packages cleaned") return ec.EXIT_SUCCESS() end clean_packages fn clean_build(cfg: config.Config): int let build_dir = config.get_build_dir(cfg) color.print_action("Cleaning build workspaces...") println(" Location: " + build_dir) if not dir.dir_exists(build_dir) color.print_info("No build directory to clean") return ec.EXIT_SUCCESS() end if let cmd = "rm -rf \"" + build_dir + "\"/*" let pid = process.process_spawn_shell(cmd) if pid > 0 process.process_wait(pid) end if color.print_success("Build workspaces cleaned") return ec.EXIT_SUCCESS() end clean_build fn clean_all(cfg: config.Config): int color.print_action("Cleaning all build artifacts...") println("") clean_sources(cfg) clean_packages(cfg) clean_build(cfg) println("") color.print_success("All build artifacts cleaned") return ec.EXIT_SUCCESS() end clean_all fn count_files(dir_path: string, extension: string): int if not dir.dir_exists(dir_path) return 0 end if let entries = res.unwrap_or(dir.list_dir(dir_path), new [string](0)) let count = entries.length() if str.length(extension) == 0 return count end if mut matched = 0 mut i = 0 while i < count if str.ends_with(entries[i], extension) matched = matched + 1 end if i = i + 1 end while return matched end count_files fn count_subdirs(dir_path: string): int if not dir.dir_exists(dir_path) return 0 end if let entries = res.unwrap_or(dir.list_dir(dir_path), new [string](0)) let count = entries.length() // Count only directories (packages being built) mut dirs = 0 mut i = 0 while i < count let entry = entries[i] if str.length(entry) > 0 and entry[0] != '.' let full_path = path.join_path(dir_path, entry) if dir.dir_exists(full_path) dirs = dirs + 1 end if end if i = i + 1 end while return dirs end count_subdirs proc print_usage() println("Usage: coral clean ") println("") println("Remove build artifacts and cached files.") println("") println("Targets:") println(" status Show what can be cleaned") println(" sources Remove downloaded source archives") println(" packages Remove built binary packages") println(" build Remove build workspaces") println(" all Remove all of the above") println("") println("Locations:") println(" sources: /usr/zports/pkgs/sources/") println(" packages: /usr/zports/pkgs/packages/") println(" build: /usr/zports/pkgs/build/") println("") println("Options:") println(" --force Override keep_packages/keep_sources config protection") println("") println("Note: This does NOT affect installed packages or the package database.") println(" Use 'coral remove' to uninstall packages.") println("") println("Examples:") println(" coral clean status") println(" coral clean build") println(" coral clean all") end print_usage // Helper: convert int to string fn int_to_str(n: int): string if n == 0 return "0" end if mut negative = false mut value = n if n < 0 negative = true value = 0 - n end if mut result = "" while value > 0 let digit = value % 10 result = str.concat(str.substring("0123456789", digit, 1), result) value = value / 10 end while if negative result = str.concat("-", result) end if return result end int_to_str end module