簡介: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:[email protected]:2401/usr/cvs/jikes
CVS password: [ Type "anoncvs" here ]
[tom@hal tmp]$ cvs - d:pserver:[email protected]:/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:[email protected]:/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 所示,圖中顯示了每個參與者是添加了文件 ,還是修改了文件:
“代碼行”僅僅是數字
代碼行計數有多重要呢?時至今日,只有項目中的人才能說得清。請考慮以 下這些情況。只要加入一個很大的格式變化,使所有的 for和 while循環看起來 更整潔,就很容易增加代碼的行數。項目中可能有大量自動生成的文件(例如, 語言語法分析程序),而這些文件都是由一個人簽入的。項目可能是一個圍繞算 術庫構建的應用程序,雖然很小,但是非常復雜;UI 代碼可能頻繁變化,但庫 的代碼只會偶爾變化。圖表雖然漂亮,但是不一定能夠表現出來誰做的工作最多 。它僅僅是原始數據的圖形化顯示,需要人來诠釋它。
圖 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,就可以看到這個 報告。
關於 Maven?
對於 Maven 用戶來說,會高興地聽到 StatCVS-XML 有一個 Maven 插件,該 插件是 StatCVS 的擴展。這個插件是可定制的;它甚至提供了一些好方法,可 以將 CVS 用戶名映射到真實的用戶名,這會使報告看起來更漂亮。有關的更多 信息,請參閱 參考資料。
為多個項目生成報告
前面已經看到了如何在一個 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 中學到許多東西。
下載:http://www.ibm.com/developerworks/cn/java/j-statcvs/