/usr/lib/python2.7/dist-packages/cvs2svn_lib/openings_closings.py is in cvs2svn 2.4.0-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | # (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 classes to keep track of symbol openings/closings."""
import cPickle
from cvs2svn_lib import config
from cvs2svn_lib.common import InternalError
from cvs2svn_lib.artifact_manager import artifact_manager
from cvs2svn_lib.svn_revision_range import SVNRevisionRange
# Constants used in SYMBOL_OPENINGS_CLOSINGS
OPENING = 'O'
CLOSING = 'C'
class SymbolingsLogger:
"""Manage the file that contains lines for symbol openings and closings.
This data will later be used to determine valid SVNRevision ranges
from which a file can be copied when creating a branch or tag in
Subversion. Do this by finding 'Openings' and 'Closings' for each
file copied onto a branch or tag.
An 'Opening' is the beginning of the lifetime of the source
(CVSRevision or CVSBranch) from which a given CVSSymbol sprouts.
The 'Closing' is the SVN revision when the source is deleted or
overwritten.
For example, on file 'foo.c', branch BEE has branch number 1.2.2 and
obviously sprouts from revision 1.2. Therefore, the SVN revision
when 1.2 is committed is the opening for BEE on path 'foo.c', and
the SVN revision when 1.3 is committed is the closing for BEE on
path 'foo.c'. Note that there may be many revisions chronologically
between 1.2 and 1.3, for example, revisions on branches of 'foo.c',
perhaps even including on branch BEE itself. But 1.3 is the next
revision *on the same line* as 1.2, that is why it is the closing
revision for those symbolic names of which 1.2 is the opening.
The reason for doing all this hullabaloo is (1) to determine what
range of SVN revision numbers can be used as the source of a copy of
a particular file onto a branch/tag, and (2) to minimize the number
of copies and deletes per creation by choosing source SVN revision
numbers that can be used for as many files as possible.
For example, revisions 1.2 and 1.3 of foo.c might correspond to
revisions 17 and 30 in Subversion. That means that when creating
branch BEE, foo.c has to be copied from a Subversion revision number
in the range 17 <= revnum < 30. Now if there were another file,
'bar.c', in the same directory, and 'bar.c's opening and closing for
BEE correspond to revisions 24 and 39 in Subversion, then we can
kill two birds with one stone by copying the whole directory from
somewhere in the range 24 <= revnum < 30."""
def __init__(self):
self.symbolings = open(
artifact_manager.get_temp_file(config.SYMBOL_OPENINGS_CLOSINGS), 'w')
def log_revision(self, cvs_rev, svn_revnum):
"""Log any openings and closings found in CVS_REV."""
for (symbol_id, cvs_symbol_id,) in cvs_rev.opened_symbols:
self._log_opening(symbol_id, cvs_symbol_id, svn_revnum)
for (symbol_id, cvs_symbol_id) in cvs_rev.closed_symbols:
self._log_closing(symbol_id, cvs_symbol_id, svn_revnum)
def log_branch_revision(self, cvs_branch, svn_revnum):
"""Log any openings and closings found in CVS_BRANCH."""
for (symbol_id, cvs_symbol_id,) in cvs_branch.opened_symbols:
self._log_opening(symbol_id, cvs_symbol_id, svn_revnum)
def _log(self, symbol_id, cvs_symbol_id, svn_revnum, type):
"""Log an opening or closing to self.symbolings.
Write out a single line to the symbol_openings_closings file
representing that SVN_REVNUM is either the opening or closing
(TYPE) of CVS_SYMBOL_ID for SYMBOL_ID.
TYPE should be one of the following constants: OPENING or CLOSING."""
self.symbolings.write(
'%x %d %s %x\n' % (symbol_id, svn_revnum, type, cvs_symbol_id)
)
def _log_opening(self, symbol_id, cvs_symbol_id, svn_revnum):
"""Log an opening to self.symbolings.
See _log() for more information."""
self._log(symbol_id, cvs_symbol_id, svn_revnum, OPENING)
def _log_closing(self, symbol_id, cvs_symbol_id, svn_revnum):
"""Log a closing to self.symbolings.
See _log() for more information."""
self._log(symbol_id, cvs_symbol_id, svn_revnum, CLOSING)
def close(self):
self.symbolings.close()
self.symbolings = None
class SymbolingsReader:
"""Provides an interface to retrieve symbol openings and closings.
This class accesses the SYMBOL_OPENINGS_CLOSINGS_SORTED file and the
SYMBOL_OFFSETS_DB. Does the heavy lifting of finding and returning
the correct opening and closing Subversion revision numbers for a
given symbolic name and SVN revision number range."""
def __init__(self):
"""Opens the SYMBOL_OPENINGS_CLOSINGS_SORTED for reading, and
reads the offsets database into memory."""
self.symbolings = open(
artifact_manager.get_temp_file(
config.SYMBOL_OPENINGS_CLOSINGS_SORTED),
'r')
# The offsets_db is really small, and we need to read and write
# from it a fair bit, so suck it into memory
offsets_db = file(
artifact_manager.get_temp_file(config.SYMBOL_OFFSETS_DB), 'rb')
# A map from symbol_id to offset. The values of this map are
# incremented as the openings and closings for a symbol are
# consumed.
self.offsets = cPickle.load(offsets_db)
offsets_db.close()
def close(self):
self.symbolings.close()
del self.symbolings
del self.offsets
def _generate_lines(self, symbol):
"""Generate the lines for SYMBOL.
SYMBOL is a TypedSymbol instance. Yield the tuple (revnum, type,
cvs_symbol_id) for all openings and closings for SYMBOL."""
if symbol.id in self.offsets:
# Set our read offset for self.symbolings to the offset for this
# symbol:
self.symbolings.seek(self.offsets[symbol.id])
while True:
line = self.symbolings.readline().rstrip()
if not line:
break
(id, revnum, type, cvs_symbol_id) = line.split()
id = int(id, 16)
revnum = int(revnum)
if id != symbol.id:
break
cvs_symbol_id = int(cvs_symbol_id, 16)
yield (revnum, type, cvs_symbol_id)
def get_range_map(self, svn_symbol_commit):
"""Return the ranges of all CVSSymbols in SVN_SYMBOL_COMMIT.
Return a map { CVSSymbol : SVNRevisionRange }."""
# A map { cvs_symbol_id : CVSSymbol }:
cvs_symbol_map = {}
for cvs_symbol in svn_symbol_commit.get_cvs_items():
cvs_symbol_map[cvs_symbol.id] = cvs_symbol
range_map = {}
for (revnum, type, cvs_symbol_id) \
in self._generate_lines(svn_symbol_commit.symbol):
cvs_symbol = cvs_symbol_map.get(cvs_symbol_id)
if cvs_symbol is None:
# This CVSSymbol is not part of SVN_SYMBOL_COMMIT.
continue
range = range_map.get(cvs_symbol)
if type == OPENING:
if range is not None:
raise InternalError(
'Multiple openings logged for %r' % (cvs_symbol,)
)
range_map[cvs_symbol] = SVNRevisionRange(
cvs_symbol.source_lod, revnum
)
else:
if range is None:
raise InternalError(
'Closing precedes opening for %r' % (cvs_symbol,)
)
if range.closing_revnum is not None:
raise InternalError(
'Multiple closings logged for %r' % (cvs_symbol,)
)
range.add_closing(revnum)
# Make sure that all CVSSymbols are accounted for, and adjust the
# closings to be not later than svn_symbol_commit.revnum.
for cvs_symbol in cvs_symbol_map.itervalues():
try:
range = range_map[cvs_symbol]
except KeyError:
raise InternalError('No opening for %s' % (cvs_symbol,))
if range.opening_revnum >= svn_symbol_commit.revnum:
raise InternalError(
'Opening in r%d not ready for %s in r%d'
% (range.opening_revnum, cvs_symbol, svn_symbol_commit.revnum,)
)
if range.closing_revnum is not None \
and range.closing_revnum > svn_symbol_commit.revnum:
range.closing_revnum = None
return range_map
|