【问题标题】:Subversion diff for zipped xml file压缩 xml 文件的 Subversion 差异
【发布时间】:2009-09-01 07:34:41
【问题描述】:

我正在使用 MySQL Workbench 来维护应用程序的数据库架构。 Workbench 使用的.mwb 文件是一个压缩的 XML 文档,保存在 Subversion 存储库中。

Subversion 将文件视为二进制数据,因此我不能使用svn diff 来显示更改,例如在提交之前。

由于数据实际上是 XML,我想可能有一些方法可以显示差异,可能是一些之前解压缩文件的脚本,或者是 svn diff 的一些插件。

理想的解决方案是:

$ svn diff db-model.mwb

甚至使用 Meld:

$ meld db-model.mwb

您能想到什么方法来实现这一点?也许其他人遇到了在 Subversion 中显示存档文本文件差异的问题。

【问题讨论】:

  • 出于好奇,Oskar,你有没有发现一种方法来渲染实际证明有用的 mwb 差异?
  • 布拉德,不,很遗憾我没有。主要是因为 XML 树包含生成的 ID,每次模型更改/更新时都会发生很大变化,因此比较树非常不方便。然而,这是两年前的事了,所以事情可能会改变吗?
  • 不,事情似乎仍然是与往常一样的 XML 变态。这些 ptr 属性在每次保存时仍然会发生变化,而且似乎没有太多其他信息可以以易于阅读的格式获得。差异在理论上仍然是可能的,但要做的工作量很大。
  • 对于这篇文章的未来读者:我知道这个问题很老了,但是I have posted a workaround that seems to work well。我将它与 Mercurial 一起使用,但基本概念没有理由不适用于 SVN。

标签: svn diff zip meld


【解决方案1】:

Subversion 允许您使用 external differencing tools 。你可以做的是编写一个包装脚本,并告诉 Subversion 使用它作为它的“diff”命令。你的包装器会解析它从 Subversion 获得的参数以挑选出“左”和“右”文件名,运行 在它们上,并返回一个错误代码,Subversion 将解释为成功或失败。在您的情况下,包装器可以解压缩 XML 文件,并将解压缩的结果传递给 “差异”或您选择的其他工具。

Subversion 将拒绝对在签入时检测为“二进制”的文件进行差异化处理。“--force”选项允许您覆盖此检查,因此即使输入文件也将运行您的包装脚本以二进制文件的形式签入。

【讨论】:

  • 谢谢。原来这有点困难。只要文件的 svn:mime-type 属性设置为“非人类可读”(比如我的 zip 文件),Subversion 就不会调用任何外部差异工具。但是删除该属性会导致 zip 文件不被版本化为二进制文件,这不太好,对吧?
  • 我不会删除该属性——SVN 可能出于其他原因需要它。您是否尝试使用“--force”选项让 SVN 运行您的差异包装脚本?
  • 奥斯卡,我也有同样的需要。你有兴趣分享你的剧本吗?吉姆 - 谢谢你的回答。
  • @andersonbd1 我找不到脚本了,但它基于这种方法:svnbook.red-bean.com/en/1.2/svn.advanced.externaldifftools.html(我几乎只是解压缩了 $LEFT 和 $RIGHT,然后将它们扔到 diff 工具。)
【解决方案2】:

我为工作台文件编写了一个 diff 脚本,它可以与 TortoiseSVN 和 TortoiseGit 集成,这将完全按照 Jim Lewis 的建议:从存档中提取实际的 XML 并对其进行比较。

该脚本还将消除差异中的所有 ptr-属性噪声。合并是不可能的,而且会有点复杂(发现 ptr 属性的行为方式,将 XML 重新打包到存档中,存档中的其他元数据是什么?,... )

python 脚本在 CC-BY 3.0 下的 pastebin 中可用:

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)

【讨论】:

  • Python 3 需要 print("") 而不是 print ""。此外,os.tempnam 被删除,我改用tempfile.mkdtemp。最后我不得不用bytes.decode(zipA.read("docu...")) 包裹zipA.read(...)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-20
  • 2023-01-14
  • 2013-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多