Utilisation des outils externes de comparaison et de fusion

L'interface entre Subversion et les outils de comparaison (de deux ou trois fichiers) remonte à l'époque où Subversion, pour afficher les différences de manière contextuelle, utilisait directement la suite d'outils GNU de comparaison, plus précisément les utilitaires diff et diff3. Pour obtenir le comportement désiré par Subversion, l'appel à ces programmes se faisait avec une ribambelle d'options et de paramètres dont la plupart étaient spécifiques à ces utilitaires. Plus tard, Subversion s'est doté de sa propre bibliothèque de comparaison et, afin de conserver la possibilité de choisir, les options --diff-cmd et --diff3-cmd ont été ajoutées au client en ligne de commande pour que les utilisateurs allergiques à la nouvelle bibliothèque puissent indiquer facilement leur souhait de se servir des utilitaires GNU diff et diff3. Si ces options étaient utilisées, Subversion ignorait purement et simplement sa bibliothèque interne de comparaison et appelait alors ces programmes externes, avec leurs listes d'arguments longue comme un jour sans pain et leurs autres spécificités. Les choses sont restées en l'état.

Il n'a pas fallu longtemps pour que les adeptes de Subversion comprennent que si l'on pouvait utiliser les utilitaires GNU diff et diff3 situés à un endroit précis du disque, on pouvait alors aussi utiliser ce mécanisme pour utiliser d'autres outils de comparaison. Après tout, Subversion ne vérifiait pas que les programmes qu'il lançait faisaient bien partie de la suite des outils GNU de comparaison. Mais la seule chose que l'on peut configurer dans l'utilisation de programmes externes est leur emplacement sur le disque ; pas les options, ni l'ordre des paramètres, ni le reste. Subversion continue à envoyer toutes les options des utilitaires GNU à votre programme de comparaison, indépendamment du fait que votre programme en tienne compte ou non. Et c'est là que la plupart des utilisateurs ne comprennent pas la logique de la chose.

La clé pour utiliser des outils externes de comparaison de deux ou trois fichiers (autres que les programmes GNU diff et diff3 bien sûr) avec Subversion est de créer des scripts d'interface qui convertissent les données fournies par Subversion en données compréhensibles par l'outil de comparaison que vous utilisez, puis de convertir les sorties de votre outil vers le format attendu par Subversion : le format que les outils GNU auraient utilisé. Les sections suivantes détaillent les spécificités de ce qu'attend Subversion.

[Note] Note

La décision de lancer une comparaison entre deux ou trois fichiers dans le cadre d'une opération Subversion est entièrement du ressort de Subversion et est conditionnée, en autres, au fait que les fichiers soient lisibles par un humain comme indiqué par leur propriété svn:mime-type. Cela signifie, par exemple, que même si vous avez le plus formidable outil de l'univers, capable de comparer et fusionner des documents Microsoft Word, il ne sera jamais appelé par Subversion tant que le type MIME des documents Word suivis en versions indiquera qu'ils ne sont pas lisibles par un humain (tel que application/msword). Pour plus d'informations sur la configuration des types MIME, voir la section intitulée « Type de contenu des fichiers »

Subversion 1.5 introduit la résolution interactive des conflits (décrite dans la section intitulée « Résoudre les conflits (fusionner des modifications) ») et l'une des options proposées à l'utilisateur est de lancer un outil de fusion externe. Si cette action est choisie, Subversion consultera l'option merge-tool-cmd de la zone de configuration des exécutables, susceptible de contenir le nom d'un outil externe de fusion et, s'il en trouve un, lancera cet outil avec les fichiers appropriés en paramètres. Il y a deux différences notables avec l'outil de comparaison de trois fichiers. D'abord, l'outil de comparaison est toujours utilisé pour afficher les différences entre trois fichiers alors que l'outil de fusion est employé uniquement quand l'application de comparaison a détecté un conflit. Ensuite, l'interface est beaucoup plus propre — votre outil de fusion a seulement besoin d'accepter comme paramètres en ligne de commande les chemins des quatre fichiers suivants : le fichier de référence, le « leur » (qui contient les modifications en provenance du dépôt), le « mien » (qui contient les modifications locales) et le fichier dans lequel sera placé le contenu final à stocker.

Programme externe de comparaison

