python脚本抽取patch

方案开发时,同一个平台的代码针对不同的客户,可能有不同的需求改动。当新项目来时,可能一些需求是以往项目做过的,简单粗暴的办法是由开发人员重复的将之前的需求改动porting到新项目上来。而这种做法基本就是纯体力活,本篇文档介绍如何利用Python脚本,根据特殊标签从项目代码里抽取出bug对应的patch,减轻抽取patch的工作量。

需求描述

新项目上一些需求老项目已经做过,需要提供一种自动化方案快速的将这些需求改动抽取成一个个patch,方便快速的将需求导入新项目。项目代码通过git管理,每一个需求对应一个bug号。

需求分析

知道了bug号,则可以通过bug号查看到git提交的记录,利用命令:

git format-patch

生成patch。但如何找出bug对应的是哪个git,又如何通过bug号查找出对应的comment id。看看命令:

git log –oneline

的输出结果:
这里写图片描述
可以结合grep命令筛选出bug对应的comment id。
至于如何找bug对应的git呢?很显然不可能手动进入git目录去执行上面的命令,有没有一种方法可以将源码下所有git的git log输出结果定向到一个文件里,这样就可以在这个文件里过滤出需要的commit了。答案是肯定的,命令repo forall 就可以办到,查看repo forall的帮助信息:
这里写图片描述
-p 参数可以输出git的目录,那么将git命令和repo forall结合起来:

repo forall -p -c ’ git log –no-merges –oneline’ > allpatch

它就会将源码下所有git的输出信息汇总到allpatch文件中。顺便提下 git log –no-merges中–no-merges参数的含义:
这里写图片描述
下图是输出的部分结果:
这里写图片描述

代码实现

根据上面的分析,脚本的大致框架应该如下:
这里写图片描述
给出简单的主要代码:

#!/usr/bin/env python
import os
import sys

'''
this script use to create patch from bugnumbers.
'''
class FilterPatch:
    def printBreakLine(self):
        line = "################################\n"
        print line
        return line
    def helpInfo(self):
        print "need input filterPatch file which record bugnumbers \n"
        sys.exit(1)
    def filterPatch(self,allPatchsFile,filterFile):
        allpatchs = allPatchsFile
        bugnumbers = filterFile
        filterResult = open("filterPatchsResult","w")
        fileLineNum = 0
        for patch in open(allpatchs,'r'):
            if (patch.startswith("project")):
                filterResult.write(self.printBreakLine())
                filterResult.write("%s" % patch)
                print patch
                filterResult.write(self.printBreakLine())
                fileLineNum = fileLineNum + 3
            else:
                for bug in open(bugnumbers):
                    if bug.strip() != None and patch.find(bug.strip()) != -1:
                        filterResult.write("bug===%spatch====%s\n" % (bug,patch))
        filterResult.close()

class CreatePatch:
    def createPath(self):
        if os.path.exists("filterPatchsResult"):
            flag = 0
            gitDirName = None
            for git in open("filterPatchsResult"):
                if (git.startswith("project")):
                    gitDirName = git.replace("project"," ").strip()
                elif (git.startswith("patch====")):
                    os.chdir("/local/source_code/androidN-source-code/%s" % (gitDirName))
                    commitId = git.split("====")[1].split(" ")[0]
                    os.system("git format-patch --start-number %d -1 %s" % (flag,commitId))
                    curdir = os.getcwd()
                    os.chdir("/local/source_code/androidN-source-code")
                    os.system("cp --parents %s/*.patch /local/source_code/androidN-source-code/Patchs" % (gitDirName))
                    os.system("rm -v %s/*.patch" % (gitDirName))
                    flag = flag +1
                else:
                    pass

def createAllPatchFile(path):
    os.chdir(path)
    os.system("repo forall -p -c  'git log --no-merges --oneline' > allpatch")
    return os.getcwd() + "/allpatch"

