2009-09-01 20 views
10

Estoy usando MySQL Workbench para mantener el esquema de la base de datos para una aplicación. El archivo .mwb que usa Workbench, que es un documento XML comprimido, se guarda en un repositorio de Subversion.Subversion diff para el archivo xml comprimido

El archivo se trata como datos binarios por Subversion, por lo que no puedo usar svn diff para mostrar los cambios, por ejemplo, antes de confirmar.

Dado que los datos son realmente XML, estoy pensando que podría haber alguna manera de mostrar el diff de todos modos, tal vez algún script que descomprima el archivo antes, o algún complemento en svn diff.

La solución ideal sería permitir esto:

$ svn diff db-model.mwb 

o incluso usando Meld:

$ meld db-model.mwb 

¿Qué enfoque se puede pensar para lograr esto? Tal vez alguien más ha tenido este problema de mostrar diff para archivos de texto archivados en Subversion.

+0

por curiosidad Oskar, ¿alguna vez descubrir una manera de hacer un diff de un mwb que realmente resultó útil? –

+0

Brad, desafortunadamente no lo hice. Principalmente porque el árbol XML contenía ID generados que cambiaban prácticamente cada vez que se cambiaba/actualizaba el modelo, por lo que comparar los árboles era muy inconveniente. Sin embargo, esto fue hace dos años, ¿así que las cosas podrían haber cambiado? – Oskar

+0

No, las cosas todavía parecen ser la misma perversión XML que siempre fueron. Esos atributos ptr aún cambian en cada guardado, y no parece haber mucha otra información disponible en un formato fácil de leer. Diffs aún son teóricamente posibles, pero sería una gran cantidad de trabajo por hacer. –

Respuesta

8

Subversion le permite usar external differencing tools. Lo que puede hacer es escribir un script de envoltura y decirle a Subversion que lo use como su comando "diff". Su contenedor analizaría los argumentos que obtiene de Subversion para seleccionar los nombres de archivo "izquierdo" y "derecho", opere en ellos y devuelva un código de error que Subversion interpretará como correcto o fallido. En su caso, el contenedor podría descomprimir los archivos XML y pasar los resultados descomprimidos al "diff" u otra herramienta de su elección.

Subversion rechazará los archivos que se detectaron como "binarios" cuando se registraron. La opción "--force" le permite anular esta comprobación, por lo que su script de envoltura se ejecutará incluso si la entrada los archivos se registran como binarios.

+0

Gracias. Resulta que esto fue un poco difícil. Subversion no llamará a ninguna herramienta de diferenciación externa siempre que el archivo tenga una propiedad svn: mime-type configurada en algo 'no legible para humanos' (como mis archivos zip). Pero eliminar esa propiedad hará que el archivo comprimido no tenga una versión como archivo binario, que no es tan bueno, ¿verdad? – Oskar

+0

No eliminaría la propiedad. SVN podría necesitarla por otros motivos. ¿Has probado la opción "--force" para que SVN ejecute tu script de script de diferencial? –

+0

- ¡la fuerza hizo el truco! – Oskar

2

He escrito un script diff para archivos de workbench que se puede integrar con TortoiseSVN y TortoiseGit, que hará exactamente lo que Jim Lewis sugiere: Extraiga el XML real del archivo y difírelo.

El script también eliminará todos los ptr -Atributos de ruido en el diff. La fusión no es posible y sería un poco más complicado (descubrir cómo los ptr -attributes se comportarían, vuelva a embalar el XML en el archivo, lo que es con la otra metadatos en el archivo ?, ...)

la secuencia de comandos de Python está disponible en Pastebin debajo CC-BY 3.0:

http://pastebin.com/AcD7dBNH

# extensions: mwb 
# TortoiseSVN Diff script for MySQL Workbench scheme files 
# 2012 by Oliver Iking, Z-Software GmbH, oliverikingREPLACETHISWITHANATz-software.net, http://www.z-software.net/ 
# This work is licensed under a Creative Commons Attribution 3.0 Unported License - http://creativecommons.org/licenses/by/3.0/ 

# Will produce two diffable documents, which don't resemble the FULL MWB content, but the scheme relevant data. 
# Merging is not possible 

# Open your TortoiseSVN (or TortoiseSomething) settings, go to the "Diff Viewer" tab and click on "Advanced". Add 
# a row with the extension ".mwb" and a command line of 
# "path\to\python.exe" "path\to\diff-mwb.py" %base %mine 
# Apply changes and now you can diff mysql workbench scheme files 

import sys 
import zipfile 
import os 
import time 
import tempfile 
import re 

# mysql workbench XML will have _ptr_ attributes which are modified on each save for almost each XML node. Remove the visual litter, 
# make actual changes stand out. 
def sanitizeMwbXml(xml): 
    return re.sub('_ptr_="([0-9a-fA-F]{8})"', '', xml) 

try: 
    if len(sys.argv) < 2: 
     print("Not enough parameters, cannot diff documents!") 
     sys.exit(1) 

    docOld = sys.argv[1] 
    docNew = sys.argv[2] 

    if not os.path.exists(docOld) or not os.path.exists(docNew): 
     print("Documents don't exist, cannot diff!") 
     sys.exit(1) 

    # Workbench files are actually zip archives 
    zipA = zipfile.ZipFile(docOld, 'r') 
    zipB = zipfile.ZipFile(docNew, 'r') 

    tempSubpath = os.tempnam(None,"mwbcompare") 

    docA = os.path.join(tempSubpath, "mine.document.mwb.xml") 
    docB = os.path.join(tempSubpath, "theirs.document.mwb.xml") 

    os.makedirs(tempSubpath) 

    if os.path.exists(docA) or os.path.exists(docB): 
     print("Cannot extract documents, files exist!") 
     sys.exit(1) 

    # Read, sanitize and write actual scheme XML contents to temporary files 

    docABytes = sanitizeMwbXml(zipA.read("document.mwb.xml")) 
    docBBytes = sanitizeMwbXml(zipB.read("document.mwb.xml")) 

    docAFile = open(docA, "w") 
    docBFile = open(docB, "w") 

    docAFile.write(docABytes) 
    docBFile.write(docBBytes) 

    docAFile.close() 
    docBFile.close() 

    os.system("TortoiseProc /command:diff /path:\"" + docA + "\" /path2:\"" + docB + "\""); 

    # TortoiseProc will spawn a subprocess so we can't delete the files. They're in the tempdir, so they 
    # will be cleaned up eventually 
    #os.unlink(docA) 
    #os.unlink(docB) 

    sys.exit(0) 
except Exception as e: 
    print str(e) 
    # Sleep, or the command window will close 
    time.sleep(5) 
+1

Python 3 necesita 'print (" ")' en lugar de 'print" "'. Además 'os.tempnam' se eliminó, yo uso' tempfile.mkdtemp' en su lugar. Finalmente tuve que envolver 'zipA.read (...)' con 'bytes.decode (zipA.read (" docu ... "))'. –

Cuestiones relacionadas