From 6d541ff88be902b935a67a248e7178825992c10a Mon Sep 17 00:00:00 2001 From: mhagger Date: Sun, 26 Sep 2010 10:25:37 +0000 Subject: [PATCH] Move the RCS keyword expanding/collapsing code to a separate module. git-svn-id: http://cvs2svn.tigris.org/svn/cvs2svn/trunk@5284 be7e6eca-30d4-0310-a8e5-ac0d63af7087 --- cvs2svn_lib/checkout_internal.py | 95 ++--------------------------- cvs2svn_lib/keyword_expander.py | 128 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 91 deletions(-) create mode 100644 cvs2svn_lib/keyword_expander.py diff --git a/cvs2svn_lib/checkout_internal.py b/cvs2svn_lib/checkout_internal.py index abd3202e..ffae6280 100644 --- a/cvs2svn_lib/checkout_internal.py +++ b/cvs2svn_lib/checkout_internal.py @@ -76,9 +76,6 @@ recursively. When a TextRecord is deleted at this stage, its deltatext is also deleted from the delta database.""" -import re -import time - from cvs2svn_lib import config from cvs2svn_lib.common import DB_OPEN_NEW from cvs2svn_lib.common import DB_OPEN_READ @@ -95,6 +92,8 @@ from cvs2svn_lib.database import Database from cvs2svn_lib.database import IndexedDatabase from cvs2svn_lib.rcs_stream import RCSStream from cvs2svn_lib.rcs_stream import MalformedDeltaException +from cvs2svn_lib.keyword_expander import expand_keywords +from cvs2svn_lib.keyword_expander import collapse_keywords from cvs2svn_lib.revision_manager import RevisionCollector from cvs2svn_lib.revision_manager import RevisionReader from cvs2svn_lib.serializer import MarshalSerializer @@ -626,95 +625,9 @@ class InternalRevisionCollector(RevisionCollector): self._rcs_trees.close() -class _KeywordExpander: - """A class whose instances provide substitutions for CVS keywords. - - This class is used via its __call__() method, which should be called - with a match object representing a match for a CVS keyword string. - The method returns the replacement for the matched text. - - The __call__() method works by calling the method with the same name - as that of the CVS keyword (converted to lower case). - - Instances of this class can be passed as the REPL argument to - re.sub().""" - - date_fmt_old = "%Y/%m/%d %H:%M:%S" # CVS 1.11, rcs - date_fmt_new = "%Y-%m-%d %H:%M:%S" # CVS 1.12 - - date_fmt = date_fmt_new - - @classmethod - def use_old_date_format(klass): - """Class method to ensure exact compatibility with CVS 1.11 - output. Use this if you want to verify your conversion and you're - using CVS 1.11.""" - klass.date_fmt = klass.date_fmt_old - - def __init__(self, cvs_rev): - self.cvs_rev = cvs_rev - - def __call__(self, match): - return '$%s: %s $' % ( - match.group(1), getattr(self, match.group(1).lower())(), - ) - - def author(self): - return Ctx()._metadata_db[self.cvs_rev.metadata_id].original_author - - def date(self): - return time.strftime(self.date_fmt, time.gmtime(self.cvs_rev.timestamp)) - - def header(self): - return '%s %s %s %s Exp' % ( - self.source(), self.cvs_rev.rev, self.date(), self.author(), - ) - - def id(self): - return '%s %s %s %s Exp' % ( - self.rcsfile(), self.cvs_rev.rev, self.date(), self.author(), - ) - - def locker(self): - # Handle kvl like kv, as a converted repo is supposed to have no - # locks. - return '' - - def log(self): - # Would need some special handling. - return 'not supported by cvs2svn' - - def name(self): - # Cannot work, as just creating a new symbol does not check out - # the revision again. - return 'not supported by cvs2svn' - - def rcsfile(self): - return self.cvs_rev.cvs_file.rcs_basename + ",v" - - def revision(self): - return self.cvs_rev.rev - - def source(self): - project = self.cvs_rev.cvs_file.project - return '%s/%s%s,v' % ( - project.cvs_repository_root, - project.cvs_module, - self.cvs_rev.cvs_file.cvs_path, - ) - - def state(self): - # We check out only live revisions. - return 'Exp' - - class InternalRevisionReader(RevisionReader): """A RevisionReader that reads the contents from an own delta store.""" - _kws = 'Author|Date|Header|Id|Locker|Log|Name|RCSfile|Revision|Source|State' - _kw_re = re.compile(r'\$(' + _kws + r'):[^$\n]*\$') - _kwo_re = re.compile(r'\$(' + _kws + r')(:[^$\n]*)?\$') - def __init__(self, compress): self._compress = compress @@ -809,9 +722,9 @@ class InternalRevisionReader(RevisionReader): # Leave keywords in the form that they were checked in. pass elif keyword_handling == 'collapsed': - text = self._kw_re.sub(r'$\1$', text) + text = collapse_keywords(text) elif keyword_handling == 'expanded': - text = self._kwo_re.sub(_KeywordExpander(cvs_rev), text) + text = expand_keywords(text, cvs_rev) else: raise FatalError( 'Undefined _keyword_handling property (%r) for %s' diff --git a/cvs2svn_lib/keyword_expander.py b/cvs2svn_lib/keyword_expander.py new file mode 100644 index 00000000..e180e1d1 --- /dev/null +++ b/cvs2svn_lib/keyword_expander.py @@ -0,0 +1,128 @@ +# (Be in -*- python -*- mode.) +# +# ==================================================================== +# Copyright (c) 2007-2010 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/. +# ==================================================================== + +"""Expand RCS/CVS keywords.""" + + +import re +import time + +from cvs2svn_lib.context import Ctx + + +class _KeywordExpander: + """A class whose instances provide substitutions for CVS keywords. + + This class is used via its __call__() method, which should be called + with a match object representing a match for a CVS keyword string. + The method returns the replacement for the matched text. + + The __call__() method works by calling the method with the same name + as that of the CVS keyword (converted to lower case). + + Instances of this class can be passed as the REPL argument to + re.sub().""" + + date_fmt_old = "%Y/%m/%d %H:%M:%S" # CVS 1.11, rcs + date_fmt_new = "%Y-%m-%d %H:%M:%S" # CVS 1.12 + + date_fmt = date_fmt_new + + @classmethod + def use_old_date_format(klass): + """Class method to ensure exact compatibility with CVS 1.11 + output. Use this if you want to verify your conversion and you're + using CVS 1.11.""" + klass.date_fmt = klass.date_fmt_old + + def __init__(self, cvs_rev): + self.cvs_rev = cvs_rev + + def __call__(self, match): + return '$%s: %s $' % ( + match.group(1), getattr(self, match.group(1).lower())(), + ) + + def author(self): + return Ctx()._metadata_db[self.cvs_rev.metadata_id].original_author + + def date(self): + return time.strftime(self.date_fmt, time.gmtime(self.cvs_rev.timestamp)) + + def header(self): + return '%s %s %s %s Exp' % ( + self.source(), self.cvs_rev.rev, self.date(), self.author(), + ) + + def id(self): + return '%s %s %s %s Exp' % ( + self.rcsfile(), self.cvs_rev.rev, self.date(), self.author(), + ) + + def locker(self): + # Handle kvl like kv, as a converted repo is supposed to have no + # locks. + return '' + + def log(self): + # Would need some special handling. + return 'not supported by cvs2svn' + + def name(self): + # Cannot work, as just creating a new symbol does not check out + # the revision again. + return 'not supported by cvs2svn' + + def rcsfile(self): + return self.cvs_rev.cvs_file.rcs_basename + ",v" + + def revision(self): + return self.cvs_rev.rev + + def source(self): + project = self.cvs_rev.cvs_file.project + return '%s/%s%s,v' % ( + project.cvs_repository_root, + project.cvs_module, + self.cvs_rev.cvs_file.cvs_path, + ) + + def state(self): + # We check out only live revisions. + return 'Exp' + + +_kws = 'Author|Date|Header|Id|Locker|Log|Name|RCSfile|Revision|Source|State' +_kw_re = re.compile(r'\$(' + _kws + r'):[^$\n]*\$') +_kwo_re = re.compile(r'\$(' + _kws + r')(:[^$\n]*)?\$') + + +def expand_keywords(text, cvs_rev): + """Return TEXT with keywords expanded for CVS_REV. + + E.g., '$Author$' -> '$Author: jrandom $'.""" + + return _kwo_re.sub(_KeywordExpander(cvs_rev), text) + + +def collapse_keywords(text): + """Return TEXT with keywords collapsed. + + E.g., '$Author: jrandom $' -> '$Author$'.""" + + return _kw_re.sub(r'$\1$', text) + + -- 2.11.4.GIT