Разница Subversion для заархивированного XML-файла

Я использую MySQL Workbench для поддержки схемы базы данных для приложения. Используемый Workbench файл .mwb, представляющий собой сжатый XML-документ, хранится в репозитории Subversion.

Файл обрабатывается Subversion как двоичные данные, поэтому я не могу использовать svn diff для отображения изменений, например, перед фиксацией.

Поскольку данные на самом деле представляют собой XML, я думаю, что в любом случае может быть какой-то способ показать разницу, может быть, какой-нибудь скрипт, который предварительно распаковывает файл, или какой-нибудь плагин для svn diff.

Идеальное решение позволит это:

$ svn diff db-model.mwb

или даже используя Meld:

$ meld db-model.mwb

Какой подход вы можете придумать для достижения этой цели? Возможно, у кого-то еще была проблема с отображением различий для архивных текстовых файлов в Subversion.


person Oskar    schedule 01.09.2009    source источник
comment
Из любопытства, Оскар, вы когда-нибудь находили способ отрендерить разницу mwb, которая действительно оказалась полезной?   -  person Brad Koch    schedule 03.10.2011
comment
Бред, нет к сожалению не делал. В основном из-за того, что XML-дерево содержало сгенерированные идентификаторы, которые менялись каждый раз при изменении/обновлении модели, поэтому сравнивать деревья было очень неудобно. Однако это было два года назад, так что все могло измениться?   -  person Oskar    schedule 04.10.2011
comment
Нет, вещи по-прежнему кажутся тем же извращением XML, которым они всегда были. Эти атрибуты ptr по-прежнему меняются при каждом сохранении, и, похоже, не так много другой информации, доступной в легко читаемом формате. Дифференциалы все еще теоретически возможны, но это будет огромный объем работы.   -  person Brad Koch    schedule 04.10.2011
comment
Для будущих читателей этого сообщения: я знаю, что этот вопрос очень старый, но я опубликовал обходной путь, который, кажется, работает хорошо . Я использую его с Mercurial, но нет никаких причин, по которым базовая концепция не будет работать с SVN.   -  person elixenide    schedule 09.11.2015


Ответы (2)


Subversion позволяет использовать внешние инструменты для определения различий . Что вы можете сделать, так это написать сценарий-оболочку и указать Subversion использовать его в качестве команды «diff». Ваша оболочка будет анализировать аргументы, которые она получает от Subversion, чтобы выбрать «левое» и «правое» имена файлов, работать с ними и возвращать код ошибки, который Subversion интерпретирует как успех или неудачу. В вашем случае оболочка может разархивировать XML-файлы и передать разархивированные результаты в «diff» или другой инструмент по вашему выбору.

Subversion не будет сравнивать файлы, которые были обнаружены как «двоичные» при их возврате. Параметр «--force» позволяет вам переопределить эту проверку, поэтому ваш скрипт-оболочка будет выполняться, даже если входные файлы будут проверены. как бинарники.

person Jim Lewis    schedule 01.09.2009
comment
Спасибо. Оказалось, это было довольно сложно. Subversion не будет вызывать какие-либо внешние инструменты для определения различий, если у файла есть свойство svn:mime-type, установленное на что-то «нечитаемое человеком» (например, мои zip-файлы). Но удаление этого свойства приведет к тому, что zip-файл не будет иметь версию двоичного файла, что не так уж и хорошо, верно? - person Oskar; 04.09.2009
comment
Я бы не стал удалять это свойство — оно может понадобиться SVN по другим причинам. Вы пробовали опцию --force, чтобы заставить SVN запускать ваш скрипт-оболочку diff? - person Jim Lewis; 04.09.2009
comment
Оскар, у меня то же самое. Есть ли у вас интерес поделиться своим сценарием? Джим - спасибо за ответ. - person andersonbd1; 17.08.2011
comment
@andersonbd1 Я больше не могу найти сценарий, но он был основан на следующем подходе: svnbook.red-bean.com/en/1.2/svn.advanced.externaldifftools.html (я просто распаковал $LEFT и $RIGHT перед тем, как бросить их в инструмент сравнения). - person Oskar; 04.10.2011

Я написал сценарий сравнения для файлов рабочей среды, который можно интегрировать с TortoiseSVN и TortoiseGit, и он будет делать именно то, что предлагает Джим Льюис: извлечь фактический XML из архива и сравнить его.

Скрипт также устранит весь шум ptr-Attribute в diff. Слияние невозможно и будет немного сложнее (узнайте, как будут вести себя ptr-атрибуты, переупакуйте XML в архив, что с другими метаданными в архиве?,... )

Скрипт python доступен в pastebin под 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)
person Oliver    schedule 12.06.2012
comment
Python 3 требует print("") вместо print "". Кроме того, os.tempnam был удален, вместо него я использую tempfile.mkdtemp. Наконец мне пришлось обернуть zipA.read(...) с bytes.decode(zipA.read("docu...")). - person Micha Wiedenmann; 08.02.2013