下面附有更新的脚本,这些脚本现在正在我的示例文档中运行
为什么以下 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 属性
- 我将clean和scrub都设置为cat,验证了我的文件保存和恢复没有问题。
- 我将 clean 设置为python ~/Documents/pyscripts/unzip.py。提交和 checkout 后,文件现在更大(未压缩),但在 MS-Word 中打开时出现错误。此外,md5 与上面的“仅脚本”测试不匹配。尽管文件大小是相同的。
- 我将 clean 设置回 cat 并将磨砂设置为 python ~/Documents/pyscripts/zip.py。提交和 checkout 后,文件现在较小(压缩),但在 MS-Word 中打开时再次出错。 md5 再次与“仅脚本”测试不同,但文件大小匹配。
- 正如预期的那样,为 python 脚本设置 clean 和 scrap 会产生错误。
我真的迷失了方向,我认为 git Attributes 只是在 stdin 上提供输入并从 stdout 读取它。我已经测试了这两个脚本,可以很好地使用来自 cat 的管道和来自输出的重定向。我知道脚本正在运行 b/c 文件大小按预期更改,但是在文件中的某处引入了一个小更改。
其他引用
我在Win7上使用msgit,上面的所有命令都是在git bash窗口中输入的。
解压缩脚本
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:更新脚本以在文件处理期间写入内存而不是 stdout。
最佳答案
我发现使用 zipfile.ZipFile() 且目标为 stdout 会导致问题。打开目标为 StringIO() 的 zip 文件,然后最后将完整的 StringIO 文件写入 stdout 就解决了该问题。
我还没有对此进行广泛的测试,有些 .docx 内容可能无法得到很好的处理,但只有时间才能证明一切。我的测试文件现在打开时没有错误,而且由于使用比标准 .docx 格式更高的压缩,工作目录中的 .docx 文件更小。
我已经确认,在对 .docx 文件执行多次编辑和提交后,我可以打开该文件,编辑一行,然后提交,而不会在存储库大小中添加较大的增量。例如,一个 19KB 的文件,在存储库历史记录中进行了 3 次编辑后,在顶部添加了新行,在执行垃圾收集后,存储库中仅创建了 1KB 的增量。。使用 Mercurial 运行相同的测试(尽可能接近)会产生 9.3KB 的增量提交。我不是 Mercurial 专家,我的理解是 Mercurial 没有“gc”命令,因此没有运行任何命令。
关于python - 为什么从命令行调用的脚本与从 git 属性调用的脚本的行为不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18729473/