1
2
3
4
5
6
7
8
9
10 """cvsanalyser CVS History analyser
11 - 直接分析CVS History 记录
12 - 取得统计数据!
13 特别的 203 中的自动执行:
14 - #su -l sinaop
15 - 专门的用户中的 来维护
16 - %crontab -e
17
18 @version: $Id: cvsanalyser.py,v 1.10 2005/01/05 07:13:36 zhouqi Exp $
19 @author: U{Zoom.Quiet<mailto:[email protected]>}
20 @see: U{cvsdelta by Limodou<http://pyrecord.freezope.org/articles/doc2001082801/show>}
21 """
22 import sys,os,string
23 import time,datetime
24 from elementtree import ElementTree
25 from elementtree.ElementTree import Element, SubElement, tostring
26
27 import getopt
28 import ConfigParser
29
30
31
32
33
34 class CvsAnalyser:
35 """主类,集成所有处理
36 """
37
38
39 def __init__(self):
40 """初始化参数
41 - 通过 /var/log/cron 的据错邮件发现目录的严格性
42 - 当前除了.conf 文件,要需要配置cfg 文件的读取路径!
43 """
44 self.cfg = ConfigParser.ConfigParser()
45 try:
46
47 self.cfg.read("/home/zoomq/share/statcvs/cvsanalyser.conf")
48
49
50 self.cvsroot = self.cfg.get('Path','cvsroot')
51 self.cvs = self.cfg.get('Target','cvs').split()
52 self.tarea = int(self.cfg.get('Target','time'))
53 self.viewcvs = self.cfg.get('Target','viewcvs')
54 self.xml = self.cfg.get('Target','xml')
55 self.xmlhead = """<?xml version='1.0' encoding='UTF-8'?>
56 <!-- edited with elementtree (http://effbot.org/zone/element-index.htm) by Zoom.Quiet -->
57 <?xml-stylesheet type='text/xsl' href='historystat.xsl'?>
58 """
59
60
61 self.finder = "find %s -mtime -7 -type f | wc -l | awk '{print $1}'"
62 except:
63 print """config files:\n cvsanalyser.conf
64 not exist or bad!!!
65 please check it....and try again!
66 """
67 return
68 self.report = {}
69 self.stime = (datetime.date.today()-datetime.timedelta(self.tarea)).isoformat()
70 self.etime = datetime.date.today().isoformat()
71
72
73
74 def __repr__(self):
75 """类自述定义,记录手册等等信息
76 """
77 return """
78 使用手册:
79 设置 cvsanalyser.conf 指定对应的 CVS root 的目录,和输出的XML文件,以及文件的编码约定
80 cvsanalyser.py 将自动追查所有CVS模块的更新信息
81 """
82
83
84
85 def chkFiles(self):
86 """逐一搜索有效目录获得History 文件列表
87 - 好象没有必要? CVSROOT 目录是每个库的唯一!
88 """
89 files = []
90 for key in self.cvs:
91 files.append(key)
92 return files
93
94
95
96 def analyseAll(self):
97 """逐一处理所有模块
98 - 使用Python 内建结构先建立数据映射
99 - self.report{}:
100 - cvs 仓库名称:{}
101 - commits: ; files: ;
102 - mods:{}
103 - 模块名:{}
104 - commits: ; files: ;
105 - viewcvs:{} 链接到 ViewCVS 各文件的 下载,查看
106 # 本地单一文件测试
107 his = open("history","r")
108 hislis = his.readlines()
109 print "-------------"
110 print len(hislis)
111 cvs="scm"
112 self.report[cvs]=self.analyseDate(hislis)
113 print "==============="
114 #print self.report
115 self.put2xml()
116 return
117 """
118 cvsli = self.chkFiles()
119 for cvs in cvsli:
120
121 his = open(self.cvsroot+cvs+"/CVSROOT/history","r")
122 hislis = his.readlines()
123 print "-------------"
124 print len(hislis)
125 self.report[cvs]=self.analyseDate(hislis)
126
127
128 """成功的数据实例
129 {'scm': {'files': 9, 'commits': 20
130 , 'mods': {'scm': {'files': 9, 'commits': 20
131 ,'viewcvs': {
132 'CVSanalyser.leo': ('M', '41d50d27', 'zhouqi', 'scm/statcvs', '1.3',
133 'CVSanalyser.leo')
134 , 'weeklystat.py': ('M', '41d50d27', 'zhouqi', 'scm/statcvs',
135 '1.4', 'weeklystat.py')
136 , 'weeklystat.xsl': ('M', '41d4ec4c', 'zhouqi', 'scm/sta
137 tcvs', '1.3', 'weeklystat.xsl')
138 , 'cvsanalyser.conf': ('M', '41d50d27', 'zhouqi',
139 'scm/statcvs', '1.2', 'cvsanalyser.conf')
140 , 'statcvs.sh.py': ('M', '41d4ec4c', '
141 zhouqi', 'scm/statcvs', '1.6', 'statcvs.sh.py')
142 , 'weeklystat.xml': ('A', '41d0f6
143 92', 'zhouqi', 'scm/statcvs', '1.1', 'weeklystat.xml')
144 , 'style.css': ('A', '41d0
145 f7b3', 'zhouqi', 'scm/statcvs', '1.1', 'style.css')
146 , 'cvsanalyser.py': ('M', '41
147 d50d27', 'zhouqi', 'scm/statcvs', '1.2', 'cvsanalyser.py')
148 , 'sinaeye.ico': ('A',
149 '41d0f7b3', 'zhouqi', 'scm/statcvs', '1.1', 'sinaeye.ico')
150 }
151 }
152 }
153 }}
154 """
155
156
157
158
159
160
161 def analyseDate(self,historic):
162 """根据日期进行统计
163 - 是每个CVS 的针对性分析
164 """
165 rep = []
166
167 for line in historic:
168 info = self.analyseLine(line)
169
170 sdate=time.strftime('%Y-%m-%d', time.localtime(int(info[1], 16)))
171 if(sdate>=self.stime):
172 if(info[0]in"AMT"):
173
174 rep.append(info)
175
176
177 print "<<history in date right"
178 print len(rep)
179 return self.analyseAct(rep)
180
181
182 def analyseAct(self,list):
183 """根据行为分析
184 - 关注 M|A 作为更新
185 - T 作为版本标记行为
186 - 统计不同模块中的更新情况!
187 - 变更次数
188 - 文件数
189 - 统计整个库的修改文件数
190 """
191 rep = {}
192 rep["commits"]=0
193 rep["files"]=0
194 modict={}
195 fdict={}
196 for line in list:
197 if(line[0] in "AMT"):
198 rep["commits"]+=1
199
200
201 moudle = line[3].split("/")[0]
202 if(moudle in modict):
203 modict[moudle]["commits"]+=1
204 fdict=self.analyseFile(fdict,moudle,line)
205 else:
206
207 print "moudle:::"+moudle
208 modict[moudle]={}
209 modict[moudle]["commits"]=1
210 modict[moudle]["files"]=1
211
212 fdict=self.analyseFile(fdict,moudle,line)
213 else:
214 pass
215 rep["mods"]=modict
216 for mod in rep["mods"]:
217
218 rep["mods"][mod]["viewcvs"]=fdict[mod]
219 rep["mods"][mod]["files"]=len(fdict[mod])
220
221 rep["files"]+=rep["mods"][mod]["files"]
222
223
224 """"
225 for m in fdict:
226 print len(fdict[m])
227 for f in fdict[m]:
228 print fdict[m][f]
229 """
230 return rep
231
232
233
234
235 def analyseFile(self,fdict,mod,hisline):
236 """使用专门的容器,累计分析文件信息
237 - fdict 上级的文件统计容器
238 - 当前的模块信息
239 - 当前的文件History 行信息
240 """
241 file = hisline[5]
242 if mod in fdict:
243 if file in fdict[mod]:
244 fdict[mod][file]=hisline
245 else:
246 fdict[mod][file]=hisline
247 else:
248
249 fdict[mod]={}
250 fdict[mod][file]=hisline
251
252 return fdict
253
254
255
256 def viewcvsFiles(self,hisline):
257 """根据行为列表组合 ViewCVS 链接
258 - 在线观看
259 - 下载
260 仅仅在输出XML等等其它文件时调用
261 """
262 url=""
263
264
265 return url
266
267
268
269
270
271 def analyseLine(self,line):
272 """分析日志行,分解得到信息元组
273 - 操作类型
274 - 操作日期
275 - 提交人
276 - 模块
277 - 版本
278 - 文件名
279 """
280 fields=line.split('|')
281 return (fields[0][0], fields[0][1:], fields[1],fields[3], fields[4], fields[5][:-1])
282
283
284 def put2xml(self):
285 """汇出数据为XML文件!
286 - 使用轻型XML操作库 Elements and Element Trees
287 - @see: U{Elements<http://effbot.org/zone/element.htm>}
288 """
289 re = self.report
290 zday = time.strftime("%Y-%m-%d",time.localtime(time.time()))
291 print zday
292 ztime = time.strftime("%X",time.localtime(time.time()))
293
294 tree = ElementTree.parse(self.xml).getroot()
295 week = tree.findall("week")
296
297 done = 0
298 for node in week:
299 if(zday==node.attrib["date"]):
300
301 done = 1
302 tree.remove(node)
303 break
304
305 if(1==done):
306 print "recorded xml! new upgrade it!"
307 else:
308 print "need recording...will exp. as xml file"
309 neweek = Element("week")
310 neweek.set("date", zday)
311 neweek.set("time", ztime)
312 statcount = {'files':0
313 ,'commits':0
314 }
315 for proj in re:
316
317
318 newcvs = SubElement(neweek, "cvs")
319 newcvs.set("name", proj)
320 newcvs.set("files", str(re[proj]["files"]))
321 newcvs.set("commits", str(re[proj]["commits"]))
322 statcount["files"]+=re[proj]["files"]
323 statcount["commits"]+=re[proj]["commits"]
324 for mod in re[proj]["mods"]:
325 module = SubElement(newcvs, "module")
326 module.set("name", mod)
327 module.set("files", str(re[proj]["mods"][mod]["files"]))
328 module.set("commits", str(re[proj]["mods"][mod]["commits"]))
329 for view in re[proj]["mods"][mod]["viewcvs"]:
330 file = Element("file")
331
332 his = re[proj]["mods"][mod]["viewcvs"][view]
333
334 file.set("name", view)
335
336 file.set("view", self.viewcvs+his[3]+"/"+his[5]+"?root="+proj+"&rev="+his[4]+"&view=auto")
337 file.set("load", self.viewcvs+"*checkout*/"+his[3]+"/"+his[5]+"?rev="+his[4])
338 module.append(file)
339
340 neweek.set("commits", str(statcount["commits"]))
341 neweek.set("files", str(statcount["files"]))
342 tree.append(neweek)
343
344 code = tostring(tree)
345
346 print self.xml
347 open(self.xml,"w").write(self.xmlhead+code)
348
349
350
351
352
353
354
355 if __name__ == '__main__':
356 """基本运行模式
357 """
358 week = CvsAnalyser()
359 week.analyseAll()
360 week.put2xml()
361
362
363