# (Be in -*- python -*- mode.) # # ==================================================================== # Copyright (c) 2000-2006 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 database facilities used by cvs2svn.""" import cPickle from cvs2svn_lib.boolean import * from cvs2svn_lib import config from cvs2svn_lib.context import Ctx from cvs2svn_lib.artifact_manager import artifact_manager from cvs2svn_lib.database import Database from cvs2svn_lib.database import DB_OPEN_READ from cvs2svn_lib.openings_closings import OpeningsClosingsMap from cvs2svn_lib.symbol_filling_guide import SymbolFillingGuide class SymbolingsReader: """Provides an interface to 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.""" 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. self.offsets = cPickle.load(offsets_db) offsets_db.close() def filling_guide_for_symbol(self, symbol, svn_revnum): """Given SYMBOL and SVN_REVNUM, return a new SymbolFillingGuide object. SYMBOL is a TypedSymbol instance. Note that if we encounter an opening rev in this fill, but the corresponding closing rev takes place later than SVN_REVNUM, the closing will not be passed to SymbolFillingGuide in this fill (and will be discarded when encountered in a later fill). This is perfectly fine, because we can still do a valid fill without the closing--we always try to fill what we can as soon as we can.""" openings_closings_map = OpeningsClosingsMap(symbol) # It's possible to have a branch start with a file that was added # on a branch 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: fpos = self.symbolings.tell() line = self.symbolings.readline().rstrip() if not line: break id, revnum, type, branch_id, cvs_file_id = line.split() id = int(id, 16) cvs_file_id = int(cvs_file_id, 16) cvs_file = Ctx()._cvs_file_db.get_file(cvs_file_id) if branch_id == '*': svn_path = cvs_file.project.make_trunk_path(cvs_file.cvs_path) else: branch_id = int(branch_id, 16) svn_path = cvs_file.project.make_branch_path( Ctx()._symbol_db.get_symbol(branch_id), cvs_file.cvs_path) revnum = int(revnum) if revnum > svn_revnum or id != symbol.id: break openings_closings_map.register(svn_path, revnum, type) # get current offset of the read marker and set it to the offset # for the beginning of the line we just read if we used anything # we read. if not openings_closings_map.is_empty(): self.offsets[symbol.id] = fpos return SymbolFillingGuide(openings_closings_map)