使用Python写服务器端的SVN Hook

什么是SVN Hook

SVN hook 脚本,大都译为SVN钩子,提供了一种非常强大而且灵活的方式把代码库的各种事件与自定义操作联系起来。举个例子来说,代码提交到服务器以前要进行基于自定义规则的审查和检查,审查通过则继续提交,审查失败则拒绝提交。

客户端Hook VS 服务器端Hook

服务器端Hook

服务器端Hook脚本程序在服务器上执行,钩子可以调用bat批处理文件(在Windows系统中)、bash脚本、可执行文件或者一些类似于perl、python等的脚本,一共提供了一下9种情况来实现不同阶段的自定义操作:

  • 关于锁定的2种

    • pre-lock
    • post-lock
  • 关于解锁的2种

    • pre-unlock
    • post-unlock
  • 关于提交的3种

    • start-commit
    • pre-commit
    • post-commit
  • 关于属性的2种

    • pre-revprop-change
    • post-revprop-change

使用svn admin create命令创建出来的代码仓库,根目录下面有个hooks文件夹,里面已经预置了上述几种钩子脚本的模板,看了一下里面是bash脚本,如下图所示。如果要自定义其中的某一个,比如pre-commit.tmpl,把该文件拷贝一份并且重命名为pre-commit,注意要有可执行权限!

使用Python写服务器端的SVN Hook_第1张图片
svn hooks 文件夹

客户端Hook

svn的客户端也具备Hook的功能,比如windows上常用的TortoiseSVN,可以在设置的界面中设置脚本程序的类型、工作目录、执行命令等内容。如下图所示。

使用Python写服务器端的SVN Hook_第2张图片
TortoiseSVN Hooks 脚本配置界面

两者对比

对比两者的作用、功能以及实现方式,大概有下面几点不同:

  1. 作用范围不同:服务器端的hook作用于所有提交到svn server上面的代码;而客户端只是在本机上进行检查;
  2. 提供的钩子类型不同:从上述图片中可以看到两者所提供的钩子类型存在差别;
  3. 执行环境不同:客户端的环境复杂多样,Windows、Linux、Mac OS X都有,每个系统上执行hook脚本的环境是不同的,所以客户端脚本很难做到统一。并且,不同公司出品的客户端可能在hook的功能上还会有所差别(没仔细研究其他SVN客户端产品,纯属猜测)。服务器虽然也有不同的操作系统,不过定下系统之后,svn服务器端hook脚本的执行环境相对单一。
  4. hook脚本实现方式不同:SVN客户端的代码库是以文本形式存储的源代码,想要进行什么操作都可以,自由度很高;上传到服务器上的代码都是二进制文件,存储在代码库的DB中,需要配合svnlook等命令来使用。

实战一下

下面记录了本次使用Python脚本做pre-commit钩子的示例,在该示例中展示了几种主要的功能,svnlook log, svnlook changed, svnlook cat三个命令的使用方法。注意,该示例摘自完整脚本,只是示意用法,不能直接运行。

#!/usr/bin/env python
# -*- coding: utf-8 -*- 

import sys
import os
import re

def main(argv):
    # 从参数中取出来代码库和事务信息
    (repos, txn) = argv
    # svnlook log拿到的是用户提交时填写的log信息,然后随便你想做什么
    message = "".join(os.popen("svnlook log '%s' -t '%s'" % (repos, txn)).readlines()).strip()      

    # svnlook changed拿到的是用户提交的文件,这个列表中有文件的状态(A,U,D之类的)和文件名
    changelist = os.popen("svnlook changed '%s' -t '%s'" % (repos, txn)).readlines()

    # svnlook cat能读出用户提交文件的内容
    fileContent = "".join(os.popen("svnlook cat -t %s %s %s" % (txn, repos, filename)).readlines()).strip()
    
    # 返回
    if msg == '':
        sys.exit(0)
    else:
        # 输出返回信息
        sys.stderr.write(msg)
        sys.exit(1) 

if __name__ == "__main__":
    # sys.stderr.write(os.getcwd())
    # 发现默认的工作目录竟然是跟目录“/”,这里要换一下当前工作目录
    os.chdir(sys.path[0])
    # sys.stderr.write(os.getcwd())
    main(sys.argv[1:])

有几点要交代:

  1. 脚本返回0的话,svn客户端会提交成功;脚本返回非0,客户端提交代码失败;
  2. 返回给客户端的错误信息,需要脚本输出到标准错误输出;
  3. 如果跟执行环境配置有关的话,工作目录要切换;
  4. svnlook命令有很多,可以参考5。

参考4是Github上的一个完整的示例,感谢作者,供参考。

参考

  1. https://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug-settings.html#tsvn-dug-settings-hooks
  2. https://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-repository-hooks.html
  3. http://wordaligned.org/articles/a-subversion-pre-commit-hook
  4. https://github.com/lisijie/python-svn-hook/blob/master/pre-commit.py
  5. http://svnbook.red-bean.com/nightly/en/svn.ref.svnlook.html

你可能感兴趣的:(使用Python写服务器端的SVN Hook)