#!/usr/bin/env bash # apk_retention.sh — Build-Historie-Bereinigung für Timetrack APKs # # Retention-Strategie: # Aktuelle Minor-Version → letzte 15 APKs nach Build-Nummer behalten # Ältere Minor-Versionen → je eine APK behalten (höchste Build-Nummer = Release-Marker) # # Verwendung: # bash scripts/apk_retention.sh [--dir build/apk] [--keep 15] [--dry-run] # # Dateiname-Format: timetrack-{VERSION}+{BUILD}.apk # Beispiele: timetrack-0.1.0+1.apk timetrack-0.2.0+3.apk set -euo pipefail # ── Defaults ────────────────────────────────────────────────────────────────── APK_DIR="build/apk" KEEP=15 DRY_RUN=false # ── Argument-Parsing ────────────────────────────────────────────────────────── while [[ $# -gt 0 ]]; do case "$1" in --dir) APK_DIR="$2"; shift 2 ;; --keep) KEEP="$2"; shift 2 ;; --dry-run) DRY_RUN=true; shift ;; *) echo "Unbekanntes Argument: $1" >&2; exit 1 ;; esac done # ── Verzeichnis prüfen ──────────────────────────────────────────────────────── if [[ ! -d "$APK_DIR" ]]; then echo "apk_retention: Verzeichnis '$APK_DIR' nicht gefunden — übersprungen." exit 0 fi # ── Hilfsfunktionen ─────────────────────────────────────────────────────────── # Extrahiert "MAJOR.MINOR" aus "timetrack-0.1.0+5.apk" → "0.1" minor_version() { local name="$1" # Dateiname: timetrack-0.1.0+5.apk → Extrahiere "0.1.0" → nehme "0.1" local ver ver=$(echo "$name" | grep -oP '(?<=timetrack-)\d+\.\d+\.\d+(?=\+)') || true if [[ -z "$ver" ]]; then echo ""; return; fi # Nur Major.Minor echo "$ver" | cut -d. -f1-2 } # Extrahiert Build-Nummer aus "timetrack-0.1.0+5.apk" → 5 build_number() { local name="$1" echo "$name" | grep -oP '(?<=\+)\d+(?=\.apk)' || echo "0" } # Löscht eine APK + zugehörige .sha256-Datei delete_apk() { local path="$1" local sha="${path}.sha256" if [[ "$DRY_RUN" == "true" ]]; then echo " [DRY-RUN] würde löschen: $(basename "$path")" [[ -f "$sha" ]] && echo " [DRY-RUN] würde löschen: $(basename "$sha")" else rm -f "$path" [[ -f "$sha" ]] && rm -f "$sha" echo " gelöscht: $(basename "$path")" fi } # ── APKs einlesen (ohne Symlinks) ───────────────────────────────────────────── declare -a all_apks=() while IFS= read -r -d '' f; do name=$(basename "$f") # Nur versionierte APKs — kein "timetrack.apk"-Symlink if [[ "$name" == timetrack-*.apk ]]; then all_apks+=("$name") fi done < <(find "$APK_DIR" -maxdepth 1 -name "timetrack-*.apk" -not -type l -print0 2>/dev/null) total=${#all_apks[@]} if [[ $total -eq 0 ]]; then echo "apk_retention: Keine APKs gefunden in '$APK_DIR' — nichts zu tun." exit 0 fi echo "apk_retention: $total APKs gefunden in '$APK_DIR'" echo "apk_retention: Retention: letzte $KEEP in aktueller Minor-Version, je 1 pro älterer" echo "" # ── Minor-Versionen ermitteln ───────────────────────────────────────────────── declare -A minor_map # minor → kommaseparierte Liste von Dateinamen for name in "${all_apks[@]}"; do mv=$(minor_version "$name") if [[ -z "$mv" ]]; then continue; fi if [[ -v minor_map["$mv"] ]]; then minor_map["$mv"]="${minor_map[$mv]} $name" else minor_map["$mv"]="$name" fi done # Sortierte Liste der Minor-Versionen (höchste = aktuell) declare -a sorted_minors=() while IFS= read -r mv; do sorted_minors+=("$mv") done < <(printf '%s\n' "${!minor_map[@]}" | sort -t. -k1,1n -k2,2n) current_minor="${sorted_minors[-1]}" echo " Aktuelle Minor-Version : $current_minor" echo " Ältere Minor-Versionen : ${sorted_minors[*]::${#sorted_minors[@]}-1}" echo "" # ── Bereinigung: Ältere Minor-Versionen ────────────────────────────────────── for mv in "${sorted_minors[@]}"; do [[ "$mv" == "$current_minor" ]] && continue # Alle APKs dieser Minor-Version nach Build-Nummer sortieren declare -a mv_apks=() for name in ${minor_map[$mv]}; do mv_apks+=("$name") done # Sortieren nach Build-Nummer (numerisch) declare -a sorted_mv=() while IFS= read -r line; do sorted_mv+=("$line") done < <(printf '%s\n' "${mv_apks[@]}" | sort -t+ -k2,2n) keeper="${sorted_mv[-1]}" echo " Minor $mv: behalte $keeper (Release-Marker)" for name in "${sorted_mv[@]}"; do [[ "$name" == "$keeper" ]] && continue delete_apk "$APK_DIR/$name" done unset mv_apks sorted_mv done # ── Bereinigung: Aktuelle Minor-Version ────────────────────────────────────── declare -a cur_apks=() for name in ${minor_map[$current_minor]}; do cur_apks+=("$name") done # Sortieren nach Build-Nummer (numerisch) declare -a sorted_cur=() while IFS= read -r line; do sorted_cur+=("$line") done < <(printf '%s\n' "${cur_apks[@]}" | sort -t+ -k2,2n) cur_count=${#sorted_cur[@]} echo " Aktuelle Minor $current_minor: $cur_count APKs, behalte letzte $KEEP" if [[ $cur_count -gt $KEEP ]]; then to_delete=$(( cur_count - KEEP )) for (( i=0; i