svnchecker 适配安装以及踩过的坑

原理

在SVN所在服务器安装checkstyle(一个开源的著名代码检查工具,可以自定义规则)进行代码检查。运用svn的hook功能。Svn内置了钩子功能,当有事件发生的时候将自动调起一个程序。我们可以定制这段程序以实现自己的想要的功能。可以接受的事件包括:提交、加锁、解锁、改变等。以“提交”事件举例,当提交事件发生之前将执行hooks中的pre-commit脚本,提交事件之后将执行hooks中的post-commit脚本。于是我们就可以在pre-commit脚本里加入执行checkstyle的命令。此处我们再扩展一下,不直接执行checkstyle,而是先执行一个叫SVNChecker的工具,借助SVNChecker执行CheckStyle。SVNChecker是一个开源的检查框架,他可以做各种检查(不仅仅是代码规范性),并针对各种检查匹配处理模块。也就是说目前虽然只是进行“代码规范性检查”,但是加入SVNChecker后,今后若想进行其他检查,就可以轻而易举的扩展了。

配置

1、下载checkstyle,官网:http://checkstyle.sourceforge.net/
下载checkstyle-version-bin.zip的压缩包,里面有一堆文件,但主要用到的文件是checkstyle-version-all.jar,这是代码检查的核心包,配置的代码检查规矩就是由该包去进行,但反编译该包,查看里面的Main.java文件,发现有一个不太好的问题,源代码是:

1
2
3
if (filesToProcess.isEmpty()) {
result.add("Files to process must be specified, found 0.");
}

草泥马啊,提交的文件列表如果为空,就不让提交了,也就是说如果删除一个文件,提交代码,会提示错误:Files to process must be specified, found 0. 没办法,BOSS要改,下载源码一看,又是一个坑,该项目已经停止维护了。。。而且是Maven构建的项目,搭建这个项目总是编译不过,报的异常主要是依赖包找不多,好吧,时间比较紧,不费时间调包了,直接强行插入修改的类,下载checkstyle-version-bin.zip,再下载该version相关的源码,修改完后直接转成class文件,本人修改的Main,java,生成Main.class,然后解压checkstyle-version-all.jar,替换里面的Main.class,运行,结果报异常:NoSuchMethodError:Main$CliOptions,原来CliOptions是Main.java里面的内嵌类,生成class文件的时候会独立成一个Main$CliOptions.class文件,两者有唯一的识别联系,所以Main$CliOptions.class也要替换原来的,OK,运行,成功。

2、下载svnchecker,官网:http://svnchecker.sourceforge.net/overview.php
svnchecker是一个python项目,里面主要对检查文件列表前的处理,比如过滤,设置java运行环境参数,调用checkstyle.jar包对代码文件进行规范检查。BOSS提出了新需求:对之前提交的代码文件过滤,只对从现在起创建的代码文件进行代码规范检查,好吧,找了一个Python语法的网站:http://www.runoob.com/python/python-files-io.html
然后就对着这个网站边看svnchecker的源码边查Python语法。Python语法还是挺人性化的,比较好上手,svnchecker的目录:Main.py,setup.py,checks(代码检查的核心),modules(配置相关的核心),handlers。写了两个Python脚本,一个扫描过滤名单脚本,一个对提交的文件列表进行过滤的脚本,如下:

扫描过滤名单脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import os
import re

BASE_DIR = "/home/lin/Documents/paths/locker_cn"

def load_all_java(dir_path):
java_file_paths = []
for root,dirs,files in os.walk(dir_path):
for filespath in files:
path = os.path.join(root, filespath)
if re.match(".*java$",path):
path = path.replace(BASE_DIR,"")
java_file_paths.append(path)
return java_file_paths

def write_black_list(filename,filelist):
blackfile = open(filename,"wb")
try:
for file in filelist:
blackfile.write(file);
blackfile.write("\n");
finally:
blackfile.close()


def main():
java_file_paths = load_all_java(BASE_DIR)
for str in java_file_paths :
print str
write_black_list("blackfiles.ini",java_file_paths)

if __name__ == '__main__':
main()

对提交的文件列表进行过滤的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
DEBUG = True #False #True
LOG_PATH = "/data/tmp/svnchecker-0.3/log"

def writeLog(log):
if DEBUG :
ISOTIMEFORMAT='%Y-%m-%d %X'
fo = open(LOG_PATH,"a")
fo.write(time.strftime(ISOTIMEFORMAT,time.localtime()))
fo.write(" : ")
fo.write(log)
fo.write("\n")
fo.close();

def getBlackFile(filename):
files = []
if filename is not None and os.path.exists(filename) :
blackfile = open(filename,"r")
try:
for line in blackfile.readlines():
line=line.strip('\n')
files.append(line)
finally:
blackfile.close()

return files

# remove black list
blackFilename = "blackfiles.ini"
localblack = os.path.join(reposPath, "hooks", blackFilename)
globalblack = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),blackFilename)
blackFiles = []
if localblack is not None and os.path.exists(localblack):
blackFiles = getBlackFile(localblack)
elif globalblack is not None and os.path.exists(globalblack):
blackFiles = getBlackFile(globalblack)

if len(blackFiles) >0 :
for temp2 in blackFiles :
writeLog("black list files:"+temp2);

if len(files) > 0 and len(blackFiles) > 0 :
tempfiles = files [:]
for index in range(len(tempfiles)) :
file = tempfiles[index]
if file in blackFiles :
files.remove(file)

熟悉svnchecker的程序猿可能会有疑问:
a、checkstyle-version-all.jar里面报的异常:Files to process must be specified, found 0.不是可以通过check里面的Checkstyle.py去修改?
答:是可以的,但碍于处女座的思维,不改checkstyle-version-all.jar里面的源码觉得不完美
b、svnchecker不是有一个Checkstyle.IgnoreFiles属性可以设置忽略的检查文件?
答:可以,但IgnoreFiles属性是正则表达式匹配的,用的是search的匹配规则

3、配置checkstyle检查规则,可以参考

google的规范
http://checkstyle.sourceforge.net/google_style.html
sun的规范
http://checkstyle.sourceforge.net/sun_style.html

4、配置svnchecker检查项

1
2
3
4
5
6
7
[PROJECT]
Main.Regex=^/appfront/src/main/java/ #不检查的文件正则表达式
Main.PreCommitChecks=Checkstyle #代码检查的插件名,一般是Checkstyle
Checkstyle.FailureHandlers=Console #错误信息输出
Checkstyle.Java=/usr/bin/java #java运行环境地址
Checkstyle.Classpath=$CHECKSTYLE_PATH/checkstyle-5.3-all.jar #checkstyle的jar绝对地址
Checkstyle.ConfigFile=$CHECKSTYLE_PATH/checks.xml #检查规则文件

5、最后就是在仓库的hook文件夹里面修改pre-commit文件,添加:

1
$SVNCHECKER_PATH/Main.py PreCommit $1 $2 || exit 1   #Main.py的绝对地址

完~~~

文章目录
  1. 1. 原理
  2. 2. 配置
,