#!/bin/bash # Omarchy Repository Cleaner # Removes old package versions keeping only the latest set -e # Source common functions BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..") source "$BUILD_ROOT/helpers/message-helpers.sh" source "$BUILD_ROOT/helpers/paths.sh" source "$BUILD_ROOT/helpers/lock-helpers.sh" # Repository configuration KEEP_VERSIONS=2 # Function to clean old packages clean_packages() { local keep=$1 local dry_run=$2 print_info "Cleaning old packages (keeping $keep versions)..." cd "$REPO_DIR" # Group packages by name declare -A packages for pkg in *.pkg.tar.*; do [[ -f "$pkg" ]] || continue # Skip signature files [[ "$pkg" == *.sig ]] && continue # Extract package name (remove version and architecture) # Format: name-version-release-arch.pkg.tar.* local pkgname=$(echo "$pkg" | sed -E 's/-[0-9]+.*-(any|x86_64|i686)\.pkg\.tar\..*//') # Add to array if [[ -n "${packages[$pkgname]}" ]]; then packages[$pkgname]="${packages[$pkgname]} $pkg" else packages[$pkgname]="$pkg" fi done # Process each package group local total_removed=0 local space_freed=0 for pkgname in "${!packages[@]}"; do # Convert string to array and sort by modification time (newest first) IFS=' ' read -ra pkg_files <<<"${packages[$pkgname]}" # Sort by modification time local sorted_files=($(ls -t "${pkg_files[@]}" 2>/dev/null)) local count=${#sorted_files[@]} if [[ $count -gt $keep ]]; then echo " -> Processing $pkgname ($count versions found)" # Remove old versions for ((i = $keep; i < $count; i++)); do local file="${sorted_files[$i]}" local size=$(stat -c%s "$file" 2>/dev/null || echo 0) space_freed=$((space_freed + size)) if [[ "$dry_run" == true ]]; then echo " Would remove: $file ($(numfmt --to=iec-i --suffix=B $size))" else echo " Removing: $file ($(numfmt --to=iec-i --suffix=B $size))" rm -f "$file" rm -f "${file}.sig" 2>/dev/null || true fi total_removed=$((total_removed + 1)) done fi done # Summary if [[ $total_removed -gt 0 ]]; then if [[ "$dry_run" == true ]]; then echo " -> Would remove $total_removed old package(s)" echo " -> Would free $(numfmt --to=iec-i --suffix=B $space_freed)" else echo " -> Removed $total_removed old package(s)" echo " -> Freed $(numfmt --to=iec-i --suffix=B $space_freed)" fi else echo " -> No old packages to remove" fi } # Function to remove all packages remove_all_packages() { local dry_run=$1 print_error "WARNING: Removing ALL packages from repository!" if [[ "$dry_run" != true ]]; then read -p "Are you sure? Type 'yes' to confirm: " confirm if [[ "$confirm" != "yes" ]]; then print_warning "Cancelled." exit 0 fi fi cd "$REPO_DIR" local count=$(ls -1 *.pkg.tar.* 2>/dev/null | wc -l) if [[ $count -eq 0 ]]; then print_warning "No packages found to remove" return fi if [[ "$dry_run" == true ]]; then print_warning "Would remove $count package(s):" ls -1 *.pkg.tar.* 2>/dev/null | while read -r pkg; do echo " - $pkg" done else rm -f *.pkg.tar.* rm -f *.db* *.files* echo "Removed $count package(s) and database files" fi } # Function to show repository disk usage show_disk_usage() { print_info "Repository Disk Usage:" cd "$REPO_DIR" local total_size=$(du -sh . 2>/dev/null | cut -f1) local package_count=$(ls -1 *.pkg.tar.* 2>/dev/null | grep -v '\.sig$' | wc -l) echo " -> Total size: $total_size" echo " -> Package count: $package_count" if [[ $package_count -gt 0 ]]; then local avg_size=$(du -b *.pkg.tar.* 2>/dev/null | awk '{sum+=$1; count++} END {printf "%.0f", sum/count}') echo " -> Average package size: $(numfmt --to=iec-i --suffix=B $avg_size 2>/dev/null || echo "N/A")" fi } # Main execution main() { print_header "Omarchy Repository Cleaner" # Parse command line arguments DRY_RUN=false REMOVE_ALL=false SHOW_USAGE=false while [[ $# -gt 0 ]]; do case $1 in --arch) ARCH="$2" update_arch_paths shift 2 ;; --mirror) MIRROR="$2" require_valid_mirror "$MIRROR" update_arch_paths shift 2 ;; --keep) KEEP_VERSIONS="$2" shift 2 ;; --dry-run) DRY_RUN=true shift ;; --all) REMOVE_ALL=true shift ;; --usage) SHOW_USAGE=true shift ;; -h | --help) echo "Usage: $0 [OPTIONS]" echo "" echo "Options:" echo " --arch Target architecture (x86_64 or aarch64, default: x86_64)" echo " --mirror Mirror to use (edge, rc, or stable, default: edge)" echo " --keep N Keep N versions of each package (default: 2)" echo " --dry-run Preview what would be removed without removing" echo " --all Remove ALL packages (dangerous!)" echo " --usage Show disk usage statistics" echo " -h, --help Show this help message" echo "" echo "Examples:" echo " $0 # Keep 2 versions (default)" echo " $0 --keep 3 # Keep 3 versions" echo " $0 --dry-run # Preview cleanup" echo " $0 --all --dry-run # Preview complete removal" exit 0 ;; *) print_error "Unknown option: $1" exit 1 ;; esac done print_info "Mirror: $MIRROR" print_info "Architecture: $ARCH" print_info "Repository: $REPO_DIR" echo "" # Validate keep versions if ! [[ "$KEEP_VERSIONS" =~ ^[0-9]+$ ]] || [[ "$KEEP_VERSIONS" -lt 1 ]]; then print_error "Error: --keep must be a positive integer" exit 1 fi # Show dry run notice if [[ "$DRY_RUN" == true ]]; then print_warning "DRY RUN MODE - No changes will be made" fi if [[ "$DRY_RUN" != true && "$SHOW_USAGE" != true ]]; then acquire_release_lock || exit 1 fi # Execute based on options if [[ "$SHOW_USAGE" == true ]]; then show_disk_usage elif [[ "$REMOVE_ALL" == true ]]; then remove_all_packages "$DRY_RUN" else clean_packages "$KEEP_VERSIONS" "$DRY_RUN" # Update database after cleaning (unless dry run) if [[ "$DRY_RUN" != true ]]; then # Moved to release workflow : fi show_disk_usage fi } # Run main function main "$@"