#!/usr/bin/env bash # check_packages.sh — Compare Ceph package counts between production and prerelease set -euo pipefail # ── Config ──────────────────────────────────────────────────────────────────── # Search locations per distro ( = prod or prerelease version): # deb jammy/focal/noble/bookworm/trixie: # prod: $PROD_BASE/debian-/ pre: $PRE_BASE/debian-/ # RPM centos9: # prod: $PROD_BASE/rpm-/el9/ pre: $PRE_BASE/rpm-/el9/ # RPM centos10 + rocky10 (shared el10 repo): # prod: $PROD_BASE/rpm-/el10/ pre: $PRE_BASE/rpm-/el10/ PROD_BASE="/data/download.ceph.com/www" PRE_BASE="/data/download.ceph.com/www/prerelease/ceph" TMPDIR_BASE=$(mktemp -d) trap 'rm -rf "$TMPDIR_BASE"' EXIT # ── Remembered values from last run ───────────────────────────────────────── STATE_FILE="${HOME}/.cache/ceph-packages-check/last_run" LAST_PRE_VERSION="" LAST_PROD_VERSION="" LAST_DISTROS="" if [[ -f "$STATE_FILE" ]]; then # shellcheck disable=SC1090 LAST_PRE_VERSION=$(grep '^LAST_PRE_VERSION=' "$STATE_FILE" | cut -d= -f2- | tr -d '"') LAST_PROD_VERSION=$(grep '^LAST_PROD_VERSION=' "$STATE_FILE" | cut -d= -f2- | tr -d '"') LAST_DISTROS=$(grep '^LAST_DISTROS=' "$STATE_FILE" | cut -d= -f2- | tr -d '"') fi save_state() { mkdir -p "$(dirname "$STATE_FILE")" cat > "$STATE_FILE" </dev/null >> "$tmpout" done # de-duplicate and sort sort -u "$tmpout" rm -f "$tmpout" } # ── Compare a single distro ─────────────────────────────────────────────────── compare() { local label="$1" local prod_dir="$2" local pre_dir="$3" local patterns="$4" # pipe-separated local pattern_label pattern_label=$(echo "$patterns" | tr '|' '/') PATH_ROWS+=("$label|$prod_dir|$pre_dir") local prod_list pre_list prod_list=$(mktemp "$TMPDIR_BASE/prod_XXXXXX") pre_list=$(mktemp "$TMPDIR_BASE/pre_XXXXXX") if [[ -d "$prod_dir" ]]; then find_by_patterns "$prod_dir" "$patterns" > "$prod_list" else touch "$prod_list" echo -e " ${YELLOW}WARNING: prod dir not found: $prod_dir${RESET}" fi if [[ -d "$pre_dir" ]]; then find_by_patterns "$pre_dir" "$patterns" > "$pre_list" else touch "$pre_list" echo -e " ${YELLOW}WARNING: prerelease dir not found: $pre_dir${RESET}" fi local prod_count pre_count prod_count=$(wc -l < "$prod_list") pre_count=$(wc -l < "$pre_list") printf " %-30s prod: %4d pre: %4d" "$label" "$prod_count" "$pre_count" if [[ "$prod_count" -eq "$pre_count" ]]; then echo -e " ${GREEN}✓ match${RESET}" add_summary "$label" "$pattern_label" "$prod_count" "$pre_count" "OK" return fi echo -e " ${RED}✗ MISMATCH (diff: $(( pre_count - prod_count )))${RESET}" add_summary "$label" "$pattern_label" "$prod_count" "$pre_count" "MISMATCH ($(( pre_count - prod_count )))" local only_prod only_pre only_prod=$(comm -23 "$prod_list" "$pre_list") only_pre=$(comm -13 "$prod_list" "$pre_list") if [[ -n "$only_prod" ]]; then echo -e "\n ${CYAN}Only in PROD (${PROD_VERSION}):${RESET}" echo "$only_prod" | sed 's/^/ /' fi if [[ -n "$only_pre" ]]; then echo -e "\n ${CYAN}Only in PRERELEASE (${PRE_VERSION}):${RESET}" echo "$only_pre" | sed 's/^/ /' fi echo } # ── Main ────────────────────────────────────────────────────────────────────── echo -e "\n${BOLD}Ceph Package Comparison Tool${RESET}" echo "────────────────────────────────────────" # 1. Prerelease version if [[ -n "$LAST_PRE_VERSION" ]]; then read -erp "$(echo -e "${CYAN}Prerelease version (e.g. 20.2.1) [${LAST_PRE_VERSION}]: ${RESET}")" PRE_VERSION PRE_VERSION="${PRE_VERSION:-$LAST_PRE_VERSION}" else read -erp "$(echo -e "${CYAN}Prerelease version (e.g. 20.2.1): ${RESET}")" PRE_VERSION fi [[ -z "$PRE_VERSION" ]] && { echo "Prerelease version required."; exit 1; } # 2. Prod version — default to patch-1, falling back to last-used value PROD_DEFAULT=$(decrement_patch "$PRE_VERSION") PROD_DEFAULT="${PROD_DEFAULT:-$LAST_PROD_VERSION}" if [[ -n "$PROD_DEFAULT" ]]; then read -erp "$(echo -e "${CYAN}Production version [${PROD_DEFAULT}]: ${RESET}")" PROD_VERSION PROD_VERSION="${PROD_VERSION:-$PROD_DEFAULT}" else read -erp "$(echo -e "${CYAN}Production version: ${RESET}")" PROD_VERSION fi [[ -z "$PROD_VERSION" ]] && { echo "Production version required."; exit 1; } # 3. Distros echo -e "${CYAN}Available distros: jammy focal noble bookworm trixie centos9 centos10 rocky10${RESET}" if [[ -n "$LAST_DISTROS" ]]; then read -erp "$(echo -e "${CYAN}Distros to check (space-separated) [${LAST_DISTROS}]: ${RESET}")" DISTROS_INPUT DISTROS_INPUT="${DISTROS_INPUT:-$LAST_DISTROS}" else read -erp "$(echo -e "${CYAN}Distros to check (space-separated): ${RESET}")" DISTROS_INPUT fi read -ra DISTROS <<< "$DISTROS_INPUT" [[ ${#DISTROS[@]} -eq 0 ]] && { echo "At least one distro required."; exit 1; } save_state echo echo -e "${BOLD}Prod:${RESET} ${PROD_VERSION} → ${PROD_BASE}/debian-${PROD_VERSION} | rpm-${PROD_VERSION}/" echo -e "${BOLD}Prerelease:${RESET} ${PRE_VERSION} → ${PRE_BASE}/debian-${PRE_VERSION} | rpm-${PRE_VERSION}/" echo "────────────────────────────────────────" # 4. Loop distros interactively for distro in "${DISTROS[@]}"; do echo if is_rpm_distro "$distro"; then local_el=$(el_version "$distro") read -erp "$(echo -e "${BOLD}Compare ${distro} (RPM/${local_el})? [Y/n]: ${RESET}")" yn [[ "${yn,,}" == "n" ]] && { echo -e " ${YELLOW}Skipped.${RESET}"; continue; } echo -e "${BOLD}[${distro}]${RESET}" prod_dir="$PROD_BASE/rpm-${PROD_VERSION}/${local_el}" pre_dir="$PRE_BASE/rpm-${PRE_VERSION}/${local_el}" compare "RPM (${distro}/${local_el})" "$prod_dir" "$pre_dir" "*.rpm" else patterns=$(distro_patterns "$distro") pattern_label=$(distro_pattern_label "$distro") read -erp "$(echo -e "${BOLD}Compare ${distro} (${pattern_label})? [Y/n]: ${RESET}")" yn [[ "${yn,,}" == "n" ]] && { echo -e " ${YELLOW}Skipped.${RESET}"; continue; } echo -e "${BOLD}[${distro}]${RESET}" prod_dir="$PROD_BASE/debian-${PROD_VERSION}" pre_dir="$PRE_BASE/debian-${PRE_VERSION}" compare "deb ($distro)" "$prod_dir" "$pre_dir" "$patterns" fi done print_paths print_summary echo -e "\n${BOLD}Done.${RESET}\n"