StatCVS 是一个创建并发版本系统(Concurrent Versions System -CVS)储存库活动图表的方便工具。在本文中,开发人员
Tom Copeland 将解释如何安装、运行 StatCVS,概述生成的报告,然后还将介绍如何为多个储存库生成报告,StatCVS
的内幕及限制等多项内容。
如果要接手一个已经运行了好几年的软件项目,那么怎样才能得到对项目开发历史的认识呢?最好的方法可能就是与曾经参与该项目的开发人员对话,但是这说起来容易,做起来却很困难。原有的开发人员通常都已转到了其他项目中,而且要找到他们也很难。您可以查看释出频率(release
frequency),尽管这可能受非技术性的强制规定控制(有时可能只是出于“我们要在本财政年度末做一个发布”的理由)。您可以查看
bug 和特性请求跟踪器,还可以在开放和关闭的 bug 讨论中挖掘信息。或者可以直接进入源代码历史记录,用 StatCVS 这样的工具查看曾做过哪些记录,这些记录是谁修改的。我将
StatCVS 运用在各种大型项目上已经有好几年的时间了,它生成的报告一直都很不错。在本文中,将演示如何在项目上设置、运行 StatCVS,如何阅读它生成的报告,以及
StatCVS 需要改进的地方。
StatCVS 是一个 Java 程序,需要 JDK 1.4 或更高版本的支持。从命令行安装 StatCVS 最容易:只要下载最新的发行版(请参阅参考资料),将它解压到一个目录中即可;我用的是
/usr/local/statcvs/ 目录。而且,如清单 1 所示,我还创建了一个符号链接,叫作 statcvs ,它链接到刚刚安装的版本上。这可以节约日后的一些打字工作时间,更重要的是,日后只要把符号链接修改为指向要使用的版本,就可以在
StatCVS 的不同版本间切换。
清单 1. StatCVS 的符号链接
[root@hal local]# pwd
/usr/local
[root@hal local]# ln -s statcvs-0.2.2 statcvs
[root@hal local]# ls -l | grep statcvs
lrwxrwxrwx 1 root root 13 Jan 13 14:27 statcvs -> statcvs-0.2.2
drwxrwxr-x 2 root root 4096 Oct 13 23:32 statcvs-0.2.2
-rw-rw-r-- 1 tom tom 1344753 Jan 13 13:49 statcvs-0.2.2.zip
|
如果列出 statcvs 目录中的文件,就可以看到那里没有任何适用于 StatCVS 的支持 JAR 文件(supporting
JAR file)。惟一的 JAR 文件是 statcvs.jar,它包含 StatCVS 使用的惟一的第三方库:JFreeChart。这种方法使得开始了解
StatCVS 变得更容易,因为不需要关于类路径的更多知识。
为了演示 StatCVS 的工作方式,需要找到一个带有有趣的 CVS 历史记录的项目,并生成一些活动报告。developerWorks
的项目 Jikes(请参阅参考资料)已经进行了一段时间,有大量开发人员,还有一个公共的
CVS 储存库,所以它是一个好例子。
从 CVS 中获得源代码
为了从 StatCVS 得到 Jikes 的报告,需要得到最新的源代码,并生成一个 CVS 日志文件让 StatCVS 分析。所以,需要从
Jikes 的 CVS 储存库签出它的源代码。Jikes 的开发人员允许拥有只读权限的匿名用户对其储存库进行访问,所以可以用这个方法得到源代码,如清单
2 所示:
清单 2. 从 Jikes 的 CVS 储存库中签出源代码
[tom@hal tmp]$ cvs -d:pserver:anoncvs@www-124.ibm.com:/usr/cvs/jikes login
Logging in to :pserver:anoncvs@www-124.ibm.com:2401/usr/cvs/jikes
CVS password: [ Type "anoncvs" here ]
[tom@hal tmp]$ cvs -d:pserver:anoncvs@www-124.ibm.com:/usr/cvs/jikes co jikes
cvs server: Updating jikes
U jikes/.cvsignore
... several thousand lines elided ...
|
创建 CVS 日志文件
现在机器上已经有了 Jikes 代码,需要创建一个 CVS 日志文件供 StatCVS 处理。要创建这个文件,需要进入 jikes
目录,运行 cvs log 命令。正如从清单 3 中看到的,我把命令的输出重定向到了一个叫作 logfile.txt
的文件:
清单 3. 创建 CVS 日志文件
[tom@hal tmp]$ cd jikes/
[tom@hal jikes]$ time cvs -d:pserver:anoncvs@www-124.ibm.com:/usr/cvs/jikes log > logfile.txt
real 0m40.719s
user 0m0.516s
sys 0m0.314s
[tom@hal jikes]$
|
只是为了好玩,我对此进行了计时。在我的工作站上,这大约花费了 40 秒的时间,生成的日志文件大小约为 3.3 MB。
命令行界面
现在可以运行 StatCVS 生成报告了。可以从命令行运行 StatCVS,也可以从 Ant 运行(请参阅参考资料)。首先来看一下命令行界面,然后再来讨论
Ant。
StatCVS 从命令行运行很容易,因为只有一个 JAR 文件,而且可以把 JAR 文件名直接传给虚拟机。可以用不同的选项控制输出。这里是一些比较有用的选项:
-title [标题] —— 放在报告上的显示标题。
-output-dir [目录] —— 报告文件存放的位置;如果目录不存在,则自动创建该目录。
-include [模式] —— 只包含与指定模式匹配的文件。
-viewcvs [ViewCVS url] ——
储存库的 ViewCVS Web 界面的 URL(请参阅参考资料)。
下面用以上选项创建报告。首先,必须移动到 jikes/ 目录上,然后从命令行运行 StatCVS,如清单 4 所示:
清单 4. 从命令行运行 StatCVS
[tom@hal tmp]$ time java -jar /usr/local/statcvs/statcvs.jar \
-include "cpp;**/*.h" \
-output-dir report \
-title "Jikes" \
-viewcvs http://www-124.ibm.com/developerworks/oss/cvs/jikes/jikes/ jikes/logfile.txt jikes/
StatCVS - CVS statistics generation
real 0m15.232s
user 0m12.014s
sys 0m0.326s
[tom@hal tmp]$
|
注意,上面使用了 -include 参数,只捕获 C++ 源代码文件和头文件。在 CVS 模块中有许多其他文件(文档、配置脚本、报告、Web
页面等),但是本文只关心源代码。
Ant 任务
清单 5 显示了与清单 4 的命令行调用功能相同的 Ant 任务定义:
清单 5. 用 Ant 运行 StatCVS
<?xml version="1.0"?>
<project name="StatCvsAnt" default="main" basedir=".">
<taskdef name="statcvs" classname="net.sf.statcvs.ant.StatCvsTask"/>
<target name="main">
<statcvs
projectDirectory="jikes"
cvsLogFile="jikes/logfile.txt"
outputDirectory="report"
title="Jikes"
viewcvsURL="http://www-124.ibm.com/developerworks/oss/cvs/jikes/jikes/"
includeFiles="**/*.cpp;**/*.h"/>
</target>
</project>
|
报告放在清单 4 指定的报告目录中。如果用浏览器打开该目录中的 index.html 页面,该页面如图 1 所示:
图 1. Jikes 的 StatCVS 主报告页面
可以看到可用报告的分类:关于代码作者的一些统计数据、查看提交日志、代码段的行,以及关于文件和目录大小的一些统计。
代码行
代码行图表如清单 2 所示,它可能非常有趣:
图 2. Jikes 一段时间内的代码行数
这个图表中可以看出,代码最初是在 1999 年初导入的。从那以后,它增长得非常稳定,一直到 2001 底,那时代码的数量开始略有下降。还有几次,新的代码被引入或者旧的代码被重构出去,这些可以从代码行计数的急剧升降上表现出来。从
2004 年开始,似乎没有加入太多代码,这可能表明 Jikes 已经成熟到了某种程度,主要对它做些维护工作即可。
如果从主报告页上单击 Authors 链接,就可以看到数字和图表,它们指出每个参与者贡献了多少代码,如图 3 所示:
图 3. 每个参与者的代码行数
很明显,ericb 和 shields 对 lion 负责的代码有所贡献,而其他参与者也偶尔参与其中。注意,没有任何一个参与者从头到尾都参与了该项目。这个事实清楚地证明:长期项目需要那些拥有良好变量名和干净设计的清晰代码。
偶尔,StatCVS 在生成报告时表现得更聪明。如果 CVS 储存库只有一个参与者,那么主报告页上的链接只会写上“Author
page for joe_smith”,而且不会生成比较图表。这样 StatCVS 会运行得更快,报告页也会更整洁。
现在再来看一个参与者的活动图表。在主报告页面上,单击 Authors 链接可以访问 Author Activity,如图
4 所示,图中显示了每个参与者是添加了文件,还是修改了文件:
图 4. 添加代码 vs. 修改代码
您可以看到,shields 添加了大多数代码,这在预料之中,因为这个人显然是代码导入 CVS 之后的第一个维护者。同样,ericb
在项目启动之后几年之间一直进行类似的工作,主要在修改文件。
提交日志
提交日志(Commit Log)仅仅是对模块做的全部修改的一个列表。这个报告显示了谁做了修改,以及提交者在所做修改上附加的注释。而且,因为
Jikes 的储存库中有一个 ViewCVS 界面,运行 StatCVS 时还使用了一个 -viewcvs
参数,所以报告中包含了到已实际修改的源代码的链接。例如,在 2004 年 12 月 12 日,src/decl.cpp
有一个改动。如果点击 decl.cpp,会看到添加了一个 if 语句,还有一个注释。图
5 显示了 ViewCVS 的一部分,展示了两个文件版本之间的差异:
图 5. 一个具体的代码变化
还有其他一些报告:一个报告显示了平均文件大小,另外一个显示了如何通过目录树分布代码,还有一个则显示了哪个文件的版本改动最多。Jikes
的整个报告可以通过单击本文顶部或底部的 代码 图标得到,也可从 下载
小节得到。只要将它解压,并用浏览器打开 index.html,就可以看到这个报告。
前面已经看到了如何在一个 CVS 储存库上运行 StatCVS。但是,如果拥有多个储存库,那么您就会希望有一种方法能够每天夜里为所有的储存库生成
StatCVS 报告。因为可以从命令行运行 StatCVS,所以这是一个用脚本就可以解决的简单问题。以下是一些需要牢记的事项:
- StatCVS 是一个 Java 程序,所以需要大量内存才能启动。处理大型 CVS 储存库时也需要相当一段时间。所以如果运行它的机器还有其他用途,那么最好在处理不同的储存库之间让机器休息一会。如果运行的系统支持优先级设置,那么用低优先级来运行耗时比较长的任务是一个好主意。
- 如果定期将储存库添加到机器或从机器中删除储存库,那么某些储存库可能不包含模块。所以请事先检测这种可能性,免得没有必要地启动
StatCVS。
清单 6 显示了一个小小的 Ruby 脚本,可以在拥有公共父目录的多个储存库上运行 StatCVS(关于 Ruby 的更多内容,请参阅参考资料);在下载代码中也有这个脚本:
清单 6. 运行 StatCVS 处理多个储存库的脚本
#!/usr/local/bin/ruby
require 'fileutils'
HOME_DIR = "/tmp/"
CVS_DIR= "/path/to/my/cvs/"
BASE_OUTPUT_DIR = "/var/www/my-projects/"
DELAY = 5
Dir.chdir(HOME_DIR)
# get a list of all the repositories
Dir.new(CVS_DIR).entries.grep(/^[^.]/).each {|file|
# create a working directory
working_directory = "tmp_" + rand().to_s
Dir.mkdir(working_directory)
Dir.chdir(working_directory)
`cvs -d#{CVS_DIR}#{file} -Q co .`
FileUtils.rm_rf(%w{CVS CVSROOT})
# no need to run StatCVS if no modules exist yet
if !Dir.new(".").entries.grep(/^[^.]/).empty?
`cvs -d#{CVS_DIR}#{file} -Q log > log`
cmd = "/usr/java/java/bin/java "
cmd = cmd + "-jar /usr/local/statcvs/statcvs.jar "
cmd = cmd + "-output-dir #{output_directory} log ."
`#{cmd}`
FileUtils.rm("log", :force=>true)
end
# clean up and sleep for a bit to let things settle down
Dir.chdir(HOME_DIR)
FileUtils.rm_rf(working_directory)
sleep DELAY
}
|
因为 StatCVS 是一个开源项目,所以您可以得到它的代码。要得到 StatCVS 的代码,请从 StatCVS 的页面下载源代码
zip 文件(请参阅参考资料),或者从这个 Web 站点上的 CVS 储存库签出代码。
内幕
这里是一些关键的统计数字:
- 4,463 行代码,由 JavaNCSS 测量。
- 176 个 JUnit 测试。
- 一个很好的 Ant 构建文件,可以促进定制构建的编辑。
- 一个好标志 —— PMD 在 StatCVS 中找不到未使用代码的例子。
有关 JavaNCSS、JUnit、Ant 和 PMD 的更多信息,请参阅参考资料。
StatCVS 用 JFreeChart 来创建图表和图形。所有的图表都用可移植网络图形(Portable Network Graphics
- PNG)格式生成,大多数现代 Web 浏览器都支持这种格式。生成图表的代码被很好地封装在 net.sf.statcvs.renderer
包中。
限制
最大的限制可能是 StatCVS 不支持分支;它只能报告对每个模块的 HEAD 所做的修改。所以,如果开发团队的应用模式是为产品的每个版本建立一个新分支,并且只提交到这个分支,那么
StatCVS 无法返回正确的结果。这个问题曾在 StatCVS 的邮件列表上讨论过(请参阅参考资料),但是看起来近期不会得到解决。但是,既然它是开源的,谁会知道以后会怎样呢?
另一个限制是 StatCVS 只支持 CVS。随着 Subversion 正在迅速赢得 CVS 继承人的地位,所以如果 StatCVS
能够两者都支持,那就太棒了。在 StatCVS 的邮件列表上已经有了一些关于这点的讨论,但是 Subversion 修改集的格式看来正是目前的障碍。
挖掘 CVS 储存库来查找使用信息,可能产生大量的数字和图表。但是要认识这些数字的有用性,以及它们能够为特定项目开发提供什么样的深入观察,这些则要取决于您的判断。在脑子里要有这样一些概念,StatCVS
可以提供一些有趣的可视快照,让您了解项目源代码在其生命期间发生的事。
而且,StatCVS 也是开源项目良好运行的一个优秀模型。它的代码整洁、构建过程简单、文档清晰。如果您对于如何做好开源项目有兴趣,那么可以从了解
StatCVS 中学到许多东西。
名字 |
大小 |
下载方法 |
statcvs-download.zip |
563 KB |
|
|