Subversion appelle les programmes externes de comparaison avec des paramètres compatibles avec la suite d'outils de comparaison GNU et s'attend à ce que le programme renvoie un code d'erreur signifiant la réussite de la comparaison. Pour la plupart des programmes de comparaison alternatifs, seuls les sixième et septième arguments, indiquant les chemins vers les fichiers à comparer, respectivement placés à gauche et à droite, sont intéressants. Notez que Subversion lance le programme de comparaison pour chaque fichier concerné par l'opération Subversion, ce qui peut vous amener à avoir plusieurs instances simultanément si votre programme fonctionne de manière asynchrone (ou s'il est placé en arrière-plan). Enfin, Subversion s'attend à ce que votre programme retourne un code d'erreur de 1 s'il a détecté des différences ou 0 sinon. Tout autre code d'erreur est considéré comme une erreur fatale [53].

L'Exemple 7.2, « interface-diff.py » et l' Exemple 7.3, « interface-diff.bat » sont des modèles de scripts d'interface pour un outil externe de comparaison, respectivement en langage Python et en langage de script Windows :

Exemple 7.2. interface-diff.py

#!/usr/bin/env python
import sys
import os

# Indiquez ici le chemin de votre outil de comparaison favori.
DIFF = "/usr/local/bin/mon-diff-perso"

# Subversion fournit les chemins voulus dans les deux derniers arguments.
GAUCHE = sys.argv[-2]
DROITE = sys.argv[-1]

# Appelons la commande de comparaison (modifiez la ligne suivante
# en accord avec votre programme de comparaison).
cmd = [DIFF, '--left', GAUCHE, '--right', DROITE]
os.execv(cmd[0], cmd)

# Le code d'erreur renvoyé doit être :
# 0 si aucune différence n'est détectée,
# 1 s'il y a des différences.
# Tout autre code est traité comme une erreur fatale.

Exemple 7.3. interface-diff.bat

@ECHO OFF

REM Indiquez ici le chemin de votre outil de comparaison favori.
SET DIFF="C:\Program Files\Super Progs\Mon Diff Perso.exe"

REM Subversion fournit les chemins voulus dans les deux derniers arguments.
REM Ce sont les paramètres 6 et 7 (sauf si vous utilisez svn diff -x,
REM auquel cas tout est possible).
SET GAUCHE=%6
SET DROITE=%7

REM Appelons la commande de comparaison (modifiez la ligne suivante
REM en accord avec votre programme de comparaison).
%DIFF% --left %GAUCHE% --right %DROITE%

REM Le code d'erreur renvoyé doit être :
REM 0 si aucune différence n'est détectée,
REM 1 s'il y a des différences.
REM Tout autre code est traité comme une erreur fatale.

Programme externe de comparaison de trois fichiers

Subversion appelle les programmes externes de fusion avec des paramètres compatibles avec l'outil GNU diff3 et s'attend à ce que le programme externe retourne un code d'erreur correct et que le fichier résultant de l'opération de fusion soit envoyé vers la sortie standard (de façon à ce que Subversion puisse le rediriger vers le fichier suivi en versions approprié). Pour la plupart des programmes de fusion alternatifs, seuls les neuvième, dixième et onzième arguments (les chemins des fichiers qui contiennent les versions « mien », « original » et « leur » respectivement) sont intéressants. Notez que puisque Subversion utilise la sortie de votre programme de fusion, votre script d'interface ne doit pas se terminer avant que la sortie n'ait été fournie à Subversion. Quand il se termine, il doit retourner un code d'erreur de 0 si la fusion s'est correctement déroulée ou de 1 si des conflits non résolus persistent dans la sortie. Tout autre code d'erreur est considéré comme une erreur fatale.

L'Exemple 7.4, « interface-diff3.py » et l'Exemple 7.5, « interface-diff3.bat » sont des modèles pour des scripts d'interface vers un programme externe de fusion en langage Python et script Windows respectivement.

Exemple 7.4. interface-diff3.py

#!/usr/bin/env python
import sys
import os

# Indiquez ici le chemin de votre outil de fusion favori.
DIFF3 = "/usr/local/bin/mon-outil-de-fusion"

# Subversion fournit les chemins voulus dans les trois derniers arguments.
MIEN  = sys.argv[-3]
VIEUX = sys.argv[-2]
LEUR  = sys.argv[-1]

# Appelons la commande de fusion (modifiez la ligne suivante
# en accord avec votre outil de fusion).
cmd = [DIFF3, '--older', VIEUX, '--mine', MIEN, '--yours', LEUR]
os.execv(cmd[0], cmd)

# Après avoir effectué la fusion, le script doit envoyer le
# contenu du fichier résultant vers la sortie standard (stdout)
# Faites le à votre convenance.
# Le code d'erreur renvoyé doit être :
# 0 si la fusion a bien fonctionné,
# 1 s'il reste des conflits non résolus.
# Tout autre code est traité comme une erreur fatale.


Exemple 7.5. interface-diff3.bat

@ECHO OFF

REM Indiquez ici le chemin de votre outil de fusion favori.
SET DIFF3="C:\Program Files\Super Progs\Mon Outil De Fusion.exe"

REM Subversion fournit les chemins voulus dans les trois derniers arguments.
REM Ce sont les paramètres 9, 10 et 11. Mais nous n'avons accès qu'à
REM neuf paramètres en même temps, nous effectuons donc deux décalages
REM pour obtenir les paramètres manquants.
SHIFT
SHIFT
SET MIEN=%7
SET VIEUX=%8
SET LEUR=%9

REM Appelons la commande de fusion (modifiez la ligne suivante
REM en accord avec votre outil de fusion).
%DIFF3% --older %VIEUX% --mine %MIEN% --yours %LEUR%

REM Après avoir effectué la fusion, le script doit envoyer le
REM contenu du fichier résultant vers la sortie standard (stdout)
REM Faites le à votre convenance.
REM Le code d'erreur renvoyé doit être :
REM 0 si la fusion a bien fonctionné,
REM 1 s'il reste des conflits non résolus.
REM Tout autre code est traité comme une erreur fatale.



[53] Le manuel du diff GNU indique : « Un code de retour valant 0 signifie qu'aucune différence n'a été trouvée, 1 signifie que des différences sont apparues, 2 indique une erreur ».