Subversionを使ってソースコードをバージョン管理しているんですが、これを使って(主に自分用の)自動計測の真似事でも出来ないかな?と思った訳です。で、Subversion APIを使ってみようと思いました。
- 夜でもアッサム: pysvn - Subversion APIをpythonから使う
http://assam-at-night.blogspot.com/2007/10/pysvn-subversion-apipython.html - だら〜り: Subversion用API
http://www.darari.com/2007/11/subversionapi.html
これを見ると、SubversionにアクセスするAPIがあり、Python向けのバインディングとして pysvn があるようですので、これを使って情報を取得してみましょう。
ダウンロード
最初迷ったのが、Subversionの本家ダウンロードとpysvnのダウンロードの、どちらからライブラリをダウンロードした方が良いのか?という点でした。
- subversion: Subversion Packages
http://subversion.tigris.org/project_packages.html - pysvn: Downloads
http://pysvn.tigris.org/project_downloads.html
Subversion本家を見ると「svn-win32-1.5.5_py25.zip
」ってのがあって、コメントに「Python 2.5 bindings for Subversion on Win32.」って書いてあるんですね。
こっちでもOKなのかなぁ?と思って試しにダウンロードして調べてみたら、こっちはセットアップ(setup.pyとか)がありませんでした。
で、pysvnの方は、セットアップが準備されているようですので、そちらを使った方が楽だと思います。
自分は、'py26-pysvn-svn153-1.6.2-1067.exe
'をダウンロード&インストールしました。
(インストールは、ファイルをダブルクリックするだけ)
資料
SubversionのリポジトリをアクセスするAPIの資料としては、以下があるようです。
- pysvn Programmer's Guide
http://pysvn.tigris.org/docs/pysvn_prog_guide.html - pysvn: pysvn - Programmer's reference
http://pysvn.tigris.org/docs/pysvn_prog_ref.html
後は、以下でゲットできるSubversionのCHMファイル中の「第8章 開発者の情報」が良いのかなぁ?と思っています。
- Subversion BookのCHMファイルを公開 - Sarabande
http://sarabande.info/2008/02/11/svnbook-chm/
見る限り、リファレンスを見ながら いじくり回していたら、何とかなるかなぁ?というレベルでした。
それでは、以降で簡単なコードを示して見ます。
ファイルの情報を得る
まず、作業中のファイルの情報を得ましょう。
あるファイルの情報を得るには、'pysvn.Client.info
'メソッドでOKのようです。
#!/bin/env python # -*- encoding: cp932 -*- import pysvn import time client = pysvn.Client() fpath = r"F:\Wacky\test2\Python\20090104.pysvn\test1.py" o = client.info(fpath) for i in o: if i.find("time") >= 0: print i, ":", time.ctime(o[i]) elif i.find("revision") >= 0: print i, ":", o[i].number else: print i,":", o[i]
実行すると、以下のような感じになります。
F:\Wacky\test2\Python\20090104.pysvn>python test3.py is_absent : 0 properties_time : Thu Jan 01 09:00:00 1970 conflict_old : None commit_author : wacky schedule : normal repos : file:///C:/svn/code_sample2 copy_from_url : None is_copied : 0 lock_owner : None copy_from_revision : -1 property_reject_file : None lock_creation_date : 0.0 conflict_work : None kind : file lock_token : None text_time : Sun Jan 11 23:58:35 2009 lock_comment : None is_deleted : 0 uuid : None url : file:///C:/svn/code_sample2/trunk/Python/20090104.pysvn/test1.py checksum : f3501216e850cf2db0b0f3138814ae77 commit_revision : 47 name : test1.py conflict_new : None commit_time : Mon Jan 12 14:24:15 2009 revision : 47
ちなみに、日時(time)の取得時、time.ctimeメソッドを使って浮動小数点数→日時変換しています。
ファイル行数を得る
あるファイルの行数(LOC)を得るには、'pysvn.Client.cat
'メソッドで取得したテキスト文字列から、string.splitlines メソッドを使って改行数をカウントすれば良いでしょう。
#!/bin/env python # -*- encoding: cp932 -*- import pysvn client = pysvn.Client() fpath = r"F:\Wacky\test2\Python\20090104.pysvn\test1.py" txt = client.cat(fpath) print "LOC:", len(txt.splitlines())
実行すると、以下のようになります。
F:\Wacky\test2\Python\20090104.pysvn>python test4.py LOC: 41
ログ情報を得る
過去のチェックインのログを得るには、'pysvn.Client.log
'メソッドで取得できるようです。
#!/bin/env python # -*- encoding: cp932 -*- import pysvn import time client = pysvn.Client() fpath = r"F:\Wacky\test2\Python\20090104.pysvn\test1.py" entry_list = client.log(fpath) print "entry_list count:", len(entry_list) for v in entry_list: print "-----" print "revision:", v["revision"].number print "author:", v["author"] print "date:", time.ctime(v["date"]) print "message:[%s]" % v["message"]
実行すると、以下のようになります。
F:\Wacky\test2\Python\20090104.pysvn>python test5.py entry_list count: 2 ----- revision: 47 author: wacky date: Mon Jan 12 14:24:15 2009 message:[hello python ] ----- revision: 46 author: wacky date: Sun Jan 04 19:34:24 2009 message:[]
リポジトリの全ファイルリスト出力
リポジトリの全ファイルリストを出力するには、'pysvn.Client.root_url_from_path
'メソッドでリポジトリのルートを取得して、'pysvn.Client.ls
'メソッドでファイルリストを得ればOKみたいです。
#!/bin/env python # -*- encoding: cp932 -*- import pysvn client = pysvn.Client() def ls_walk(ary): unification = { 0x2014: 0x2015, # HORIZONTAL BAR 0xFF5E: 0x301C, # WAVE DASH 0x2225: 0x2016, # DOUBLE VERTICAL LINE 0x22EF: 0x2026, # HORIZONTAL ELLIPSIS 0xFF0D: 0x2212, # MINUS SIGN 0xFFE0: 0x00A2, # CENT SIGN 0xFFE1: 0x00A3, # POUND SIGN 0xFFE2: 0x00AC # NOT SIGN } for v in ary: print "name:", v["name"].translate(unification) if v["kind"] == pysvn.node_kind.dir: ls_walk(client.ls(v["name"])) print "list tree" fpath = r"F:\Wacky\test2\Python\20090104.pysvn\test1.py" rpath = client.root_url_from_path(fpath) print rpath entry_list = client.ls(rpath) ls_walk(entry_list)
実行すると、以下のような感じになります。
... name: file:///C:/svn/code_sample2/trunk/VS/20081124.HyperEstraierのバインデ ィングを作る2/test_app2/Program.cs name: file:///C:/svn/code_sample2/trunk/VS/20081124.HyperEstraierのバインデ ィングを作る2/test_app2/Properties name: file:///C:/svn/code_sample2/trunk/VS/20081124.HyperEstraierのバインデ ィングを作る2/test_app2/Properties/AssemblyInfo.cs name: file:///C:/svn/code_sample2/trunk/VS/20081124.HyperEstraierのバインデ ィングを作る2/test_app2/test_app2.csproj
リポジトリのパスを得る時、単にprint表示せずに translate メソッドを使って変換表示しています(「print "name:", v["name"].translate(unification)
」の所)。
これは、unicode文字列からcp932に変換する際の一種のテクニックです。詳しくは、以下をどうぞ。
- UnicodeEncodeError:でハマる - while( life != end ){ do( enjoy ); }
http://d.hatena.ne.jp/hirothin/20080819/1219123920 - Python bite: 文字集合非対応文字の変換 | Inside ASCADE
http://inside.ascade.co.jp/node/44 - くだすれPython(超初心者用) その2
http://pc11.2ch.net/test/read.cgi/tech/1218155094/491
感想
意外と簡単にリポジトリを操作出来たのでビックリしました。
これで情報をグラフ化したら、面白い計測データが取れるかな?
余談ですが、開発における自動計測(metrics)収集を行いたいなら、(周囲が導入に理解があるとか個人で運用実施可能なら)TracとかRedmineを入れてしまった方が現実的だと思います。
商用ならVSTS(TFS), ClearCaseですかね?VSTSは 一度使ってみたいなぁ。CodePlexがTFSで構築されているそうなので、Team Explorer Client入れれば体験可能かなぁ?
(90日評価版はあるけど、空気のように日々使わないと本気で導入しようという意識付けが働かないんですよね)