def initArgs():
    sourcePath = raw_input("Please input the absolutely path of baseline source code:\n")
    if not os.path.isdir(sourcePath):
        print "invalid path \n"
        print "use default source code path /local/source_code/androidN-source-code\n"
        sourcePath = "/local/source_code/androidN-source-code"
    bugnumbersFile = raw_input("Please input filterPatch file which record bugnumbers:\n")
    if not os.path.isfile(bugnumbersFile):
        print "invalid filterPatch file \n"
        print "use default filterPatch file bugnumber\n"
        bugnumbersFile = "bugnumber"
    os.system("rm -rf /local/source_code/androidN-source-code/Patchs")
    os.mkdir("/local/source_code/androidN-source-code/Patchs")
    os.system("sort -u %s > uniqBugnumber" % (bugnumbersFile))
    bugnumbersFile = "uniqBugnumber"
    return (sourcePath,bugnumbersFile)

if __name__ == "__main__":
    try:
        args = initArgs()
        allPatchsFile = createAllPatchFile(args[0])

        filterPatch = FilterPatch()
        filterPatch.filterPatch(allPatchsFile,args[1])

        createPatchs = CreatePatch()
        createPatchs.createPath()
    except KeyboardInterrupt:
        print
    except EOFError:
        print

过滤出来文件内容显示如下:
这里写图片描述
脚本里已经加入了patch汇总功能。在看下最终输出的patch结构。
这里写图片描述
可以看到patch已经按照git目录自动汇总在了一起。后续就可以用这些patch去新项目上打patch了。
在添加一个功能,按照bug号来归类patch。

#!/usr/bin/env python

import os
import sys

class GroupPatch:
    def group(self,path):
        os.chdir(path)
        os.system('rm -rf GroupOut')
        os.mkdir('GroupOut')
        for bug in open("uniqBugnumber"):
            bug = bug.strip()
            os.system("grep 'number:%s' . -nsr|tee temp" % (bug))
            for patch in open("temp"):
                gitName = patch.split()[0].split(":")[0]
                if not os.path.isdir('GroupOut/%s' % (bug)):
                    os.system('mkdir -p GroupOut/%s' % (bug))
                os.system('cp --parents %s GroupOut/%s' % (gitName,bug))
            os.remove('temp')


def initArgs():
    PatchsFolder = raw_input("please input path of patchs folder")
    if not os.path.isdir(PatchsFolder):
        PatchsFolder = "/local/source_code/androidN-source-code/Patchs"
    return PatchsFolder

if __name__ == "__main__":
    try:
        args = initArgs()
        group = GroupPatch()
        group.group(args)
    except KeyboardInterrupt:
        print
    except EOFError:
        print

其输出结果如下:
这里写图片描述

总结

  1. 如果一个bug分别在多个git提交了patch,这种情况脚本能正常抽取出来patch吗?
    因为repo forall这一步导出的是所有bug,只要提交记录里有bug号,并且该bug号在需要抽取的bug list里,那么可以正常抽取。在实际运用该脚本时,只要老项目上patch是严格按照功能提交的,并且每个功能都有唯一的特殊标签,就可以用这个标签来筛选patch。

  2. 按照bug号归类patch只是方便查看一个功能的实现,真正往新项目导入这些patch时,不能按照bug号打patch,因为bug之间是有依赖关系的,如果bug 111依赖bug 0000,那么在打patch时就必须先打bug 000的patch,否则bug111的patch就会打入失败。

  3. 重复性的工作,拿python写脚本是非常高效的。在没有这个脚本之前,新项目上老需求的导入是分发给各个开发人员完成的。几行简单的命令行组合成的脚本就可以将多人完成的任务在不到一分钟内完成近乎一半(剩下合入patch的工作),多了解点脚本知识还是很有必要的。
  4. 脚本涉及到的命令汇总.
    • repo forall -p -c ‘git log –no-merges’ 对源码下每一个git执行-c 参数里的命令
    • sort -u 去重并排序bug list
    • git format-patch –start-number -1 对commit输出对应的patch文件,并且patch头以int的值开始
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值