diff options
Diffstat (limited to 'cvs2svn_lib/stats_keeper.py')
-rw-r--r-- | cvs2svn_lib/stats_keeper.py | 189 |
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 + |