#!/usr/bin/env bash # fix-ci-storage-layout.sh — Normalizza il layout /var/lib/ci dopo migrazione da Windows # # Il disco conteneva già i dati CI con nomi Windows (BuildVMs, Templates, ecc.). # setup-host-linux.sh ha creato le versioni lowercase Linux (build-vms, templates, ecc.). # Questo script unisce i duplicati e rinomina le directory Windows-only. # # MODALITÀ DRY-RUN per default: mostra cosa farebbe senza toccare nulla. # Usa --apply per eseguire le modifiche. # # Uso: # sudo bash fix-ci-storage-layout.sh [--apply] [--root /var/lib/ci] set -euo pipefail CI_ROOT="/var/lib/ci" DRY_RUN=true RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' info() { echo -e "${GREEN} ✓${NC} $*"; } warn() { echo -e "${YELLOW} !${NC} $*"; } plan() { echo -e "${CYAN} →${NC} $*"; } die() { echo -e "${RED}ERRORE: $*${NC}" >&2; exit 1; } run() { if [[ "$DRY_RUN" == true ]]; then plan "[DRY-RUN] $*" else eval "$@" fi } # ── Parse args ──────────────────────────────────────────────────────────────── while [[ $# -gt 0 ]]; do case $1 in --apply) DRY_RUN=false; shift ;; --root) CI_ROOT="$2"; shift 2 ;; *) echo "Uso: sudo bash $0 [--apply] [--root ]"; exit 1 ;; esac done [[ $EUID -ne 0 ]] && die "Eseguire come root: sudo bash $0 ..." [[ ! -d "$CI_ROOT" ]] && die "$CI_ROOT non esiste" if [[ "$DRY_RUN" == true ]]; then echo "" echo "╔══════════════════════════════════════════════════╗" echo "║ DRY-RUN — nessuna modifica verrà apportata ║" echo "║ Riesegui con --apply per applicare le fix ║" echo "╚══════════════════════════════════════════════════╝" else echo "" echo "╔══════════════════════════════════════════════════╗" echo "║ APPLICAZIONE MODIFICHE ║" echo "╚══════════════════════════════════════════════════╝" fi echo " CI_ROOT: $CI_ROOT" echo "" # ── Funzione merge: sposta contenuto di SRC in DST ─────────────────────────── # Gestisce conflitti a livello top-level (non ricorsivo: i subdir ci/sono distinti) merge_into() { local src="$CI_ROOT/$1" local dst="$CI_ROOT/$2" local had_conflict=false echo "── Merge: $1/ → $2/" if [[ ! -d "$src" ]]; then warn "$1/ non presente — skip" return fi shopt -s dotglob nullglob local items=("$src"/*) shopt -u dotglob nullglob if [[ ${#items[@]} -eq 0 ]]; then warn "$1/ è vuota — rimuovo solo la directory" run "rmdir '$src'" return fi for item in "${items[@]}"; do local name name=$(basename "$item") if [[ -e "$dst/$name" ]]; then warn " CONFLITTO: $name già esiste in $2/ — skip (controlla manualmente)" had_conflict=true else run "mv '$item' '$dst/'" info " $1/$name → $2/$name" fi done if [[ "$had_conflict" == false ]]; then run "rmdir '$src'" info " Rimossa: $1/ (vuota dopo merge)" else warn " $1/ NON rimossa: contiene ancora file in conflitto" fi echo "" } # ── Funzione rename: rinomina directory Windows-only ───────────────────────── rename_dir() { local src="$CI_ROOT/$1" local dst="$CI_ROOT/$2" echo "── Rinomina: $1/ → $2/" if [[ ! -d "$src" ]]; then warn "$1/ non presente — skip" echo "" return fi if [[ -d "$dst" ]]; then warn "$2/ esiste già — usa merge invece di rename" merge_into "$1" "$2" return fi run "mv '$src' '$dst'" info "$1/ → $2/" echo "" } # ── Funzione remove: rimuove directory non necessaria su Linux ──────────────── remove_dir() { local target="$CI_ROOT/$1" local reason="$2" echo "── Rimuovi: $1/ ($reason)" if [[ ! -d "$target" ]]; then warn "$1/ non presente — skip" echo "" return fi local count count=$(find "$target" -mindepth 1 | wc -l) if [[ "$count" -gt 0 ]]; then warn "$1/ contiene $count file/dir — rimozione manuale consigliata" warn " Esegui: sudo rm -rf '$target'" else run "rmdir '$target'" info "Rimossa: $1/ (vuota)" fi echo "" } # ═══════════════════════════════════════════════════════════════════════════════ # 1. MERGE: directory con doppio (Windows uppercase + Linux lowercase) # ═══════════════════════════════════════════════════════════════════════════════ echo "━━━ FASE 1: Merge duplicati (Windows → Linux) ━━━" echo "" merge_into "Artifacts" "artifacts" merge_into "BuildVMs" "build-vms" merge_into "Logs" "logs" merge_into "Templates" "templates" # ═══════════════════════════════════════════════════════════════════════════════ # 2. RINOMINA: directory Windows-only utili su Linux # ═══════════════════════════════════════════════════════════════════════════════ echo "━━━ FASE 2: Rinomina directory Windows-only ━━━" echo "" rename_dir "ISO" "iso" rename_dir "Cache" "cache" rename_dir "State" "state" # stato orchestrator — potrebbe contenere dati utili # ═══════════════════════════════════════════════════════════════════════════════ # 3. RIMUOVI: directory non necessarie su Linux # ═══════════════════════════════════════════════════════════════════════════════ echo "━━━ FASE 3: Directory non necessarie su Linux ━━━" echo "" # RunnerWork: working dir di act_runner su Windows; su Linux è /var/lib/ci/runner/ remove_dir "RunnerWork" "working dir act_runner Windows — su Linux è runner/" # python: venv Windows (F:\CI\python\venv); su Linux è /opt/ci/venv remove_dir "python" "venv Python Windows — su Linux è /opt/ci/venv" # act_runner: binario act_runner Windows; su Linux è /opt/ci/act_runner/ remove_dir "act_runner" "binario act_runner Windows — su Linux è /opt/ci/act_runner/" # ═══════════════════════════════════════════════════════════════════════════════ # 4. RIEPILOGO # ═══════════════════════════════════════════════════════════════════════════════ echo "━━━ Layout atteso dopo fix ━━━" echo "" echo " /var/lib/ci/" for d in build-vms artifacts templates keys logs runner iso cache state; do if [[ "$DRY_RUN" == false ]]; then [[ -d "$CI_ROOT/$d" ]] && echo " ├── $d/" || echo " ├── $d/ ← MANCANTE" else echo " ├── $d/" fi done echo " ├── config.toml" echo " └── lost+found (lasciato intatto)" echo "" if [[ "$DRY_RUN" == true ]]; then echo "Riesegui con --apply per applicare tutte le modifiche." else echo "Fix completato. Verifica con: sudo ls -la $CI_ROOT/" fi