UML软件工程组织

 

 

StatCVS 提供了对 CVS 储存库活动的深入观察
 
作者:Tom Copeland 来源:IBM
 
本文内容包括:
StatCVS 是一个创建并发版本系统(Concurrent Versions System -CVS)储存库活动图表的方便工具。在本文中,开发人员 Tom Copeland 将解释如何安装、运行 StatCVS,概述生成的报告,然后还将介绍如何为多个储存库生成报告,StatCVS 的内幕及限制等多项内容。

如果要接手一个已经运行了好几年的软件项目,那么怎样才能得到对项目开发历史的认识呢?最好的方法可能就是与曾经参与该项目的开发人员对话,但是这说起来容易,做起来却很困难。原有的开发人员通常都已转到了其他项目中,而且要找到他们也很难。您可以查看释出频率(release frequency),尽管这可能受非技术性的强制规定控制(有时可能只是出于“我们要在本财政年度末做一个发布”的理由)。您可以查看 bug 和特性请求跟踪器,还可以在开放和关闭的 bug 讨论中挖掘信息。或者可以直接进入源代码历史记录,用 StatCVS 这样的工具查看曾做过哪些记录,这些记录是谁修改的。我将 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

为了演示 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 主报告页面
Jikes 的 StatCVS 主报告页面

可以看到可用报告的分类:关于代码作者的一些统计数据、查看提交日志、代码段的行,以及关于文件和目录大小的一些统计。

代码行

代码行图表如清单 2 所示,它可能非常有趣:

图 2. Jikes 一段时间内的代码行数
 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. 修改代码
添加代码 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 的代码,请从 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

参考资料

 

 

组织简介 | 联系我们 |   Copyright 2002 ®  UML软件工程组织 京ICP备10020922号

京公海网安备110108001071号