Subversionで単純なロジカルカップリングを調べる
■目的
Subversionで単純なロジカルカップリングを調べます。
ロジカルカップリングとはファイルの更新履歴から同時に更新される頻度の高いファイルのパターンを分析します。
これにより、あるファイルを修正した場合に発生する影響度を分析します。

同時変更の抽出には以下の研究のようにファイルの変更内容まで踏み込む場合もあります。
ファイルの同時変更パターンと変更差分の分析による 論理的結合関係の自動抽出

しかし、今回は単純にファイル同士の更新頻度のみをみています。




■pysvn
pysvnはSubversionをPythonで使用するためのライブラリです。
このライブラリを使用することでリポジトリのログを取得しています。

DownLoad:
http://pysvn.tigris.org/project_downloads.html

今回はWindows の Python2.7とpy27-pysvn-svn181-1.7.8-1546.exeのインストーラにて動作確認しました。
もし、ssh+svnで動作させる必要がある場合は、svnをコマンドラインで使う場合と同様に、Subversionのconfigでtunnelsの設定を行なう必要があります。
詳細は下記のページが参考になりました。


cimada-ism 「コマンドラインからのsvn+ssh」


■CSVで出力する
以下のコードはSubversionのリポジトリを指定して、そのロジカルカップリングをCSVファイルとして出力するためのスクリプトです。


# -*- coding: utf-8 -*-
# このスクリプトではpysvnを用いて、指定のサブバージョンのリポジトリで
# あるファイルを変更したときに、同時に変更されるファイルを調べます。
#
# pysvn is download from
# http://pysvn.tigris.org/project_downloads.html
# Windows の Python2.7と下記のインストーラにて動作確認。
# py27-pysvn-svn181-1.7.8-1546.exe
import pysvn
import time
import sys
from collections import defaultdict

class FilePair:
def __init__(self,path1,path2):
self.path1 = path1
self.path2 = path2
self.count = 0
self.reliability1 =0
self.reliability2 =0


class SvnRepController:
def __init__(self,url_or_path,user,passwd):
self.client = pysvn.Client()
self.url_or_path = url_or_path
self.user = user
self.passwd = passwd
self.client.callback_get_login = self.get_login

def get_login(self, realm, username, may_save):
return True, self.user,self.passwd, False

def log(self):
return self.client.log(self.url_or_path, discover_changed_paths=True)

def getSimpleLogicalCoupling(self):
files = defaultdict(int)
ret = defaultdict(FilePair)
logs = self.log()
for log in logs:
for i in range(0,len(log.changed_paths)-1):
path1 = log.changed_paths[i]
if path1.action != "M":
# 変更以外の場合は無視
continue

files[path1.path] += 1

for j in range(i+1,len(log.changed_paths)-1):
path2 = log.changed_paths[j]
if path2.action != "M":
# 変更以外の場合は無視
continue
if path1.path == path2.path:
continue

key = "%s %s" % (path1.path , path2.path)
if( ret.has_key(key) == False ):
key = "%s %s" % (path2.path , path1.path)
if( ret.has_key(key) == False ):
ret[key] = FilePair(path1.path,path2.path)
ret[key].count += 1

for k,v in ret.items():
v.reliability1 = float(v.count) / files[v.path1]
v.reliability2 = float(v.count) / files[v.path2]

return ret



if __name__ == '__main__':
argvs = sys.argv
argc = len(argvs)
if(argc != 6):
sys.stderr.write( 'Usage:\n python %s url_or_path user pass min_count min_reliability' % argvs[0] )
quit()
url_or_path = argvs[1]
user = argvs[2]
passwd = argvs[3]
min_count = argvs[4]
min_reliablility = float(argvs[5])
client = SvnRepController(url_or_path,user,passwd)
list = client.getSimpleLogicalCoupling()
print '"Path A","Path B","Count","Count/count of A","Count/count of B","reliability"'
for k,v in sorted(list.items(), key=lambda x:x[1].count, reverse=True):
if (v.reliability1 > float(min_reliablility) or v.reliability2 > float(min_reliablility)) and v.count > int(min_count):
print '"%s","%s","%d","%f","%f","%f"' % (v.path1,v.path2,v.count,v.reliability1,v.reliability2,v.reliability1 if v.reliability1>v.reliability2 else v.reliability2)


以下のように使用します。

python svnSimpleLogicalCoupling.py http://127.0.0.1/svn/SampleProject admin admin 5 0.8 > out.csv

これはSampleProjectのリポジトリに対してUser:admin,パスワードadminでログインをして、発生頻度が5回以上で、該当ファイルを変更する場合、最低、80%の確率で更新されているファイルの組み合わせを取得しています。

■画像で表現する
GraphVizを使用することでロジカルカップリングを図で表現することもできます。
PythonからGraphVizを使用するにはpydotを用います。
pydotについては下記のページを参考にしてください。
テキストを類似度毎に階層的クラスタリングで分類してみた

実際のスクリプトは下記にあります。
svnSimpleLogicalCouplingGraph.py
b0232065_20531472.png

以下のように線の太さで関係の強さを表します。
[PR]
by mima_ita | 2013-11-10 20:53 | subversion
<< VisualBasic6.0の... Trac0.12系にニコニコカ... >>


検索
カテゴリ
最新の記事
.NET4.5におけるasy..
at 2014-07-02 00:46
.NETでTwitterを検..
at 2014-06-29 00:49
Redmineのプラグインで..
at 2014-06-28 03:29
IO.popenのwrite..
at 2014-06-28 03:25
RedmineのWikiでU..
at 2014-06-28 03:16
以前の記事
最新のトラックバック
その他のジャンル
ブログパーツ