From 85c78885395a6abf477af431f43c328f6a7c9c61 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 16 Apr 2026 08:20:41 +0000 Subject: [PATCH 1/2] feat(cmdbuild): scripts de modification IHM sans recompilation Maven MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajout d'une boîte à outils pour modifier l'interface CMDBuild directement dans le fichier WAR, sans relancer une compilation Maven complète. Scripts ajoutés : - 01_extract_war.sh : extrait le WAR (archive ZIP) dans un dossier - 02_repackage_war.sh : repackage le dossier en WAR de production - 03_deploy_exploded.sh : déploiement Tomcat exploded pour rechargement à chaud - 04_watch_ui.sh : surveillance des fichiers UI avec inotify/fswatch/polling - 05_patch_war.sh : patch ciblé d'un fichier précis dans le WAR README.md décrivant les trois workflows (patch rapide, développement itératif exploded, modification en lot) et la gestion des builds Sencha CMD. Co-authored-by: oulom --- cmdbuild/01_extract_war.sh | 69 +++++++++++++++ cmdbuild/02_repackage_war.sh | 54 ++++++++++++ cmdbuild/03_deploy_exploded.sh | 94 ++++++++++++++++++++ cmdbuild/04_watch_ui.sh | 116 +++++++++++++++++++++++++ cmdbuild/05_patch_war.sh | 77 +++++++++++++++++ cmdbuild/README.md | 154 +++++++++++++++++++++++++++++++++ 6 files changed, 564 insertions(+) create mode 100755 cmdbuild/01_extract_war.sh create mode 100755 cmdbuild/02_repackage_war.sh create mode 100755 cmdbuild/03_deploy_exploded.sh create mode 100755 cmdbuild/04_watch_ui.sh create mode 100755 cmdbuild/05_patch_war.sh create mode 100644 cmdbuild/README.md diff --git a/cmdbuild/01_extract_war.sh b/cmdbuild/01_extract_war.sh new file mode 100755 index 0000000..e1c125e --- /dev/null +++ b/cmdbuild/01_extract_war.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# Extrait un WAR CMDBuild dans un répertoire de travail pour modification de l'IHM. +# Usage : ./01_extract_war.sh [dossier_cible] +# +# Le WAR est une archive ZIP standard. On extrait tout, puis on identifie +# les artefacts UI (HTML/JS/CSS/resources) séparément des JARs/classes Java +# afin de ne recompiler que ce qui est nécessaire. + +set -euo pipefail + +WAR_FILE="${1:-}" +TARGET_DIR="${2:-./cmdbuild-exploded}" + +if [[ -z "$WAR_FILE" ]]; then + echo "Usage: $0 [dossier_cible]" + echo "" + echo "Exemple :" + echo " $0 cmdbuild-3.4.war ./cmdbuild-exploded" + exit 1 +fi + +if [[ ! -f "$WAR_FILE" ]]; then + echo "ERREUR : Le fichier WAR '$WAR_FILE' n'existe pas." + exit 1 +fi + +WAR_ABS=$(realpath "$WAR_FILE") +WAR_NAME=$(basename "$WAR_FILE" .war) + +echo "=== Extraction du WAR CMDBuild ===" +echo "Source : $WAR_ABS" +echo "Cible : $TARGET_DIR" +echo "" + +# Créer le répertoire cible +mkdir -p "$TARGET_DIR" + +# Extraire le WAR (= ZIP) +unzip -q -o "$WAR_ABS" -d "$TARGET_DIR" + +echo "[OK] WAR extrait dans : $TARGET_DIR" +echo "" + +# Inventaire des ressources UI (tout ce qui n'est pas Java) +UI_MANIFEST="$TARGET_DIR/../ui-files.txt" +echo "=== Inventaire des fichiers UI ===" +find "$TARGET_DIR" \ + -not -path "*/WEB-INF/lib/*" \ + -not -path "*/WEB-INF/classes/*" \ + -not -name "*.jar" \ + -not -name "*.class" \ + -type f \ + | sort > "$UI_MANIFEST" + +UI_COUNT=$(wc -l < "$UI_MANIFEST") +echo "[OK] $UI_COUNT fichiers UI répertoriés dans : $UI_MANIFEST" +echo "" + +# Résumé de la structure +echo "=== Structure du répertoire extrait ===" +if command -v tree &>/dev/null; then + tree -L 3 --dirsfirst "$TARGET_DIR" 2>/dev/null | head -60 +else + find "$TARGET_DIR" -maxdepth 3 -type d | sort | sed "s|$TARGET_DIR||" | sed 's|^/||' +fi + +echo "" +echo "Prochaine étape : modifiez les fichiers UI dans '$TARGET_DIR'" +echo "Puis lancez : ./02_repackage_war.sh $TARGET_DIR $WAR_NAME-modified.war" diff --git a/cmdbuild/02_repackage_war.sh b/cmdbuild/02_repackage_war.sh new file mode 100755 index 0000000..1ad04a2 --- /dev/null +++ b/cmdbuild/02_repackage_war.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# Repackage un répertoire WAR extrait en un nouveau fichier WAR. +# Usage : ./02_repackage_war.sh +# +# Seuls les fichiers UI modifiés sont re-zippés avec les JARs/classes +# d'origine — aucune recompilation Maven nécessaire. + +set -euo pipefail + +EXPLODED_DIR="${1:-}" +OUTPUT_WAR="${2:-}" + +if [[ -z "$EXPLODED_DIR" || -z "$OUTPUT_WAR" ]]; then + echo "Usage: $0 " + echo "" + echo "Exemple :" + echo " $0 ./cmdbuild-exploded ./cmdbuild-modified.war" + exit 1 +fi + +if [[ ! -d "$EXPLODED_DIR" ]]; then + echo "ERREUR : Le répertoire '$EXPLODED_DIR' n'existe pas." + exit 1 +fi + +OUTPUT_ABS=$(realpath -m "$OUTPUT_WAR") +EXPLODED_ABS=$(realpath "$EXPLODED_DIR") + +echo "=== Repackaging WAR CMDBuild ===" +echo "Source : $EXPLODED_ABS" +echo "Sortie : $OUTPUT_ABS" +echo "" + +# Supprimer le WAR de sortie s'il existe déjà +[[ -f "$OUTPUT_ABS" ]] && rm -f "$OUTPUT_ABS" + +# Repackager depuis le répertoire exploded +# jar/zip doit être lancé depuis le répertoire lui-même pour avoir +# les chemins relatifs corrects dans l'archive. +( + cd "$EXPLODED_ABS" + zip -q -r "$OUTPUT_ABS" . +) + +SIZE=$(du -sh "$OUTPUT_ABS" | cut -f1) +echo "[OK] WAR généré : $OUTPUT_ABS ($SIZE)" +echo "" +echo "=== Vérification du contenu ===" +unzip -l "$OUTPUT_ABS" | tail -5 + +echo "" +echo "Déployez ce WAR dans Tomcat (webapps/) ou utilisez le mode" +echo "exploded avec le script 03_deploy_exploded.sh pour recharger" +echo "à chaud sans redémarrer Tomcat." diff --git a/cmdbuild/03_deploy_exploded.sh b/cmdbuild/03_deploy_exploded.sh new file mode 100755 index 0000000..5222ee3 --- /dev/null +++ b/cmdbuild/03_deploy_exploded.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash +# Déploie le répertoire WAR extrait directement dans Tomcat en mode "exploded" +# (sans repackager le WAR). Tomcat recharge les ressources statiques à chaud. +# +# Usage : ./03_deploy_exploded.sh [tomcat_webapps] [context_name] +# +# Exemple : +# ./03_deploy_exploded.sh ./cmdbuild-exploded /opt/tomcat/webapps cmdbuild +# +# En mode exploded, Tomcat sert directement les fichiers depuis le dossier — +# toute modification de JS/CSS/HTML est visible sans redémarrage. + +set -euo pipefail + +EXPLODED_DIR="${1:-}" +TOMCAT_WEBAPPS="${2:-/opt/tomcat/webapps}" +CONTEXT_NAME="${3:-cmdbuild}" + +if [[ -z "$EXPLODED_DIR" ]]; then + echo "Usage: $0 [tomcat_webapps] [context_name]" + echo "" + echo "Exemples :" + echo " $0 ./cmdbuild-exploded /opt/tomcat/webapps cmdbuild" + echo " $0 ./cmdbuild-exploded /var/lib/tomcat9/webapps cmdbuild" + exit 1 +fi + +if [[ ! -d "$EXPLODED_DIR" ]]; then + echo "ERREUR : Le répertoire '$EXPLODED_DIR' n'existe pas." + echo "Lancez d'abord : ./01_extract_war.sh $EXPLODED_DIR" + exit 1 +fi + +if [[ ! -d "$TOMCAT_WEBAPPS" ]]; then + echo "ERREUR : Le répertoire webapps Tomcat '$TOMCAT_WEBAPPS' n'existe pas." + echo "Vérifiez le chemin d'installation de Tomcat." + exit 1 +fi + +DEPLOY_TARGET="$TOMCAT_WEBAPPS/$CONTEXT_NAME" +EXPLODED_ABS=$(realpath "$EXPLODED_DIR") + +echo "=== Déploiement exploded CMDBuild ===" +echo "Source : $EXPLODED_ABS" +echo "Destination : $DEPLOY_TARGET" +echo "Contexte : /$CONTEXT_NAME" +echo "" + +# Supprimer l'ancien WAR éventuellement présent (Tomcat préfère le dossier) +WAR_IN_WEBAPPS="$TOMCAT_WEBAPPS/$CONTEXT_NAME.war" +if [[ -f "$WAR_IN_WEBAPPS" ]]; then + echo "[INFO] Suppression du WAR existant : $WAR_IN_WEBAPPS" + rm -f "$WAR_IN_WEBAPPS" +fi + +# Copier (ou créer un lien symbolique) le répertoire exploded +if [[ -L "$DEPLOY_TARGET" ]]; then + echo "[INFO] Le lien symbolique existe déjà, mise à jour..." + ln -sfn "$EXPLODED_ABS" "$DEPLOY_TARGET" +elif [[ -d "$DEPLOY_TARGET" ]]; then + echo "[INFO] Répertoire existant détecté — synchronisation avec rsync..." + rsync -a --delete "$EXPLODED_ABS/" "$DEPLOY_TARGET/" +else + echo "[INFO] Création du lien symbolique..." + ln -s "$EXPLODED_ABS" "$DEPLOY_TARGET" +fi + +echo "[OK] Déploiement terminé." +echo "" + +# Optionnel : recharger le contexte Tomcat via manager si disponible +TOMCAT_MANAGER="${TOMCAT_MANAGER_URL:-}" +if [[ -n "$TOMCAT_MANAGER" ]]; then + echo "=== Rechargement du contexte Tomcat ===" + TOMCAT_USER="${TOMCAT_MANAGER_USER:-admin}" + TOMCAT_PASS="${TOMCAT_MANAGER_PASS:-admin}" + curl -s -u "$TOMCAT_USER:$TOMCAT_PASS" \ + "$TOMCAT_MANAGER/text/reload?path=/$CONTEXT_NAME" \ + && echo "[OK] Contexte rechargé." \ + || echo "[WARN] Rechargement automatique échoué — redémarrez Tomcat manuellement." +else + echo "=== Information ===" + echo "Pour recharger le contexte sans redémarrer Tomcat, définissez :" + echo " TOMCAT_MANAGER_URL=http://localhost:8080/manager" + echo " TOMCAT_MANAGER_USER=admin" + echo " TOMCAT_MANAGER_PASS=votre_mot_de_passe" + echo "" + echo "Ou rechargez manuellement :" + echo " curl -u admin:pass http://localhost:8080/manager/text/reload?path=/$CONTEXT_NAME" +fi + +echo "" +echo "L'application est accessible à : http://localhost:8080/$CONTEXT_NAME" +echo "Les modifications UI sont prises en compte immédiatement (mode exploded)." diff --git a/cmdbuild/04_watch_ui.sh b/cmdbuild/04_watch_ui.sh new file mode 100755 index 0000000..890bdeb --- /dev/null +++ b/cmdbuild/04_watch_ui.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash +# Surveille les modifications de fichiers UI dans le répertoire source +# et les synchronise automatiquement vers le répertoire exploded (ou Tomcat). +# +# Usage : ./04_watch_ui.sh +# +# Prérequis : inotify-tools (Linux) ou fswatch (macOS) +# Linux : sudo apt-get install inotify-tools +# macOS : brew install fswatch +# +# Exemples : +# ./04_watch_ui.sh ./src/ui ./cmdbuild-exploded +# ./04_watch_ui.sh ./cmdbuild-exploded /opt/tomcat/webapps/cmdbuild + +set -euo pipefail + +SOURCE_DIR="${1:-}" +TARGET_DIR="${2:-}" + +if [[ -z "$SOURCE_DIR" || -z "$TARGET_DIR" ]]; then + echo "Usage: $0 " + echo "" + echo "Exemples :" + echo " $0 ./src/ui ./cmdbuild-exploded" + echo " $0 ./cmdbuild-exploded /opt/tomcat/webapps/cmdbuild" + exit 1 +fi + +if [[ ! -d "$SOURCE_DIR" ]]; then + echo "ERREUR : Le répertoire source '$SOURCE_DIR' n'existe pas." + exit 1 +fi + +if [[ ! -d "$TARGET_DIR" ]]; then + echo "ERREUR : Le répertoire cible '$TARGET_DIR' n'existe pas." + exit 1 +fi + +SOURCE_ABS=$(realpath "$SOURCE_DIR") +TARGET_ABS=$(realpath "$TARGET_DIR") + +# Extensions UI à surveiller +UI_EXTENSIONS="html|js|css|less|scss|json|xml|png|jpg|gif|svg|ico|woff|woff2|ttf|eot" + +echo "=== Surveillance des modifications UI ===" +echo "Source : $SOURCE_ABS" +echo "Cible : $TARGET_ABS" +echo "Types : $UI_EXTENSIONS" +echo "" +echo "Appuyez sur Ctrl+C pour arrêter." +echo "" + +sync_file() { + local file="$1" + local rel_path="${file#$SOURCE_ABS/}" + local dest="$TARGET_ABS/$rel_path" + mkdir -p "$(dirname "$dest")" + cp -f "$file" "$dest" + echo "[$(date '+%H:%M:%S')] Synchronisé : $rel_path" +} + +# Détecter l'outil de surveillance disponible +if command -v inotifywait &>/dev/null; then + # Linux : inotify-tools + echo "[INFO] Utilisation de inotifywait (Linux)" + inotifywait -m -r -e close_write,moved_to,create "$SOURCE_ABS" \ + --format '%w%f' \ + | while IFS= read -r changed_file; do + # Filtrer par extension + ext="${changed_file##*.}" + if echo "$ext" | grep -qiE "^($UI_EXTENSIONS)$"; then + sync_file "$changed_file" + fi + done + +elif command -v fswatch &>/dev/null; then + # macOS ou Linux avec fswatch + echo "[INFO] Utilisation de fswatch" + fswatch -r "$SOURCE_ABS" | while IFS= read -r changed_file; do + if [[ -f "$changed_file" ]]; then + ext="${changed_file##*.}" + if echo "$ext" | grep -qiE "^($UI_EXTENSIONS)$"; then + sync_file "$changed_file" + fi + fi + done + +else + # Fallback : polling toutes les 2 secondes + echo "[WARN] inotifywait et fswatch non trouvés — mode polling (2s)" + echo " Installez inotify-tools pour une surveillance temps réel :" + echo " sudo apt-get install inotify-tools" + echo "" + + declare -A file_mtimes + + # Initialiser les mtimes + while IFS= read -r -d '' f; do + file_mtimes["$f"]=$(stat -c '%Y' "$f" 2>/dev/null || echo 0) + done < <(find "$SOURCE_ABS" -type f -print0) + + while true; do + while IFS= read -r -d '' f; do + mtime=$(stat -c '%Y' "$f" 2>/dev/null || echo 0) + prev="${file_mtimes[$f]:-0}" + if [[ "$mtime" != "$prev" ]]; then + file_mtimes["$f"]="$mtime" + ext="${f##*.}" + if echo "$ext" | grep -qiE "^($UI_EXTENSIONS)$"; then + sync_file "$f" + fi + fi + done < <(find "$SOURCE_ABS" -type f -print0) + sleep 2 + done +fi diff --git a/cmdbuild/05_patch_war.sh b/cmdbuild/05_patch_war.sh new file mode 100755 index 0000000..979c159 --- /dev/null +++ b/cmdbuild/05_patch_war.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# Applique un patch de fichiers UI directement dans un WAR existant, +# sans extraire l'intégralité de l'archive. +# +# Usage : ./05_patch_war.sh +# +# Exemple — remplacer la feuille de style principale : +# ./05_patch_war.sh cmdbuild.war ./mon-theme.css css/cmdbuild.css +# +# Exemple — remplacer un fichier JavaScript : +# ./05_patch_war.sh cmdbuild.war ./custom.js javascript/cmdbuild/view/main.js +# +# Cette approche modifie uniquement l'entrée ciblée dans l'archive ZIP — +# les JARs et classes Java ne sont pas touchés. + +set -euo pipefail + +WAR_FILE="${1:-}" +LOCAL_FILE="${2:-}" +WAR_PATH="${3:-}" + +if [[ -z "$WAR_FILE" || -z "$LOCAL_FILE" || -z "$WAR_PATH" ]]; then + echo "Usage: $0 " + echo "" + echo "Exemples :" + echo " $0 cmdbuild.war ./mon-logo.png images/logo.png" + echo " $0 cmdbuild.war ./custom.css css/custom.css" + echo " $0 cmdbuild.war ./index.jsp index.jsp" + exit 1 +fi + +if [[ ! -f "$WAR_FILE" ]]; then + echo "ERREUR : WAR introuvable : $WAR_FILE" + exit 1 +fi + +if [[ ! -f "$LOCAL_FILE" ]]; then + echo "ERREUR : Fichier local introuvable : $LOCAL_FILE" + exit 1 +fi + +WAR_ABS=$(realpath "$WAR_FILE") +LOCAL_ABS=$(realpath "$LOCAL_FILE") + +echo "=== Patch du WAR ===" +echo "WAR : $WAR_ABS" +echo "Fichier : $LOCAL_ABS" +echo "Cible ZIP : $WAR_PATH" +echo "" + +# Vérifier que le chemin existe dans le WAR +if ! unzip -l "$WAR_ABS" "$WAR_PATH" &>/dev/null; then + echo "[WARN] Le chemin '$WAR_PATH' n'existe pas encore dans le WAR." + echo " Il sera ajouté comme nouvelle entrée." +fi + +# zip -j : pas de récursion, juste le fichier +# On place le fichier local avec le bon nom relatif dans le WAR +TMPDIR_PATCH=$(mktemp -d) +trap 'rm -rf "$TMPDIR_PATCH"' EXIT + +# Reproduire l'arborescence pour que zip conserve le chemin relatif +WAR_DIR=$(dirname "$WAR_PATH") +mkdir -p "$TMPDIR_PATCH/$WAR_DIR" +cp "$LOCAL_ABS" "$TMPDIR_PATCH/$WAR_PATH" + +( + cd "$TMPDIR_PATCH" + zip -q "$WAR_ABS" "$WAR_PATH" +) + +echo "[OK] Patch appliqué : $WAR_PATH" +echo "" +echo "Vérification :" +unzip -l "$WAR_ABS" "$WAR_PATH" +echo "" +echo "Redéployez le WAR dans Tomcat pour prendre en compte le changement." diff --git a/cmdbuild/README.md b/cmdbuild/README.md new file mode 100644 index 0000000..ff99a92 --- /dev/null +++ b/cmdbuild/README.md @@ -0,0 +1,154 @@ +# Modification de l'IHM CMDBuild sans recompilation Maven + +Ce répertoire contient des scripts shell pour modifier l'interface graphique (IHM) +de CMDBuild directement dans le fichier WAR — **sans recompiler les sources Java avec Maven**. + +## Principe + +Un fichier `.war` est une archive ZIP standard. Il contient : +- `WEB-INF/lib/` : les JARs Java (ne pas toucher) +- `WEB-INF/classes/` : les classes compilées (ne pas toucher) +- Tout le reste : ressources UI (HTML, JSP, JS, CSS, images, etc.) + +Les ressources UI peuvent être modifiées directement, sans aucune compilation. + +--- + +## Workflows disponibles + +### Workflow 1 — Modification rapide d'un ou deux fichiers (patch direct) + +Pour modifier un fichier précis dans le WAR sans extraire toute l'archive : + +```bash +./05_patch_war.sh cmdbuild.war ./mon-nouveau-logo.png images/logo.png +./05_patch_war.sh cmdbuild.war ./custom.css css/custom.css +``` + +Puis redéployez le WAR dans Tomcat. + +--- + +### Workflow 2 — Développement itératif (mode exploded) + +Pour modifier librement l'IHM avec rechargement immédiat : + +**Étape 1 : Extraire le WAR** +```bash +./01_extract_war.sh cmdbuild.war ./cmdbuild-exploded +``` + +**Étape 2 : Déployer en mode exploded dans Tomcat** +```bash +./03_deploy_exploded.sh ./cmdbuild-exploded /opt/tomcat/webapps cmdbuild +``` +Tomcat sert les fichiers directement depuis le dossier — toute modification +est visible immédiatement sans redémarrage. + +**Étape 3 : Surveiller et synchroniser les modifications** +```bash +./04_watch_ui.sh ./cmdbuild-exploded /opt/tomcat/webapps/cmdbuild +``` + +**Étape 4 : Repackager le WAR final pour la production** +```bash +./02_repackage_war.sh ./cmdbuild-exploded ./cmdbuild-modified.war +``` + +--- + +### Workflow 3 — Modification en lot puis repackaging + +**Extraire → modifier → repackager :** +```bash +# 1. Extraire +./01_extract_war.sh cmdbuild.war ./cmdbuild-exploded + +# 2. Modifier vos fichiers UI dans ./cmdbuild-exploded/ +# Exemple : éditer JS, CSS, images, templates... +vim ./cmdbuild-exploded/javascript/cmdbuild/view/main/MainPanel.js +vim ./cmdbuild-exploded/css/cmdbuild.css + +# 3. Repackager +./02_repackage_war.sh ./cmdbuild-exploded ./cmdbuild-v2.war + +# 4. Déployer dans Tomcat +cp ./cmdbuild-v2.war /opt/tomcat/webapps/cmdbuild.war +``` + +--- + +## Structure typique d'un WAR CMDBuild + +``` +cmdbuild-exploded/ +├── index.jsp ← Page d'entrée +├── css/ ← Feuilles de style +│ └── cmdbuild.css +├── images/ ← Images / icônes +├── javascript/ ← Fichiers JavaScript +│ └── cmdbuild/ +│ ├── view/ ← Composants Ext JS (vues) +│ ├── model/ ← Modèles de données +│ └── store/ ← Stores Ext JS +├── WEB-INF/ +│ ├── web.xml ← Config servlet +│ ├── lib/ ← JARs Java (ne pas modifier) +│ └── classes/ ← Classes compilées (ne pas modifier) +└── META-INF/ + └── MANIFEST.MF +``` + +> **Note :** CMDBuild utilise [Sencha Ext JS](https://www.sencha.com/products/extjs/). +> Les fichiers JS dans `javascript/cmdbuild/` définissent les composants de l'IHM. +> Ils peuvent être modifiés directement si le WAR n'utilise pas de build minifié. +> Pour un build minifié, voir ci-dessous. + +--- + +## Gestion du build minifié (Sencha CMD) + +Si le WAR contient un build minifié (`app.js` ou `app-all.js` de grande taille), +les sources lisibles se trouvent dans les archives sources CMDBuild. + +Dans ce cas, deux approches sont possibles : + +### Option A : Override CSS uniquement (sans recompilation) +Ajouter une feuille de style CSS supplémentaire dans `index.jsp` ou `WEB-INF/tiles/` : +```html + +``` +Puis patcher le WAR avec `05_patch_war.sh`. + +### Option B : Recompiler uniquement le frontend (Sencha CMD) +```bash +# Installer Sencha CMD +# Depuis le répertoire source du module UI cmdbuild : +sencha app build +# Puis copier le build dans le répertoire exploded +``` +Cette approche ne nécessite **pas** de recompiler Java/Maven. + +--- + +## Prérequis des scripts + +| Outil | Usage | Installation | +|-------|-------|--------------| +| `unzip` / `zip` | Extraction / repackaging WAR | `sudo apt-get install zip unzip` | +| `rsync` | Synchronisation déploiement | `sudo apt-get install rsync` | +| `inotify-tools` | Surveillance fichiers (Linux) | `sudo apt-get install inotify-tools` | +| `fswatch` | Surveillance fichiers (macOS) | `brew install fswatch` | +| `curl` | Rechargement contexte Tomcat | Disponible par défaut | + +--- + +## Scripts disponibles + +| Script | Description | +|--------|-------------| +| `01_extract_war.sh` | Extraire le WAR dans un répertoire | +| `02_repackage_war.sh` | Repackager le répertoire en WAR | +| `03_deploy_exploded.sh` | Déployer en mode exploded dans Tomcat | +| `04_watch_ui.sh` | Surveiller et synchroniser les modifications UI | +| `05_patch_war.sh` | Patcher un fichier précis dans le WAR | From 0247bf88c042279daece1f6863794e1158b7add6 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 16 Apr 2026 08:41:47 +0000 Subject: [PATCH 2/2] =?UTF-8?q?feat(cmdbuild):=20r=C3=A9utilisation=20des?= =?UTF-8?q?=20JARs=20du=20WAR=20comme=20d=C3=A9pendances=20Maven?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajout de trois scripts pour exposer les JARs présents dans WEB-INF/lib/ du WAR directement à Maven, sans recompilation des sources : - 06_install_jars_to_m2.sh : installe chaque JAR dans ~/.m2/repository avec coordonnées Maven déduites du nom de fichier ; génère le bloc à coller dans pom.xml - 07_local_repo.sh : construit un dépôt Maven au format file:// dans le projet (committable dans Git, utilisable sans Maven installé) - 08_generate_pom_deps.sh : audit non-destructif des JARs + génération du snippet pom.xml sans rien modifier README mis à jour avec le workflow complet et les deux approches (A/B). Co-authored-by: oulom --- cmdbuild/06_install_jars_to_m2.sh | 153 +++++++++++++++++++++++++ cmdbuild/07_local_repo.sh | 184 ++++++++++++++++++++++++++++++ cmdbuild/08_generate_pom_deps.sh | 154 +++++++++++++++++++++++++ cmdbuild/README.md | 111 ++++++++++++++++++ 4 files changed, 602 insertions(+) create mode 100755 cmdbuild/06_install_jars_to_m2.sh create mode 100755 cmdbuild/07_local_repo.sh create mode 100755 cmdbuild/08_generate_pom_deps.sh diff --git a/cmdbuild/06_install_jars_to_m2.sh b/cmdbuild/06_install_jars_to_m2.sh new file mode 100755 index 0000000..09d2fdf --- /dev/null +++ b/cmdbuild/06_install_jars_to_m2.sh @@ -0,0 +1,153 @@ +#!/usr/bin/env bash +# Installe les JARs présents dans WEB-INF/lib/ d'un WAR directement dans +# le dépôt Maven local (~/.m2/repository) sous un groupId commun. +# +# Après ce script, tous les JARs sont utilisables comme dépendances Maven +# normales dans votre pom.xml — sans recompiler les sources ni télécharger. +# +# Usage : +# ./06_install_jars_to_m2.sh [groupId] [version] +# +# Exemples : +# ./06_install_jars_to_m2.sh cmdbuild.war +# ./06_install_jars_to_m2.sh cmdbuild-3.4.war org.cmdbuild 3.4 +# ./06_install_jars_to_m2.sh cmdbuild.war com.mycompany.cmdbuild 1.0-LOCAL +# +# Les JARs dont le nom contient déjà une version (ex: commons-lang3-3.12.0.jar) +# sont déposés avec leur groupId/version d'origine quand ils sont reconnus. +# Les JARs propres à CMDBuild (préfixe "cmdbuild-") sont installés sous +# le groupId fourni. + +set -euo pipefail + +WAR_FILE="${1:-}" +GROUP_ID="${2:-org.cmdbuild.local}" +VERSION="${3:-WAR-SNAPSHOT}" + +if [[ -z "$WAR_FILE" ]]; then + echo "Usage: $0 [groupId] [version]" + echo "" + echo "Exemples :" + echo " $0 cmdbuild-3.4.war" + echo " $0 cmdbuild-3.4.war org.cmdbuild 3.4" + exit 1 +fi + +if [[ ! -f "$WAR_FILE" ]]; then + echo "ERREUR : WAR introuvable : $WAR_FILE" + exit 1 +fi + +if ! command -v mvn &>/dev/null; then + echo "ERREUR : 'mvn' n'est pas dans le PATH." + echo "Installez Maven : sudo apt-get install maven" + echo "" + echo "Alternative sans Maven : utilisez le script 07_local_repo.sh" + exit 1 +fi + +WAR_ABS=$(realpath "$WAR_FILE") +TMPDIR_JARS=$(mktemp -d) +trap 'rm -rf "$TMPDIR_JARS"' EXIT + +echo "=== Installation des JARs du WAR dans ~/.m2 ===" +echo "WAR : $WAR_ABS" +echo "GroupId : $GROUP_ID" +echo "Version : $VERSION" +echo "" + +# Extraire uniquement WEB-INF/lib/ +echo "[1/4] Extraction de WEB-INF/lib/ ..." +unzip -q "$WAR_ABS" "WEB-INF/lib/*.jar" -d "$TMPDIR_JARS" 2>/dev/null || \ +unzip -q "$WAR_ABS" -d "$TMPDIR_JARS" + +LIB_DIR="$TMPDIR_JARS/WEB-INF/lib" +if [[ ! -d "$LIB_DIR" ]]; then + echo "ERREUR : WEB-INF/lib/ non trouvé dans le WAR." + exit 1 +fi + +JAR_LIST=("$LIB_DIR"/*.jar) +JAR_COUNT=${#JAR_LIST[@]} +echo "[OK] $JAR_COUNT JARs trouvés dans WEB-INF/lib/" +echo "" + +# Fichier de log des dépendances générées +DEP_FILE="$(dirname "$WAR_ABS")/war-dependencies.xml" +echo "" > "$DEP_FILE" +echo "" >> "$DEP_FILE" + +OK=0 +SKIP=0 +FAIL=0 + +echo "[2/4] Installation dans ~/.m2 ..." +echo "" + +for JAR in "${JAR_LIST[@]}"; do + BASENAME=$(basename "$JAR" .jar) + + # Tenter de déduire groupId:artifactId:version depuis le nom du JAR + # Forme courante : artifactId-version.jar (ex: commons-lang3-3.12.0.jar) + # On sépare sur le dernier segment qui ressemble à une version (chiffre en tête) + if [[ "$BASENAME" =~ ^(.*)-([0-9][^-]*.*)$ ]]; then + ARTIFACT_ID="${BASH_REMATCH[1]}" + JAR_VERSION="${BASH_REMATCH[2]}" + # Pour les JARs CMDBuild propres, on impose le groupId fourni + if [[ "$ARTIFACT_ID" == cmdbuild* ]]; then + G="$GROUP_ID" + V="$VERSION" + else + # Pour les bibliothèques tierces déjà dans Maven Central, + # on installe quand même pour garantir la disponibilité offline. + G="$GROUP_ID.thirdparty" + V="$JAR_VERSION" + fi + else + ARTIFACT_ID="$BASENAME" + JAR_VERSION="$VERSION" + G="$GROUP_ID" + V="$VERSION" + fi + + printf " %-55s → %s:%s:%s\n" "$BASENAME.jar" "$G" "$ARTIFACT_ID" "$V" + + if mvn install:install-file \ + -Dfile="$JAR" \ + -DgroupId="$G" \ + -DartifactId="$ARTIFACT_ID" \ + -Dversion="$V" \ + -Dpackaging=jar \ + -DgeneratePom=true \ + -q 2>/dev/null; then + ((OK++)) + cat >> "$DEP_FILE" < + $G + $ARTIFACT_ID + $V + +EOF + else + echo " [WARN] Échec pour $BASENAME" + ((FAIL++)) + fi +done + +echo "" >> "$DEP_FILE" + +echo "" +echo "[3/4] Résumé :" +echo " Installés avec succès : $OK" +echo " Échecs : $FAIL" +echo "" +echo "[4/4] Fichier de dépendances généré : $DEP_FILE" +echo " → Copiez le contenu dans votre pom.xml section" +echo "" +echo "=== Utilisation dans pom.xml ===" +echo "" +echo "Ajoutez ceci dans la section de votre pom.xml :" +echo "" +head -20 "$DEP_FILE" +echo " ..." +echo "" diff --git a/cmdbuild/07_local_repo.sh b/cmdbuild/07_local_repo.sh new file mode 100755 index 0000000..317e625 --- /dev/null +++ b/cmdbuild/07_local_repo.sh @@ -0,0 +1,184 @@ +#!/usr/bin/env bash +# Crée un dépôt Maven au format "file repository" à partir des JARs du WAR. +# +# Alternative au script 06 quand Maven n'est pas installé, ou pour partager +# un dépôt local avec l'équipe (en le commitant dans le dépôt Git du projet). +# +# Un "file repository" Maven suit la structure : +# ///-.jar +# ///-.pom +# +# Dans le pom.xml, il suffit d'ajouter : +# +# +# war-local +# file://${project.basedir}/war-repo +# +# +# +# Usage : +# ./07_local_repo.sh [dossier_repo] [groupId] [version] +# +# Exemples : +# ./07_local_repo.sh cmdbuild.war ./war-repo +# ./07_local_repo.sh cmdbuild-3.4.war ./war-repo org.cmdbuild 3.4 + +set -euo pipefail + +WAR_FILE="${1:-}" +REPO_DIR="${2:-./war-repo}" +GROUP_ID="${3:-org.cmdbuild.local}" +VERSION="${4:-WAR-SNAPSHOT}" + +if [[ -z "$WAR_FILE" ]]; then + echo "Usage: $0 [dossier_repo] [groupId] [version]" + echo "" + echo "Exemples :" + echo " $0 cmdbuild-3.4.war ./war-repo" + echo " $0 cmdbuild-3.4.war ./war-repo org.cmdbuild 3.4" + exit 1 +fi + +if [[ ! -f "$WAR_FILE" ]]; then + echo "ERREUR : WAR introuvable : $WAR_FILE" + exit 1 +fi + +WAR_ABS=$(realpath "$WAR_FILE") +REPO_ABS=$(realpath -m "$REPO_DIR") +TMPDIR_JARS=$(mktemp -d) +trap 'rm -rf "$TMPDIR_JARS"' EXIT + +echo "=== Création du dépôt Maven local (file repository) ===" +echo "WAR : $WAR_ABS" +echo "Dépôt : $REPO_ABS" +echo "GroupId : $GROUP_ID" +echo "Version : $VERSION" +echo "" + +# Extraire WEB-INF/lib/ +echo "[1/4] Extraction de WEB-INF/lib/ ..." +unzip -q "$WAR_ABS" "WEB-INF/lib/*.jar" -d "$TMPDIR_JARS" 2>/dev/null || \ +unzip -q "$WAR_ABS" -d "$TMPDIR_JARS" + +LIB_DIR="$TMPDIR_JARS/WEB-INF/lib" +if [[ ! -d "$LIB_DIR" ]]; then + echo "ERREUR : WEB-INF/lib/ non trouvé dans le WAR." + exit 1 +fi + +JAR_LIST=("$LIB_DIR"/*.jar) +JAR_COUNT=${#JAR_LIST[@]} +echo "[OK] $JAR_COUNT JARs trouvés" +echo "" + +mkdir -p "$REPO_ABS" + +# Fichiers de sortie pom.xml +DEP_FILE="$REPO_ABS/dependencies-snippet.xml" +REPO_SNIPPET="$REPO_ABS/repository-snippet.xml" + +echo "[2/4] Population du dépôt ..." +echo "" + +OK=0 + +generate_pom() { + local g="$1" a="$2" v="$3" + cat < + + 4.0.0 + $g + $a + $v + jar + +EOF +} + +declare -a ARTIFACTS=() + +for JAR in "${JAR_LIST[@]}"; do + BASENAME=$(basename "$JAR" .jar) + + if [[ "$BASENAME" =~ ^(.*)-([0-9][^-]*.*)$ ]]; then + ARTIFACT_ID="${BASH_REMATCH[1]}" + JAR_VERSION="${BASH_REMATCH[2]}" + if [[ "$ARTIFACT_ID" == cmdbuild* ]]; then + G="$GROUP_ID"; V="$VERSION" + else + G="$GROUP_ID.thirdparty"; V="$JAR_VERSION" + fi + else + ARTIFACT_ID="$BASENAME" + G="$GROUP_ID"; V="$VERSION" + fi + + # Construire le chemin dans le dépôt : groupId/artifactId/version/ + G_PATH="${G//.//}" + DEST_DIR="$REPO_ABS/$G_PATH/$ARTIFACT_ID/$V" + mkdir -p "$DEST_DIR" + + # Copier le JAR + cp "$JAR" "$DEST_DIR/${ARTIFACT_ID}-${V}.jar" + + # Générer le POM minimal + generate_pom "$G" "$ARTIFACT_ID" "$V" > "$DEST_DIR/${ARTIFACT_ID}-${V}.pom" + + printf " %-55s → %s\n" "$BASENAME.jar" "$G_PATH/$ARTIFACT_ID/$V/" + ARTIFACTS+=("$G:$ARTIFACT_ID:$V") + ((OK++)) +done + +# Générer le snippet +echo "[3/4] Génération des snippets pom.xml ..." + +{ + echo "" + echo "" + for ENTRY in "${ARTIFACTS[@]}"; do + IFS=':' read -r G A V <<< "$ENTRY" + echo " " + echo " $G" + echo " $A" + echo " $V" + echo " " + done + echo "" +} > "$DEP_FILE" + +# Générer le snippet +REPO_URL="file://\${project.basedir}/$(basename "$REPO_ABS")" +{ + echo "" + echo "" + echo " " + echo " war-local" + echo " Dépôt local extrait du WAR CMDBuild" + echo " $REPO_URL" + echo " " + echo "" +} > "$REPO_SNIPPET" + +echo "" +echo "[4/4] Résumé :" +echo " JARs traités : $OK" +echo " Dépôt créé : $REPO_ABS/" +echo "" +echo "=== Intégration dans votre pom.xml ===" +echo "" +echo "--- Étape 1 : déclarer le dépôt local ---" +cat "$REPO_SNIPPET" +echo "" +echo "--- Étape 2 : ajouter les dépendances ---" +echo "(voir $DEP_FILE pour la liste complète)" +echo "" +head -15 "$DEP_FILE" +echo " ..." +echo "" +echo "" +echo "=== Pour partager avec l'équipe ===" +echo "Committez le dossier '$(basename "$REPO_ABS")/' dans Git :" +echo " git add $(basename "$REPO_ABS")/" +echo " git commit -m 'chore: dépôt Maven local extrait du WAR CMDBuild'" diff --git a/cmdbuild/08_generate_pom_deps.sh b/cmdbuild/08_generate_pom_deps.sh new file mode 100755 index 0000000..1deb7a8 --- /dev/null +++ b/cmdbuild/08_generate_pom_deps.sh @@ -0,0 +1,154 @@ +#!/usr/bin/env bash +# Inspecte les JARs dans WEB-INF/lib/ d'un WAR et génère : +# - Un snippet prêt à coller dans un pom.xml +# - Un rapport lisible des JARs détectés avec leurs coordonnées Maven +# +# Ce script est non-destructif : il ne modifie ni le WAR ni ~/.m2. +# Il est utile pour auditer le contenu avant d'utiliser le script 06 ou 07. +# +# Usage : +# ./08_generate_pom_deps.sh [groupId] [version] +# +# Exemples : +# ./08_generate_pom_deps.sh cmdbuild.war +# ./08_generate_pom_deps.sh cmdbuild-3.4.war org.cmdbuild 3.4 + +set -euo pipefail + +WAR_FILE="${1:-}" +GROUP_ID="${2:-org.cmdbuild.local}" +VERSION="${3:-WAR-SNAPSHOT}" + +if [[ -z "$WAR_FILE" ]]; then + echo "Usage: $0 [groupId] [version]" + echo "" + echo "Exemple : $0 cmdbuild-3.4.war org.cmdbuild 3.4" + exit 1 +fi + +if [[ ! -f "$WAR_FILE" ]]; then + echo "ERREUR : WAR introuvable : $WAR_FILE" + exit 1 +fi + +WAR_ABS=$(realpath "$WAR_FILE") +TMPDIR_JARS=$(mktemp -d) +trap 'rm -rf "$TMPDIR_JARS"' EXIT + +echo "=== Analyse des JARs du WAR ===" +echo "WAR : $WAR_ABS" +echo "GroupId : $GROUP_ID (pour les JARs CMDBuild)" +echo "Version : $VERSION" +echo "" + +# Extraire uniquement WEB-INF/lib/ +unzip -q "$WAR_ABS" "WEB-INF/lib/*.jar" -d "$TMPDIR_JARS" 2>/dev/null || \ +unzip -q "$WAR_ABS" -d "$TMPDIR_JARS" + +LIB_DIR="$TMPDIR_JARS/WEB-INF/lib" +if [[ ! -d "$LIB_DIR" ]]; then + echo "ERREUR : WEB-INF/lib/ non trouvé dans le WAR." + exit 1 +fi + +JAR_LIST=("$LIB_DIR"/*.jar) +JAR_COUNT=${#JAR_LIST[@]} + +echo "JARs trouvés : $JAR_COUNT" +echo "" + +# ── Colonnes : TYPE | groupId | artifactId | version ────────────────────────── +printf "%-10s %-45s %-40s %s\n" "TYPE" "groupId" "artifactId" "version" +printf '%s\n' "$(printf '─%.0s' {1..110})" + +CMDBUILD_JARS=() +THIRDPARTY_JARS=() + +for JAR in "${JAR_LIST[@]}"; do + BASENAME=$(basename "$JAR" .jar) + + if [[ "$BASENAME" =~ ^(.*)-([0-9][^-]*.*)$ ]]; then + A="${BASH_REMATCH[1]}" + V="${BASH_REMATCH[2]}" + if [[ "$A" == cmdbuild* ]]; then + G="$GROUP_ID"; TYPE="cmdbuild" + else + G="$GROUP_ID.thirdparty"; TYPE="tierce" + fi + else + A="$BASENAME"; V="$VERSION" + G="$GROUP_ID"; TYPE="cmdbuild" + fi + + printf "%-10s %-45s %-40s %s\n" "$TYPE" "$G" "$A" "$V" + + if [[ "$TYPE" == "cmdbuild" ]]; then + CMDBUILD_JARS+=("$G:$A:$V") + else + THIRDPARTY_JARS+=("$G:$A:$V") + fi +done + +echo "" +echo "Résumé : ${#CMDBUILD_JARS[@]} JARs CMDBuild, ${#THIRDPARTY_JARS[@]} JARs tiers" +echo "" + +# ── Génération du snippet pom.xml ───────────────────────────────────────────── +OUT_FILE="$(dirname "$WAR_ABS")/pom-dependencies-snippet.xml" + +{ +cat <<'HEADER' + +HEADER + +echo "" +echo "" +echo "" +for ENTRY in "${CMDBUILD_JARS[@]}"; do + IFS=':' read -r G A V <<< "$ENTRY" + echo " " + echo " $G" + echo " $A" + echo " $V" + echo " " +done + +echo "" +echo " " +for ENTRY in "${THIRDPARTY_JARS[@]}"; do + IFS=':' read -r G A V <<< "$ENTRY" + echo " " + echo " $G" + echo " $A" + echo " $V" + echo " " +done +echo "" +} > "$OUT_FILE" + +echo "=== Snippet pom.xml généré ===" +echo "Fichier : $OUT_FILE" +echo "" +echo "Aperçu (10 premières dépendances) :" +grep -A3 "" "$OUT_FILE" | head -40 +echo "..." +echo "" +echo "Prochaines étapes :" +echo " 1. Installer les JARs dans ~/.m2 : ./06_install_jars_to_m2.sh $WAR_FILE $GROUP_ID $VERSION" +echo " 2. Ou créer un dépôt fichier Git : ./07_local_repo.sh $WAR_FILE ./war-repo $GROUP_ID $VERSION" +echo " 3. Copier $OUT_FILE dans votre pom.xml" diff --git a/cmdbuild/README.md b/cmdbuild/README.md index ff99a92..fcb9660 100644 --- a/cmdbuild/README.md +++ b/cmdbuild/README.md @@ -131,6 +131,113 @@ Cette approche ne nécessite **pas** de recompiler Java/Maven. --- +--- + +## Réutiliser les JARs du WAR comme dépendances Maven + +Le WAR contient dans `WEB-INF/lib/` tous les JARs déjà compilés de CMDBuild et +ses dépendances tierces. L'idée est de les exposer à Maven pour éviter toute +recompilation ou téléchargement. + +Deux approches sont disponibles selon votre contexte : + +--- + +### Approche A — Installer dans `~/.m2` (recommandée, nécessite Maven) + +Installe chaque JAR dans votre dépôt Maven local. Une fois fait, Maven les trouve +comme n'importe quelle dépendance déclarée dans un `pom.xml`. + +```bash +./06_install_jars_to_m2.sh cmdbuild.war org.cmdbuild 3.4 +``` + +Le script génère automatiquement un fichier `war-dependencies.xml` contenant le +bloc `` à coller dans votre `pom.xml`. + +Puis dans votre `pom.xml` : +```xml + + + org.cmdbuild + cmdbuild-core + 3.4 + + + +``` + +Recompiler ensuite **uniquement votre module** : +```bash +mvn install -pl mon-module-ui -DskipTests +``` + +--- + +### Approche B — Dépôt fichier dans Git (sans Maven requis, partageable) + +Crée un dépôt Maven au format `file://` directement dans le projet. Ce dossier +peut être commité dans Git pour que toute l'équipe en bénéficie sans installation. + +```bash +./07_local_repo.sh cmdbuild.war ./war-repo org.cmdbuild 3.4 +``` + +Puis déclarer le dépôt dans votre `pom.xml` : +```xml + + + war-local + JARs extraits du WAR CMDBuild + file://${project.basedir}/war-repo + + + + + + +``` + +Puis commiter le dépôt pour partager avec l'équipe : +```bash +git add war-repo/ +git commit -m "chore: dépôt Maven local extrait du WAR CMDBuild" +``` + +--- + +### Inspecter les JARs sans rien installer (audit) + +Avant d'utiliser les scripts 06 ou 07, vous pouvez auditer le contenu du WAR et +obtenir un aperçu des coordonnées Maven détectées : + +```bash +./08_generate_pom_deps.sh cmdbuild.war org.cmdbuild 3.4 +``` + +Produit un rapport dans le terminal et un fichier `pom-dependencies-snippet.xml`. + +--- + +### Résumé — Workflow complet avec JARs du WAR + +```bash +# 1. Auditer le WAR +./08_generate_pom_deps.sh cmdbuild.war org.cmdbuild 3.4 + +# 2. Installer les JARs dans ~/.m2 +./06_install_jars_to_m2.sh cmdbuild.war org.cmdbuild 3.4 + +# 3. Ajouter le contenu de war-dependencies.xml dans votre pom.xml + +# 4. Compiler uniquement votre module (pas le reste de CMDBuild) +mvn install -pl mon-module-ui -DskipTests -o +# └─ offline : Maven ne tente pas +# de vérifier les versions réseau +``` + +--- + ## Prérequis des scripts | Outil | Usage | Installation | @@ -140,6 +247,7 @@ Cette approche ne nécessite **pas** de recompiler Java/Maven. | `inotify-tools` | Surveillance fichiers (Linux) | `sudo apt-get install inotify-tools` | | `fswatch` | Surveillance fichiers (macOS) | `brew install fswatch` | | `curl` | Rechargement contexte Tomcat | Disponible par défaut | +| `mvn` | Installation JARs dans ~/.m2 | `sudo apt-get install maven` | --- @@ -152,3 +260,6 @@ Cette approche ne nécessite **pas** de recompiler Java/Maven. | `03_deploy_exploded.sh` | Déployer en mode exploded dans Tomcat | | `04_watch_ui.sh` | Surveiller et synchroniser les modifications UI | | `05_patch_war.sh` | Patcher un fichier précis dans le WAR | +| `06_install_jars_to_m2.sh` | Installer les JARs du WAR dans `~/.m2` | +| `07_local_repo.sh` | Créer un dépôt Maven fichier partageable en Git | +| `08_generate_pom_deps.sh` | Inspecter les JARs et générer un snippet `pom.xml` |