1 # (Be in -*- python -*- mode.)
3 # ====================================================================
4 # Copyright (c) 2000-2008 CollabNet. All rights reserved.
6 # This software is licensed as described in the file COPYING, which
7 # you should have received as part of this distribution. The terms
8 # are also available at http://subversion.tigris.org/license-1.html.
9 # If newer versions of this license are posted there, you may use a
10 # newer version instead, at your option.
12 # This software consists of voluntary contributions made by many
13 # individuals. For exact contribution history, see the revision
14 # history and logs, available at http://cvs2svn.tigris.org/.
15 # ====================================================================
17 """This module contains the StatsKeeper class.
19 A StatsKeeper can pickle itself to a STATISTICS_FILE. This module
20 also includes a function to read a StatsKeeper from a STATISTICS_FILE."""
25 from cStringIO
import StringIO
27 from cvs2svn_lib
.cvs_item
import CVSRevision
28 from cvs2svn_lib
.cvs_item
import CVSBranch
29 from cvs2svn_lib
.cvs_item
import CVSTag
34 self
._svn
_rev
_count
= None
35 self
._first
_rev
_date
= 1L<<32
36 self
._last
_rev
_date
= 0
37 self
._pass
_timings
= { }
38 self
._stats
_reflect
_exclude
= False
39 self
.reset_cvs_rev_info()
41 def log_duration_for_pass(self
, duration
, pass_num
, pass_name
):
42 self
._pass
_timings
[pass_num
] = (pass_name
, duration
,)
44 def set_stats_reflect_exclude(self
, value
):
45 self
._stats
_reflect
_exclude
= value
47 def reset_cvs_rev_info(self
):
48 self
._repos
_file
_count
= 0
50 self
._cvs
_revs
_count
= 0
51 self
._cvs
_branches
_count
= 0
52 self
._cvs
_tags
_count
= 0
54 # A set of tag_ids seen:
57 # A set of branch_ids seen:
58 self
._branch
_ids
= set()
60 def record_cvs_file(self
, cvs_file
):
61 self
._repos
_file
_count
+= 1
62 self
._repos
_size
+= cvs_file
.file_size
64 def _record_cvs_rev(self
, cvs_rev
):
65 self
._cvs
_revs
_count
+= 1
67 if cvs_rev
.timestamp
< self
._first
_rev
_date
:
68 self
._first
_rev
_date
= cvs_rev
.timestamp
70 if cvs_rev
.timestamp
> self
._last
_rev
_date
:
71 self
._last
_rev
_date
= cvs_rev
.timestamp
73 def _record_cvs_branch(self
, cvs_branch
):
74 self
._cvs
_branches
_count
+= 1
75 self
._branch
_ids
.add(cvs_branch
.symbol
.id)
77 def _record_cvs_tag(self
, cvs_tag
):
78 self
._cvs
_tags
_count
+= 1
79 self
._tag
_ids
.add(cvs_tag
.symbol
.id)
81 def record_cvs_item(self
, cvs_item
):
82 if isinstance(cvs_item
, CVSRevision
):
83 self
._record
_cvs
_rev
(cvs_item
)
84 elif isinstance(cvs_item
, CVSBranch
):
85 self
._record
_cvs
_branch
(cvs_item
)
86 elif isinstance(cvs_item
, CVSTag
):
87 self
._record
_cvs
_tag
(cvs_item
)
89 raise RuntimeError('Unknown CVSItem type')
91 def set_svn_rev_count(self
, count
):
92 self
._svn
_rev
_count
= count
94 def svn_rev_count(self
):
95 return self
._svn
_rev
_count
97 def __getstate__(self
):
98 state
= self
.__dict
__.copy()
99 # This can get kinda large, so we don't store it:
102 def archive(self
, filename
):
103 f
= open(filename
, 'wb')
104 cPickle
.dump(self
, f
)
110 f
.write('cvs2svn Statistics:\n')
111 f
.write('------------------\n')
112 f
.write('Total CVS Files: %10i\n' % (self
._repos
_file
_count
,))
113 f
.write('Total CVS Revisions: %10i\n' % (self
._cvs
_revs
_count
,))
114 f
.write('Total CVS Branches: %10i\n' % (self
._cvs
_branches
_count
,))
115 f
.write('Total CVS Tags: %10i\n' % (self
._cvs
_tags
_count
,))
116 f
.write('Total Unique Tags: %10i\n' % (len(self
._tag
_ids
),))
117 f
.write('Total Unique Branches: %10i\n' % (len(self
._branch
_ids
),))
118 f
.write('CVS Repos Size in KB: %10i\n' % ((self
._repos
_size
/ 1024),))
120 if self
._svn
_rev
_count
is not None:
121 f
.write('Total SVN Commits: %10i\n' % self
._svn
_rev
_count
)
124 'First Revision Date: %s\n' % (time
.ctime(self
._first
_rev
_date
),)
127 'Last Revision Date: %s\n' % (time
.ctime(self
._last
_rev
_date
),)
129 f
.write('------------------')
131 if not self
._stats
_reflect
_exclude
:
134 '(These are unaltered CVS repository stats and do not\n'
135 ' reflect tags or branches excluded via --exclude)\n'
141 def _get_timing_format(value
):
142 # Output times with up to 3 decimal places:
143 decimals
= max(0, 4 - len('%d' % int(value
)))
144 length
= len(('%%.%df' % decimals
) % value
)
145 return '%%%d.%df' % (length
, decimals
,)
147 def single_pass_timing(self
, pass_num
):
148 (pass_name
, duration
,) = self
._pass
_timings
[pass_num
]
149 format
= self
._get
_timing
_format
(duration
)
150 time_string
= format
% (duration
,)
152 'Time for pass%d (%s): %s seconds.'
153 % (pass_num
, pass_name
, time_string
,)
157 passes
= self
._pass
_timings
.keys()
160 f
.write('Timings (seconds):\n')
161 f
.write('------------------\n')
164 for pass_num
in passes
:
165 (pass_name
, duration
,) = self
._pass
_timings
[pass_num
]
168 format
= self
._get
_timing
_format
(total
)
170 for pass_num
in passes
:
171 (pass_name
, duration
,) = self
._pass
_timings
[pass_num
]
173 (format
+ ' pass%-2d %s\n') % (duration
, pass_num
, pass_name
,)
176 f
.write((format
+ ' total') % total
)
180 def read_stats_keeper(filename
):
181 """Factory function: Return a _StatsKeeper instance.
183 Read the instance from FILENAME as written by StatsKeeper.archive()."""
185 f
= open(filename
, 'rb')
186 retval
= cPickle
.load(f
)