aboutsummaryrefslogtreecommitdiff
blob: 1a82540732d967db5f5b39a625ddff989b01b854 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
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