内容简介:python实现web svn diff
最近想做一个在线codereivew的功能,需要在web页面上分两栏(side-by-side)展示新老代码的差异(diff)。
在github参考了一些项目,例如:coderev、cdiff;经过一定的尝试,最终选择了使用 Python 来实现这个功能,因为python内置的difflib标准库里有一个计算diff的函数是专门用来生成两栏(side-by-side)视图用的,而这个算法是挺复杂的,网上并没有资料讲解,所以拿来即用吧。
项目地址: https://github.com/owenliang/side-by-side-diff
项目效果: https://owenliang.github.io/side-by-side-diff/sample/side-by-side-view.html
思路
生成patch
首先,需要生成diff内容,也就是patch。这种patch文件的格式如下:
Index: bgm/application_zdm/views/mgc_detail.php =================================================================== --- bgm/application_zdm/views/mgc_detail.php (revision 172736) +++ bgm/application_zdm/views/mgc_detail.php (working copy) @@ -189,7 +189,7 @@ </div> </div> <div class="button-group pull-right"> - <a class="btn btn-primary btn-lg btn-submit" name="publish"><?= $status != 2 ? '发布榜单' : '保存榜单' ?></a> + <a class="btn btn-primary btn-lg btn-submit" name="publish"><?= $status == 2 ? '保存榜单' : '发布榜单' ?></a> <a class="btn btn-success btn-lg btn-submit" name="draft"><?= $status != 2 ? '保存为草稿' : '榜单已发布,退回为草稿' ?></a> </div> </form> @@ -236,27 +236,6 @@ var uiLi3=[{n:"请选择",k:0}]; $(this).find("ul:first").children().each(function(){ uiLi3.push({ - n:$(this).find("a:first").html(), - k:$(this).find("input:first").val() - }); - }); - uiLi2.push({ - s:$(this).find("a:first").html(), - k:$(this).find("input:first").val(), - r:uiLi3 - }); - }); - uiLi1.push({ - n:$(this).find("a:first").html(), - k:$(this).find("input:first").val(), - a:uiLi2 - }); - }); - cateList.push({ - p:$(this).find("a:first").html(), - k:$(this).find("input:first").val(), - c:uiLi1 - }); }); cateJson = {dataList:cateList}; return cateJson; @@ -285,42 +264,19 @@ } }; - var toolBox={ - cateSelected: function (curSelected) { - //初始化商品分类json数据 - handleCategory.getCateJson(function(data){ - var curSelectedArr=[]; - var catSelectConf={ - jsonData:data, - first:0,//电脑数码 - second:0,//手机通讯 - third:0,//非智能手机 - four:0, - nodata:"none" + var toolBox={vwregergweartvwertgreqgewr }; if(curSelected){//商品分类id匹配成功 curSelectedArr=curSelected.split(","); if(curSelectedArr.length>0){ $.each(curSelectedArr,function(index,cid){ - if(index==0){ - catSelectConf.first=cid; - }else if(index==1){ - catSelectConf.second=cid; - }else if(index==2){ - catSelectConf.third=cid; - }else if(index==3){ - catSelectConf.four=cid; - }else{ + if(index=sfawdv + fdd + fvweq + fa + wefawre + fgvwref - } - }) - } - } - handleCategory.cateInit(catSelectConf);//选中的商品分类填充到select - }); - }, - }; - toolBox.cateSelected("<?= implode(',', $categories) ?>"); </script> @@ -341,38 +297,7 @@ $('#tag-selector').select2({ ajax: { - url: '/tool/tag_search_by_title', - dataType: 'json', - data: function (params) { - return { - term: params.term, - page: params.page - }; - }, - processResults: function (data) { - return { - results: data.data, - pagination: { - more: data.data.length > 0 - } - }; - } - }, - placeholder: '键入关键词开始搜索...', - minimumInputLength: 1 - }); - - $('.btn-submit').click(function (event) { - event.preventDefault(); - - var formData = $(this).closest('form').serializeArray(); - - switch (this.name) { - case 'draft': - formData.push({name: 'status', value: 1}); - formData.push({name: 'is_deleted', value: 0}); - break; - case 'publish': + formData.push({name: 'status', value: 2}); formData.push({name: 'is_deleted', value: 0}); break;
一般我们通过svn diff或者git diff就可以生成,或者通过diff -u filename1 filename2也可以生成。
解析patch
我们需要解析patch文件,这个过程并不复杂。
类似于这种段落,表示是某个文件发生了变更:
Index: bgm/application_zdm/views/mgc_detail.php =================================================================== --- bgm/application_zdm/views/mgc_detail.php (revision 172736) +++ bgm/application_zdm/views/mgc_detail.php (working copy)
类似于这种段落,表示文件内的某一段发生了变化:
@@ -189,7 +189,7 @@ </div> </div> <div class="button-group pull-right"> - <a class="btn btn-primary btn-lg btn-submit" name="publish"><?= $status != 2 ? '发布榜单' : '保存榜单' ?></a> + <a class="btn btn-primary btn-lg btn-submit" name="publish"><?= $status == 2 ? '保存榜单' : '发布榜单' ?></a> <a class="btn btn-success btn-lg btn-submit" name="draft"><?= $status != 2 ? '保存为草稿' : '榜单已发布,退回为草稿' ?></a> </div> </form>
可见,上述段落删掉了一行,又增加了一行,相当于替换了原先的行。
而没有-号与+号的行,称为上下文(context)行,表示新老文件都拥有且没有变化过的行。
还原老与新段落
对于上述每个段落,我们需要还原出老文件和新文件。
context和-的行是老文件拥有的,而context和+的行是新文件拥有的,通过这样划分就可以得到每个差异段落的老内容和新内容。
调用python重算diff
现在可以将每个段落的老内容和新内容,作为一个pair传递给python的difflib._mdiff函数,这个函数会计算返回一个数组,每一个元素代表了双栏(side-by-side)视图中的一行。
我们需要根据_mdiff的返回值,对新老的行号进行重新标记。
在我的diff.py程序中,最终输出的结果在这里查看: https://raw.githubusercontent.com/owenliang/side-by-side-diff/master/sample/diff.json 。
可以观察到,最外层数组是若干的index,即发生变化的文件。
而index.segments里的每一个元素则是一个发生差异的段落。
段落内的rows记录了差异的行,我们只需要顺序的展示为两栏即可;左侧是老文件的行内容,右侧是新文件的行内容,红色标识变化前的行,绿色标识变化后的行。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- php如何实现session,自己实现session,laravel如何实现session
- AOP如何实现及实现原理
- webpack 实现 HMR 及其实现原理
- Docker实现原理之 - OverlayFS实现原理
- 为什么实现 .NET 的 ICollection 集合时需要实现 SyncRoot 属性?如何正确实现这个属性?
- 自己实现集合框架(十):顺序栈的实现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Masterminds of Programming
Federico Biancuzzi、Chromatic / O'Reilly Media / 2009-03-27 / USD 39.99
Description Masterminds of Programming features exclusive interviews with the creators of several historic and highly influential programming languages. Think along with Adin D. Falkoff (APL), Jame......一起来看看 《Masterminds of Programming》 这本书的介绍吧!