1

更新的脚本附在下面,这些现在正在处理我的示例文档

为什么以下 python 脚本在通过 git 属性或命令行调用时执行不同?

我有两个基于 mercurial zipdoc 功能建模的脚本。我要做的就是解压缩存储中的 docx 文件(filter.clean)并在恢复时压缩它们(filter.smudge)。我有两个脚本运行良好,但是一旦我将它们放入 git 属性,它们就不起作用,我不明白为什么。

我已经通过执行以下操作进行了测试

测试脚本(git bash)

$ cat original.docx | python ~/Documents/pyscripts/unzip.py > uncompress.docx

$ cat uncompress.docx | python ~/Documents/pyscripts/zip.py > compress.docx

$ md5sum uncompress.docx compress.docx

我可以用 Microsoft Word 打开未压缩和压缩文件,没有错误。脚本按预期工作。

测试 Git 属性

  1. 我将 clean 和 scrub 都设置为cat,验证了我的文件保存和恢复没有问题。
  2. 我将 clean 设置为python ~/Documents/pyscripts/unzip.py。提交和签出后,文件现在更大(未压缩),但在 MS-Word 中打开时出错。此外,md5 与上面的“仅脚本”测试不匹配。虽然文件大小相同。
  3. 我将 clean 设置回cat并将 Scrub 设置为python ~/Documents/pyscripts/zip.py。提交和签出后,文件现在更小(压缩),但在 MS-Word 中打开时再次出错。同样,md5 与“仅脚本”测试不同,但文件大小匹配。
  4. 正如预期的那样,将清理和清理都设置为 python 脚本会产生错误。

我真的迷路了,我认为 git Attributes 只是在标准输入上提供输入并从标准输出中读取它。我已经测试了这两个脚本以使用来自 cat 的管道和来自输出的重定向。我知道脚本正在运行 b/c 文件按预期更改大小,但是在文件中的某处引入了一个小更改。

附加参考

我在 Win7 上使用 msgit,上面的所有命令都输入到 git bash 窗口中。

Git 属性说明

解压脚本

import fileinput
import sys
import zipfile

# Set stdin and stdout to binary read/write
if sys.platform == "win32":
    import os, msvcrt
    msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)

try:
  from cStringIO import StringIO
except:
  from StringIO import StringIO

# Wrap stdio into a file like object
inString = StringIO(sys.stdin.read())
outString = StringIO()

# Store each member uncompressed
try:
    with zipfile.ZipFile(inString,'r') as inFile:
        outFile = zipfile.ZipFile(outString,'w',zipfile.ZIP_STORED)
        for memberInfo in inFile.infolist():
            member = inFile.read(memberInfo)
            memberInfo.compress_type = 0
            outFile.writestr(memberInfo,member)
        outFile.close()
except zipfile.BadZipfile:
    sys.stdout.write(inString.getvalue())

sys.stdout.write(outString.getvalue())

压缩脚本

import fileinput
import sys
import zipfile

# Set stdin and stdout to binary read/write
if sys.platform == "win32":
    import os, msvcrt
    msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)

try:
  from cStringIO import StringIO
except:
  from StringIO import StringIO

# Wrap stdio into a file like object
inString = StringIO(sys.stdin.read())
outString = StringIO()

# Store each member compressed
try:
    with zipfile.ZipFile(inString,'r') as inFile:
        outFile = zipfile.ZipFile(outString,'w',zipfile.ZIP_DEFLATED)
        for memberInfo in inFile.infolist():
            member = inFile.read(memberInfo)
            memberInfo.compress_type = zipfile.ZIP_DEFLATED
            outFile.writestr(memberInfo,member)
        outFile.close()
except zipfile.BadZipfile:
    sys.stdout.write(inString.getvalue())

sys.stdout.write(outString.getvalue())

编辑:格式化 编辑 2:脚本更新为在文件处理期间写入内存而不是标准输出。

4

1 回答 1

1

我发现使用目标为标准输出的 zipfile.ZipFile() 会导致问题。打开目标为 StringIO() 的 zipfile,然后最后将完整的 StringIO 文件写入标准输出已解决了该问题。

我没有对此进行广泛测试,并且可能无法很好地处理某些 .docx 内容,但只有时间会证明一切。我的测试文件现在可以正常打开,而且由于使用了比标准 .docx 格式更高的压缩率,因此工作目录中的 .docx 文件更小。

我已经确认,在对 .docx 文件执行多次编辑和提交后,我可以打开文件,编辑一行并提交,而不会在 repo 大小中添加大的增量。例如,一个 19KB 的文件,在 repo 历史记录中进行了 3 次之前的编辑后,在顶部添加了一个新行,在执行垃圾收集之后在 repo 中创建了一个只有 1KB 的增量。使用 Mercurial 运行相同的测试(尽可能接近)导致 9.3KB 增量提交。我不是 Mercurial 专家,我的理解是 mercurial 没有“gc”命令,所以没有运行。

于 2013-09-11T14:02:31.027 回答