我有一堆Sed / unix fu,我开始怀疑不会是完成任务的最佳方式,因为出现的线条不一致svn diff'...
svn diff -r 1:9 |
expand |
sed -e 's/^Index: \(.*\)/]}, { "index":"\1", /g' |
sed -e 's/^--- \(.*\)/"from":"\1", /g' |
sed -e 's/^+++ \(.*\)/"to":"\1", "chunks":[/g' |
sed -e 's/^@@ \(.*\) @@/]},{"locn":"\1", "lines": [/g' |
sed -e 's/^-\(.*\)/"-\1",/g' |
sed -e 's/^+\(.*\)/"+\1",/g' |
sed -e 's/^ \(.*\)/" \1",/g' |
sed -e 's/^==============.*//g' |
tr -d '\n' |
sed -e 's/"chunks":\[\]},{/"chunks":\[{/g' |
sed -e 's/^]}, \(.*\)/{"changes":[ \1]}]}]}/g' |
sed -e 's/,\]}/]}/g' |
jshon
它可靠地转变......
Index: file1.txt
===================================================================
--- file1.txt (revision 8)
+++ file1.txt (revision 9)
@@ -1,3 +1,5 @@
+zzz
+
aaa
Efficiently Blah blah
@@ -7,3 +9,5 @@
functional solutions.
bbb
+
+www
进入......
{
"changes": [
{
"index": "file1.txt",
"to": "file1.txt (revision 9)",
"from": "file1.txt (revision 8)",
"chunks": [
{
"locn": "-1,3 +1,5",
"lines": [
"+zzz",
"+",
" aaa",
" ",
" Efficiently blah blah"
]
},
{
"locn": "-7,3 +9,5",
"lines": [
" functional solutions.",
" ",
" bbb",
"+",
"+www"
]
}
]
}
]
}
但是'svn diff'可能会出现的问题比我处理的更多,我想知道在这个方向上进行是否愚蠢。
答案 0 :(得分:2)
我可能会使用diff parser in libsvn_diff。我不确定它是否被绑定包装,但它很可能是从Python绑定开始的。
从svn_diff_open_patch_file()开始,然后通过调用svn_diff_parse_next_patch()迭代文件中的补丁,直到它为svn_patch_t提供NULL。
一旦你有了每个文件的结构,生成你的JSON应该是微不足道的。
公平警告,diff解析器中可能存在错误。它是为svn补丁编写的,我发现了错误(虽然我认为大多数错误都在补丁应用程序中而不是解析)。另一方面,这样做应该意味着即使我们调整补丁格式输出,你也应该总是有一个好的解析器。当然,您的错误报告(如果您最终拥有)可以改进我们的解析器。
只有我发生的其他事情是API不流畅(它适用于文件),这可能不是你想要的。此外,如果你真的想要走下兔子洞,你可以直接驱动WC / RA层,作为编辑器驱动器的接收器,生成你的json输出而不是统一的差异。但这可能比你想要的更多,因为有大量的代码只是为了处理差异目标类型的所有不同变化(本地到本地,回购到回购,本地到回购,回购到本地)。
示例强>
所以我决定玩diff解析器。我最终编写了以下python脚本来使用它,并生成与您的示例几乎相同的JSON输出。请注意,解析器会抛弃索引行,因此我的输出中没有。
我遇到了一个小的改动我必须对Python SWIG绑定做这个工作(svn_patch_t的hunks字段没有正确转换为python列表),我在r1548379上修复了Subversion trunk(我怀疑补丁会干净地适用于1.8)。
请注意,svn_diff_hunk_readline_diff_text()的文档说第一行将是hunk标题,但它似乎不是真的。虽然您可以使用svn_diff_hunk_get_ {original,modified} _ {start,length}函数重建所需的hunk标头数据。
我没有费心去处理属性更改解析或操作解析(我不认为对此的支持是完全的,但如果你想要它,我会把它作为一个练习给你)。
如果这不是最Pythonic代码我的appologies。其中一部分原因是被包装的C API不利于这一点,部分原因是我对Python不太满意。我是用Python做的,因为这些绑定在这方面更接近完成。
您只需运行以下脚本:python scriptname.py patchfile
import sys
from svn import diff, core
import json
class UDiff:
def convert_svn_patch_t(self, patch, pool):
data = {}
data['from'] = patch.old_filename
data['to'] = patch.new_filename
iter_pool = core.Pool(pool);
chunks = []
for hunk in patch.hunks:
iter_pool.clear()
chunk = {}
orig_start = diff.svn_diff_hunk_get_original_start(hunk)
orig_len = diff.svn_diff_hunk_get_original_length(hunk)
mod_start = diff.svn_diff_hunk_get_modified_start(hunk)
mod_len = diff.svn_diff_hunk_get_modified_length(hunk)
chunk['locn'] = "-%d,%d +%d,%d" % \
(orig_start, orig_len, mod_start, mod_len)
lines = []
while True:
text, eol, eof = diff.svn_diff_hunk_readline_diff_text(hunk,
iter_pool,
iter_pool)
if eof:
break;
lines.append("%s%s" % (text, eol))
chunk['lines'] = lines
chunks.append(chunk)
data['chunks'] = chunks
self.data = data
def as_dict(self):
return self.data
def __init__(self, patch, pool):
self.convert_svn_patch_t(patch, pool)
class UDiffAsJson:
def __init__(self):
self.pool = core.Pool()
def convert(self, fname):
patch_file = diff.svn_diff_open_patch_file(fname, self.pool)
iter_pool = core.Pool(self.pool)
changes = []
while True:
iter_pool.clear()
patch = diff.svn_diff_parse_next_patch(patch_file,
False, # reverse
False, # ignore_whitespace
iter_pool, iter_pool)
if not patch:
break
udiff = UDiff(patch, iter_pool)
changes.append(udiff.as_dict())
data = {}
data['changes'] = changes
diff.svn_diff_close_patch_file(patch_file, iter_pool)
return json.dumps(data, indent=True)
if __name__ == "__main__":
udiffasjson = UDiffAsJson()
sys.stdout.write(udiffasjson.convert(sys.argv[1]))