aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'cvs2svn_lib/stats_keeper.py')
-rw-r--r--cvs2svn_lib/stats_keeper.py189
1 files changed, 189 insertions, 0 deletions
diff --git a/cvs2svn_lib/stats_keeper.py b/cvs2svn_lib/stats_keeper.py
new file mode 100644
index 0000000..1a82540
--- /dev/null
+++ b/cvs2svn_lib/stats_keeper.py
@@ -0,0 +1,189 @@
+# (Be in -*- python -*- mode.)
+#
+# ====================================================================
+# Copyright (c) 2000-2008 CollabNet. All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://subversion.tigris.org/license-1.html.
+# If newer versions of this license are posted there, you may use a
+# newer version instead, at your option.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For exact contribution history, see the revision
+# history and logs, available at http://cvs2svn.tigris.org/.
+# ====================================================================
+
+"""This module contains the StatsKeeper class.
+
+A StatsKeeper can pickle itself to a STATISTICS_FILE. This module
+also includes a function to read a StatsKeeper from a STATISTICS_FILE."""
+
+
+import time
+import cPickle
+from cStringIO import StringIO
+
+from cvs2svn_lib.cvs_item import CVSRevision
+from cvs2svn_lib.cvs_item import CVSBranch
+from cvs2svn_lib.cvs_item import CVSTag
+
+
+class StatsKeeper:
+ def __init__(self):
+ self._svn_rev_count = None
+ self._first_rev_date = 1L<<32
+ self._last_rev_date = 0
+ self._pass_timings = { }
+ self._stats_reflect_exclude = False
+ self.reset_cvs_rev_info()
+
+ def log_duration_for_pass(self, duration, pass_num, pass_name):
+ self._pass_timings[pass_num] = (pass_name, duration,)
+
+ def set_stats_reflect_exclude(self, value):
+ self._stats_reflect_exclude = value
+
+ def reset_cvs_rev_info(self):
+ self._repos_file_count = 0
+ self._repos_size = 0
+ self._cvs_revs_count = 0
+ self._cvs_branches_count = 0
+ self._cvs_tags_count = 0
+
+ # A set of tag_ids seen:
+ self._tag_ids = set()
+
+ # A set of branch_ids seen:
+ self._branch_ids = set()
+
+ def record_cvs_file(self, cvs_file):
+ self._repos_file_count += 1
+ self._repos_size += cvs_file.file_size
+
+ def _record_cvs_rev(self, cvs_rev):
+ self._cvs_revs_count += 1
+
+ if cvs_rev.timestamp < self._first_rev_date:
+ self._first_rev_date = cvs_rev.timestamp
+
+ if cvs_rev.timestamp > self._last_rev_date:
+ self._last_rev_date = cvs_rev.timestamp
+
+ def _record_cvs_branch(self, cvs_branch):
+ self._cvs_branches_count += 1
+ self._branch_ids.add(cvs_branch.symbol.id)
+
+ def _record_cvs_tag(self, cvs_tag):
+ self._cvs_tags_count += 1
+ self._tag_ids.add(cvs_tag.symbol.id)
+
+ def record_cvs_item(self, cvs_item):
+ if isinstance(cvs_item, CVSRevision):
+ self._record_cvs_rev(cvs_item)
+ elif isinstance(cvs_item, CVSBranch):
+ self._record_cvs_branch(cvs_item)
+ elif isinstance(cvs_item, CVSTag):
+ self._record_cvs_tag(cvs_item)
+ else:
+ raise RuntimeError('Unknown CVSItem type')
+
+ def set_svn_rev_count(self, count):
+ self._svn_rev_count = count
+
+ def svn_rev_count(self):
+ return self._svn_rev_count
+
+ def __getstate__(self):
+ state = self.__dict__.copy()
+ # This can get kinda large, so we don't store it:
+ return state
+
+ def archive(self, filename):
+ f = open(filename, 'wb')
+ cPickle.dump(self, f)
+ f.close()
+
+ def __str__(self):
+ f = StringIO()
+ f.write('\n')
+ f.write('cvs2svn Statistics:\n')
+ f.write('------------------\n')
+ f.write('Total CVS Files: %10i\n' % (self._repos_file_count,))
+ f.write('Total CVS Revisions: %10i\n' % (self._cvs_revs_count,))
+ f.write('Total CVS Branches: %10i\n' % (self._cvs_branches_count,))
+ f.write('Total CVS Tags: %10i\n' % (self._cvs_tags_count,))
+ f.write('Total Unique Tags: %10i\n' % (len(self._tag_ids),))
+ f.write('Total Unique Branches: %10i\n' % (len(self._branch_ids),))
+ f.write('CVS Repos Size in KB: %10i\n' % ((self._repos_size / 1024),))
+
+ if self._svn_rev_count is not None:
+ f.write('Total SVN Commits: %10i\n' % self._svn_rev_count)
+
+ f.write(
+ 'First Revision Date: %s\n' % (time.ctime(self._first_rev_date),)
+ )
+ f.write(
+ 'Last Revision Date: %s\n' % (time.ctime(self._last_rev_date),)
+ )
+ f.write('------------------')
+
+ if not self._stats_reflect_exclude:
+ f.write(
+ '\n'
+ '(These are unaltered CVS repository stats and do not\n'
+ ' reflect tags or branches excluded via --exclude)\n'
+ )
+
+ return f.getvalue()
+
+ @staticmethod
+ def _get_timing_format(value):
+ # Output times with up to 3 decimal places:
+ decimals = max(0, 4 - len('%d' % int(value)))
+ length = len(('%%.%df' % decimals) % value)
+ return '%%%d.%df' % (length, decimals,)
+
+ def single_pass_timing(self, pass_num):
+ (pass_name, duration,) = self._pass_timings[pass_num]
+ format = self._get_timing_format(duration)
+ time_string = format % (duration,)
+ return (
+ 'Time for pass%d (%s): %s seconds.'
+ % (pass_num, pass_name, time_string,)
+ )
+
+ def timings(self):
+ passes = self._pass_timings.keys()
+ passes.sort()
+ f = StringIO()
+ f.write('Timings (seconds):\n')
+ f.write('------------------\n')
+
+ total = 0.0
+ for pass_num in passes:
+ (pass_name, duration,) = self._pass_timings[pass_num]
+ total += duration
+
+ format = self._get_timing_format(total)
+
+ for pass_num in passes:
+ (pass_name, duration,) = self._pass_timings[pass_num]
+ f.write(
+ (format + ' pass%-2d %s\n') % (duration, pass_num, pass_name,)
+ )
+
+ f.write((format + ' total') % total)
+ return f.getvalue()
+
+
+def read_stats_keeper(filename):
+ """Factory function: Return a _StatsKeeper instance.
+
+ Read the instance from FILENAME as written by StatsKeeper.archive()."""
+
+ f = open(filename, 'rb')
+ retval = cPickle.load(f)
+ f.close()
+ return retval
+