Since, with the addition of cvs2svn_lib, the value of $LastChangedRevision$ is
[cvs2svn.git] / cvs2svn_lib / symbolings_reader.py
blob376cc425adc8a8856d341278677b968ce0319c4c
1 # (Be in -*- python -*- mode.)
3 # ====================================================================
4 # Copyright (c) 2000-2006 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 database facilities used by cvs2svn."""
19 import cPickle
21 from cvs2svn_lib.boolean import *
22 from cvs2svn_lib import config
23 from cvs2svn_lib.context import Ctx
24 from cvs2svn_lib.artifact_manager import artifact_manager
25 from cvs2svn_lib.database import Database
26 from cvs2svn_lib.database import DB_OPEN_READ
27 from cvs2svn_lib.openings_closings import OpeningsClosingsMap
28 from cvs2svn_lib.symbol_filling_guide import SymbolFillingGuide
31 class SymbolingsReader:
32 """Provides an interface to the SYMBOL_OPENINGS_CLOSINGS_SORTED file
33 and the SYMBOL_OFFSETS_DB. Does the heavy lifting of finding and
34 returning the correct opening and closing Subversion revision
35 numbers for a given symbolic name."""
37 def __init__(self):
38 """Opens the SYMBOL_OPENINGS_CLOSINGS_SORTED for reading, and
39 reads the offsets database into memory."""
41 self.symbolings = open(
42 artifact_manager.get_temp_file(
43 config.SYMBOL_OPENINGS_CLOSINGS_SORTED),
44 'r')
45 # The offsets_db is really small, and we need to read and write
46 # from it a fair bit, so suck it into memory
47 offsets_db = file(
48 artifact_manager.get_temp_file(config.SYMBOL_OFFSETS_DB), 'rb')
49 # A map from symbol_id to offset.
50 self.offsets = cPickle.load(offsets_db)
51 offsets_db.close()
53 def filling_guide_for_symbol(self, symbol, svn_revnum):
54 """Given SYMBOL and SVN_REVNUM, return a new SymbolFillingGuide object.
56 SYMBOL is a Symbol instance. Note that if we encounter an opening
57 rev in this fill, but the corresponding closing rev takes place
58 later than SVN_REVNUM, the closing will not be passed to
59 SymbolFillingGuide in this fill (and will be discarded when
60 encountered in a later fill). This is perfectly fine, because we
61 can still do a valid fill without the closing--we always try to
62 fill what we can as soon as we can."""
64 openings_closings_map = OpeningsClosingsMap(symbol)
66 # It's possible to have a branch start with a file that was added
67 # on a branch
68 if symbol.id in self.offsets:
69 # Set our read offset for self.symbolings to the offset for this
70 # symbol:
71 self.symbolings.seek(self.offsets[symbol.id])
73 while True:
74 fpos = self.symbolings.tell()
75 line = self.symbolings.readline().rstrip()
76 if not line:
77 break
78 id, revnum, type, branch_id, cvs_file_id = line.split()
79 id = int(id, 16)
80 cvs_file_id = int(cvs_file_id, 16)
81 cvs_file = Ctx()._cvs_file_db.get_file(cvs_file_id)
82 if branch_id == '*':
83 svn_path = Ctx().project.make_trunk_path(cvs_file.cvs_path)
84 else:
85 branch_id = int(branch_id, 16)
86 svn_path = Ctx().project.make_branch_path(
87 Ctx()._symbol_db.get_name(branch_id), cvs_file.cvs_path)
88 revnum = int(revnum)
89 if revnum > svn_revnum or id != symbol.id:
90 break
91 openings_closings_map.register(svn_path, revnum, type)
93 # get current offset of the read marker and set it to the offset
94 # for the beginning of the line we just read if we used anything
95 # we read.
96 if not openings_closings_map.is_empty():
97 self.offsets[symbol.id] = fpos
99 return SymbolFillingGuide(openings_closings_map)