#!/bin/bash ############################################################################### # Script de migration en batch des entités depuis geosector_20251008 # # Usage: ./migrate_batch.sh [options] # # Options: # --start N Commencer à partir de l'entité N (défaut: 1) # --limit N Migrer seulement N entités (défaut: toutes) # --dry-run Simuler sans exécuter # --continue Continuer après une erreur (défaut: s'arrêter) # --interactive Mode interactif (défaut si aucune option) # # Exemple: # ./migrate_batch.sh --start 10 --limit 5 # ./migrate_batch.sh --continue # ./migrate_batch.sh --interactive ############################################################################### # Configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" JSON_FILE="${SCRIPT_DIR}/migrations_entites.json" LOG_DIR="/var/www/geosector/api/logs/migrations" MIGRATION_SCRIPT="${SCRIPT_DIR}/php/migrate_from_backup.php" SOURCE_DB="geosector_20251013_13" TARGET_DB="pra_geo" # Paramètres par défaut START_INDEX=1 LIMIT=0 DRY_RUN=0 CONTINUE_ON_ERROR=0 INTERACTIVE_MODE=0 SPECIFIC_ENTITY_ID="" SPECIFIC_CP="" # Couleurs RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # No Color # Sauvegarder le nombre d'arguments avant le parsing INITIAL_ARGS=$# # Parse des arguments while [[ $# -gt 0 ]]; do case $1 in --start) START_INDEX="$2" shift 2 ;; --limit) LIMIT="$2" shift 2 ;; --dry-run) DRY_RUN=1 shift ;; --continue) CONTINUE_ON_ERROR=1 shift ;; --interactive|-i) INTERACTIVE_MODE=1 shift ;; --help) grep "^#" "$0" | grep -v "^#!/bin/bash" | sed 's/^# //' exit 0 ;; *) echo "Option inconnue: $1" echo "Utilisez --help pour l'aide" exit 1 ;; esac done # Activer le mode interactif si aucun argument n'a été fourni if [ $INITIAL_ARGS -eq 0 ]; then INTERACTIVE_MODE=1 fi # Vérifications préalables if [ ! -f "$JSON_FILE" ]; then echo -e "${RED}❌ Fichier JSON introuvable: $JSON_FILE${NC}" exit 1 fi if [ ! -f "$MIGRATION_SCRIPT" ]; then echo -e "${RED}❌ Script de migration introuvable: $MIGRATION_SCRIPT${NC}" exit 1 fi # Créer le répertoire de logs mkdir -p "$LOG_DIR" # Fichiers de log BATCH_LOG="${LOG_DIR}/batch_$(date +%Y%m%d_%H%M%S).log" SUCCESS_LOG="${LOG_DIR}/success.log" ERROR_LOG="${LOG_DIR}/errors.log" # MODE INTERACTIF if [ $INTERACTIVE_MODE -eq 1 ]; then echo "" echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}" echo -e "${CYAN} 🔧 Mode interactif - Migration d'entités GeoSector${NC}" echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}" echo "" # Question 1: Migration globale ou ciblée ? echo -e "${YELLOW}1️⃣ Type de migration :${NC}" echo -e " ${CYAN}a)${NC} Migration globale (toutes les entités)" echo -e " ${CYAN}b)${NC} Migration par lot (plage d'entités)" echo -e " ${CYAN}c)${NC} Migration par code postal" echo -e " ${CYAN}d)${NC} Migration d'une entité spécifique (ID)" echo "" echo -ne "${YELLOW}Votre choix (a/b/c/d) : ${NC}" read -r MIGRATION_TYPE echo "" case $MIGRATION_TYPE in a|A) # Migration globale - garder les valeurs par défaut START_INDEX=1 LIMIT=0 echo -e "${GREEN}✓${NC} Migration globale sélectionnée" ;; b|B) # Migration par lot echo -e "${YELLOW}2️⃣ Configuration du lot :${NC}" echo -ne " Première entité (index, défaut=1) : " read -r USER_START if [ -n "$USER_START" ]; then START_INDEX=$USER_START fi echo -ne " Limite (nombre d'entités, défaut=toutes) : " read -r USER_LIMIT if [ -n "$USER_LIMIT" ]; then LIMIT=$USER_LIMIT fi echo "" echo -e "${GREEN}✓${NC} Migration par lot : de l'index $START_INDEX, limite de $LIMIT entités" ;; c|C) # Migration par code postal echo -ne "${YELLOW}2️⃣ Code postal à migrer : ${NC}" read -r SPECIFIC_CP echo "" if [ -z "$SPECIFIC_CP" ]; then echo -e "${RED}❌ Code postal requis${NC}" exit 1 fi echo -e "${GREEN}✓${NC} Migration pour le code postal : $SPECIFIC_CP" ;; d|D) # Migration d'une entité spécifique - bypass complet du JSON echo -ne "${YELLOW}2️⃣ ID de l'entité à migrer : ${NC}" read -r SPECIFIC_ENTITY_ID echo "" if [ -z "$SPECIFIC_ENTITY_ID" ]; then echo -e "${RED}❌ ID d'entité requis${NC}" exit 1 fi echo -e "${GREEN}✓${NC} Migration de l'entité ID : $SPECIFIC_ENTITY_ID" echo "" # Demander si suppression des données de l'entité avant migration echo -ne "${YELLOW}3️⃣ Supprimer les données existantes de cette entité dans la TARGET avant migration ? (y/N): ${NC}" read -r DELETE_BEFORE DELETE_FLAG="" if [[ $DELETE_BEFORE =~ ^[Yy]$ ]]; then echo -e "${GREEN}✓${NC} Les données seront supprimées avant migration" DELETE_FLAG="--delete-before" else echo -e "${BLUE}ℹ${NC} Les données seront conservées (ON DUPLICATE KEY UPDATE)" fi echo "" # Confirmer la migration echo -ne "${YELLOW}⚠️ Confirmer la migration de l'entité #${SPECIFIC_ENTITY_ID} ? (y/N): ${NC}" read -r CONFIRM if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then echo -e "${RED}❌ Migration annulée${NC}" exit 0 fi # Exécuter directement la migration sans passer par le JSON ENTITY_LOG="${LOG_DIR}/entity_${SPECIFIC_ENTITY_ID}_$(date +%Y%m%d_%H%M%S).log" echo "" echo -e "${BLUE}⏳ Migration de l'entité #${SPECIFIC_ENTITY_ID} en cours...${NC}" php "$MIGRATION_SCRIPT" \ --source-db="$SOURCE_DB" \ --target-db="$TARGET_DB" \ --mode=entity \ --entity-id="$SPECIFIC_ENTITY_ID" \ --log="$ENTITY_LOG" \ $DELETE_FLAG EXIT_CODE=$? if [ $EXIT_CODE -eq 0 ]; then echo -e "${GREEN}✅ Entité #${SPECIFIC_ENTITY_ID} migrée avec succès${NC}" echo -e "${BLUE}📋 Log détaillé : $ENTITY_LOG${NC}" else echo -e "${RED}❌ Erreur lors de la migration de l'entité #${SPECIFIC_ENTITY_ID}${NC}" echo -e "${RED}📋 Voir le log : $ENTITY_LOG${NC}" exit 1 fi exit 0 ;; *) echo -e "${RED}❌ Choix invalide${NC}" exit 1 ;; esac echo "" fi # Fonctions utilitaires log() { echo -e "$1" | tee -a "$BATCH_LOG" } log_success() { echo "$1" >> "$SUCCESS_LOG" log "${GREEN}✓${NC} $1" } log_error() { echo "$1" >> "$ERROR_LOG" log "${RED}✗${NC} $1" } # Extraire les entity_id du JSON (compatible sans jq) get_entity_ids() { if [ -n "$SPECIFIC_ENTITY_ID" ]; then # Entité spécifique par ID - chercher exactement "entity_id" : ID, grep "\"entity_id\" : ${SPECIFIC_ENTITY_ID}," "$JSON_FILE" | sed 's/.*: \([0-9]*\).*/\1/' elif [ -n "$SPECIFIC_CP" ]; then # Entités par code postal grep -B 2 "\"code_postal\" : \"$SPECIFIC_CP\"" "$JSON_FILE" | grep '"entity_id"' | sed 's/.*: \([0-9]*\).*/\1/' else # Toutes les entités grep '"entity_id"' "$JSON_FILE" | sed 's/.*: \([0-9]*\).*/\1/' fi } # Compter le nombre total d'entités TOTAL_ENTITIES=$(get_entity_ids | wc -l) # Vérifier si des entités ont été trouvées if [ $TOTAL_ENTITIES -eq 0 ]; then if [ -n "$SPECIFIC_ENTITY_ID" ]; then echo -e "${RED}❌ Entité #${SPECIFIC_ENTITY_ID} introuvable dans le fichier JSON${NC}" elif [ -n "$SPECIFIC_CP" ]; then echo -e "${RED}❌ Aucune entité trouvée pour le code postal ${SPECIFIC_CP}${NC}" else echo -e "${RED}❌ Aucune entité trouvée${NC}" fi exit 1 fi # Calculer le nombre d'entités à migrer if [ $LIMIT -gt 0 ]; then END_INDEX=$((START_INDEX + LIMIT - 1)) if [ $END_INDEX -gt $TOTAL_ENTITIES ]; then END_INDEX=$TOTAL_ENTITIES fi else END_INDEX=$TOTAL_ENTITIES fi # Bannière de démarrage echo "" log "${BLUE}═══════════════════════════════════════════════════════════${NC}" log "${BLUE} Migration en batch des entités GeoSector${NC}" log "${BLUE}═══════════════════════════════════════════════════════════${NC}" log "📅 Date: $(date '+%Y-%m-%d %H:%M:%S')" log "📁 Source: $SOURCE_DB" log "📁 Cible: $TARGET_DB" # Afficher les informations selon le mode if [ -n "$SPECIFIC_ENTITY_ID" ]; then log "🎯 Mode: Migration d'une entité spécifique" log "📊 Entité ID: $SPECIFIC_ENTITY_ID" elif [ -n "$SPECIFIC_CP" ]; then log "🎯 Mode: Migration par code postal" log "📮 Code postal: $SPECIFIC_CP" log "📊 Entités trouvées: $TOTAL_ENTITIES" else TOTAL_AVAILABLE=$(grep '"entity_id"' "$JSON_FILE" | wc -l) log "📊 Total entités disponibles: $TOTAL_AVAILABLE" log "🎯 Entités à migrer: $START_INDEX à $END_INDEX" fi if [ $DRY_RUN -eq 1 ]; then log "${YELLOW}🔍 Mode DRY-RUN (simulation)${NC}" fi log "${BLUE}═══════════════════════════════════════════════════════════${NC}" echo "" # Confirmation utilisateur if [ $DRY_RUN -eq 0 ]; then echo -ne "${YELLOW}⚠️ Confirmer la migration ? (y/N): ${NC}" read -r CONFIRM if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then log "❌ Migration annulée par l'utilisateur" exit 0 fi echo "" fi # Compteurs SUCCESS_COUNT=0 ERROR_COUNT=0 SKIPPED_COUNT=0 CURRENT_INDEX=0 # Début de la migration START_TIME=$(date +%s) # Lire les entity_id et migrer get_entity_ids | while read -r ENTITY_ID; do CURRENT_INDEX=$((CURRENT_INDEX + 1)) # Filtrer par index if [ $CURRENT_INDEX -lt $START_INDEX ]; then continue fi if [ $CURRENT_INDEX -gt $END_INDEX ]; then break fi # Récupérer les détails de l'entité depuis le JSON (match exact avec la virgule) ENTITY_INFO=$(grep -A 8 "\"entity_id\" : ${ENTITY_ID}," "$JSON_FILE") ENTITY_NAME=$(echo "$ENTITY_INFO" | grep '"nom"' | sed 's/.*: "\(.*\)".*/\1/') ENTITY_CP=$(echo "$ENTITY_INFO" | grep '"code_postal"' | sed 's/.*: "\(.*\)".*/\1/') NB_USERS=$(echo "$ENTITY_INFO" | grep '"nb_users"' | sed 's/.*: \([0-9]*\).*/\1/') NB_PASSAGES=$(echo "$ENTITY_INFO" | grep '"nb_passages"' | sed 's/.*: \([0-9]*\).*/\1/') # Afficher la progression PROGRESS=$((CURRENT_INDEX - START_INDEX + 1)) TOTAL=$((END_INDEX - START_INDEX + 1)) PERCENT=$((PROGRESS * 100 / TOTAL)) log "" log "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" log "${BLUE}[$PROGRESS/$TOTAL - ${PERCENT}%]${NC} Entité #${ENTITY_ID}: ${ENTITY_NAME} (${ENTITY_CP})" log " 👥 Users: ${NB_USERS} | 📍 Passages: ${NB_PASSAGES}" # Mode dry-run if [ $DRY_RUN -eq 1 ]; then log "${YELLOW} 🔍 [DRY-RUN] Simulation de la migration${NC}" SKIPPED_COUNT=$((SKIPPED_COUNT + 1)) continue fi # Exécuter la migration ENTITY_LOG="${LOG_DIR}/entity_${ENTITY_ID}_$(date +%Y%m%d_%H%M%S).log" log " ⏳ Migration en cours..." php "$MIGRATION_SCRIPT" \ --source-db="$SOURCE_DB" \ --target-db="$TARGET_DB" \ --mode=entity \ --entity-id="$ENTITY_ID" \ --log="$ENTITY_LOG" > /tmp/migration_output_$$.txt 2>&1 EXIT_CODE=$? if [ $EXIT_CODE -eq 0 ]; then # Succès SUCCESS_COUNT=$((SUCCESS_COUNT + 1)) log_success "Entité #${ENTITY_ID} (${ENTITY_NAME}) migrée avec succès" # Afficher un résumé du log avec détails if [ -f "$ENTITY_LOG" ]; then # Chercher la ligne avec les marqueurs #STATS# STATS_LINE=$(grep "#STATS#" "$ENTITY_LOG" 2>/dev/null) if [ -n "$STATS_LINE" ]; then # Extraire chaque compteur OPE=$(echo "$STATS_LINE" | grep -oE 'OPE:[0-9]+' | cut -d: -f2) USERS=$(echo "$STATS_LINE" | grep -oE 'USER:[0-9]+' | cut -d: -f2) SECTORS=$(echo "$STATS_LINE" | grep -oE 'SECTOR:[0-9]+' | cut -d: -f2) PASSAGES=$(echo "$STATS_LINE" | grep -oE 'PASS:[0-9]+' | cut -d: -f2) # Valeurs par défaut si extraction échoue OPE=${OPE:-0} USERS=${USERS:-0} SECTORS=${SECTORS:-0} PASSAGES=${PASSAGES:-0} log " 📊 ope: ${OPE} | users: ${USERS} | sectors: ${SECTORS} | passages: ${PASSAGES}" else log " 📊 Statistiques non disponibles" fi fi else # Erreur ERROR_COUNT=$((ERROR_COUNT + 1)) log_error "Entité #${ENTITY_ID} (${ENTITY_NAME}) - Erreur code $EXIT_CODE" # Afficher les dernières lignes du log d'erreur if [ -f "/tmp/migration_output_$$.txt" ]; then log "${RED} 📋 Dernières erreurs:${NC}" tail -5 "/tmp/migration_output_$$.txt" | sed 's/^/ /' | tee -a "$BATCH_LOG" fi # Arrêter ou continuer ? if [ $CONTINUE_ON_ERROR -eq 0 ]; then log "" log "${RED}❌ Migration interrompue suite à une erreur${NC}" log " Utilisez --continue pour continuer malgré les erreurs" exit 1 fi fi # Nettoyage rm -f "/tmp/migration_output_$$.txt" # Pause entre les migrations (pour éviter de surcharger) sleep 1 done # Fin de la migration END_TIME=$(date +%s) DURATION=$((END_TIME - START_TIME)) HOURS=$((DURATION / 3600)) MINUTES=$(((DURATION % 3600) / 60)) SECONDS=$((DURATION % 60)) # Résumé final log "" log "${BLUE}═══════════════════════════════════════════════════════════${NC}" log "${BLUE} Résumé de la migration${NC}" log "${BLUE}═══════════════════════════════════════════════════════════${NC}" log "✅ Succès: ${GREEN}${SUCCESS_COUNT}${NC}" log "❌ Erreurs: ${RED}${ERROR_COUNT}${NC}" log "⏭️ Ignorées: ${YELLOW}${SKIPPED_COUNT}${NC}" log "⏱️ Durée: ${HOURS}h ${MINUTES}m ${SECONDS}s" log "" log "📋 Logs détaillés:" log " - Batch: $BATCH_LOG" log " - Succès: $SUCCESS_LOG" log " - Erreurs: $ERROR_LOG" log " - Individuels: $LOG_DIR/entity_*.log" log "${BLUE}═══════════════════════════════════════════════════════════${NC}" # Code de sortie if [ $ERROR_COUNT -gt 0 ]; then exit 1 else exit 0 fi