From 28cea7206fc2bb6e2b62f8a9f4617d0fcc8b494b Mon Sep 17 00:00:00 2001 From: mhagger Date: Wed, 16 Jun 2010 04:27:40 +0000 Subject: [PATCH] Decide whether to collapse RCS keywords based on a CVSRevision property. RevisionReader reads a CVSRevision property _keyword_handling to decide whether to collapse RCS keywords when retrieving the revision content. Set this property via a new KeywordHandlingPropertySetter (for DVCSs) and SVNKeywordHandlingPropertySetter (for SVN) to preserve existing behavior. git-svn-id: http://cvs2svn.tigris.org/svn/cvs2svn/trunk@5187 be7e6eca-30d4-0310-a8e5-ac0d63af7087 --- cvs2bzr-example.options | 5 +++++ cvs2git-example.options | 5 +++++ cvs2hg-example.options | 5 +++++ cvs2svn-example.options | 5 +++++ cvs2svn_lib/checkout_internal.py | 15 +++++++++------ cvs2svn_lib/cvs_revision_manager.py | 4 ++-- cvs2svn_lib/dumpfile_delegate.py | 8 +------- cvs2svn_lib/dvcs_common.py | 33 +++++++++++++++++++++++++++++++++ cvs2svn_lib/git_output_option.py | 4 +--- cvs2svn_lib/git_revision_collector.py | 4 +--- cvs2svn_lib/rcs_revision_manager.py | 4 ++-- cvs2svn_lib/revision_manager.py | 8 ++++---- cvs2svn_lib/svn_run_options.py | 23 +++++++++++++++++++++++ 13 files changed, 96 insertions(+), 27 deletions(-) diff --git a/cvs2bzr-example.options b/cvs2bzr-example.options index d57fd83f..274b1ea3 100644 --- a/cvs2bzr-example.options +++ b/cvs2bzr-example.options @@ -81,6 +81,7 @@ from cvs2svn_lib.log import Log from cvs2svn_lib.project import Project from cvs2svn_lib.git_output_option import GitRevisionInlineWriter from cvs2svn_lib.bzr_output_option import BzrOutputOption +from cvs2svn_lib.dvcs_common import KeywordHandlingPropertySetter from cvs2svn_lib.revision_manager import NullRevisionCollector from cvs2svn_lib.rcs_revision_manager import RCSRevisionReader from cvs2svn_lib.cvs_revision_manager import CVSRevisionReader @@ -404,6 +405,10 @@ ctx.file_property_setters.extend([ # being executable: ExecutablePropertySetter(), + # The following causes keywords to be collapsed in all text to be + # committed: + KeywordHandlingPropertySetter('collapsed'), + ]) ctx.revision_property_setters.extend([ ]) diff --git a/cvs2git-example.options b/cvs2git-example.options index 94bb5893..b545c263 100644 --- a/cvs2git-example.options +++ b/cvs2git-example.options @@ -83,6 +83,7 @@ from cvs2svn_lib.git_revision_collector import GitRevisionCollector from cvs2svn_lib.external_blob_generator import ExternalBlobGenerator from cvs2svn_lib.git_output_option import GitRevisionMarkWriter from cvs2svn_lib.git_output_option import GitOutputOption +from cvs2svn_lib.dvcs_common import KeywordHandlingPropertySetter from cvs2svn_lib.revision_manager import NullRevisionCollector from cvs2svn_lib.rcs_revision_manager import RCSRevisionReader from cvs2svn_lib.cvs_revision_manager import CVSRevisionReader @@ -439,6 +440,10 @@ ctx.file_property_setters.extend([ # being executable: ExecutablePropertySetter(), + # The following causes keywords to be collapsed in all text to be + # committed: + KeywordHandlingPropertySetter('collapsed'), + ]) ctx.revision_property_setters.extend([ ]) diff --git a/cvs2hg-example.options b/cvs2hg-example.options index b2499695..cf0cc73d 100644 --- a/cvs2hg-example.options +++ b/cvs2hg-example.options @@ -87,6 +87,7 @@ from cvs2svn_lib.log import Log from cvs2svn_lib.project import Project from cvs2svn_lib.git_output_option import GitRevisionInlineWriter from cvs2svn_lib.git_output_option import GitOutputOption +from cvs2svn_lib.dvcs_common import KeywordHandlingPropertySetter from cvs2svn_lib.revision_manager import NullRevisionCollector from cvs2svn_lib.rcs_revision_manager import RCSRevisionReader from cvs2svn_lib.cvs_revision_manager import CVSRevisionReader @@ -400,6 +401,10 @@ ctx.file_property_setters.extend([ # being executable: ExecutablePropertySetter(), + # The following causes keywords to be collapsed in all text to be + # committed: + KeywordHandlingPropertySetter('collapsed'), + ]) ctx.revision_property_setters.extend([ ]) diff --git a/cvs2svn-example.options b/cvs2svn-example.options index 2c26b85a..3a200ec5 100644 --- a/cvs2svn-example.options +++ b/cvs2svn-example.options @@ -69,6 +69,7 @@ from cvs2svn_lib.project import Project from cvs2svn_lib.svn_output_option import DumpfileOutputOption from cvs2svn_lib.svn_output_option import ExistingRepositoryOutputOption from cvs2svn_lib.svn_output_option import NewRepositoryOutputOption +from cvs2svn_lib.svn_run_options import SVNKeywordHandlingPropertySetter from cvs2svn_lib.revision_manager import NullRevisionCollector from cvs2svn_lib.rcs_revision_manager import RCSRevisionReader from cvs2svn_lib.cvs_revision_manager import CVSRevisionReader @@ -505,6 +506,10 @@ ctx.file_property_setters.extend([ # file that has one: DescriptionPropertySetter(propname='cvs:description'), + # The following is for internal use. It determines how to handle + # keywords in the text being committed: + SVNKeywordHandlingPropertySetter(), + ]) ctx.revision_property_setters.extend([ # Uncomment the following line to include the original CVS revision diff --git a/cvs2svn_lib/checkout_internal.py b/cvs2svn_lib/checkout_internal.py index 9e36e6e4..5aec6ac9 100644 --- a/cvs2svn_lib/checkout_internal.py +++ b/cvs2svn_lib/checkout_internal.py @@ -749,13 +749,13 @@ class InternalRevisionReader(RevisionReader): return self._text_record_db[cvs_rev.id] - def get_content(self, cvs_rev, suppress_keyword_substitution=False): + def get_content(self, cvs_rev): """Check out the text for revision C_REV from the repository. - Return the text. If SUPPRESS_KEYWORD_SUBSTITUTION is True, any - RCS keywords will be _un_expanded prior to returning the file - content. Note that $Log$ never actually generates a log (which - makes test 'requires_cvs()' fail). + Return the text. If CVS_REV has a property + _keyword_handling=='collapsed', collapse any RCS keywords in the + file content. Note that $Log$ never actually generates a log + (which makes test 'requires_cvs()' fail). Revisions may be requested in any order, but if they are not requested in dependency order the checkout database will become @@ -767,8 +767,11 @@ class InternalRevisionReader(RevisionReader): except MalformedDeltaException, (msg): raise FatalError('Malformed RCS delta in %s, revision %s: %s' % (cvs_rev.cvs_file.get_filename(), cvs_rev.rev, msg)) + + keyword_handling = cvs_rev.get_property('_keyword_handling') + if cvs_rev.cvs_file.mode != 'b' and cvs_rev.cvs_file.mode != 'o': - if suppress_keyword_substitution or cvs_rev.cvs_file.mode == 'k': + if keyword_handling == 'collapsed' or cvs_rev.cvs_file.mode == 'k': text = self._kw_re.sub(r'$\1$', text) else: text = self._kwo_re.sub(_KeywordExpander(cvs_rev), text) diff --git a/cvs2svn_lib/cvs_revision_manager.py b/cvs2svn_lib/cvs_revision_manager.py index b68872a7..01f465e3 100644 --- a/cvs2svn_lib/cvs_revision_manager.py +++ b/cvs2svn_lib/cvs_revision_manager.py @@ -93,7 +93,7 @@ class CVSRevisionReader(RevisionReader): self.cvs_executable, ) - def get_content(self, cvs_rev, suppress_keyword_substitution=False): + def get_content(self, cvs_rev): project = cvs_rev.cvs_file.project pipe_cmd = [ self.cvs_executable @@ -103,7 +103,7 @@ class CVSRevisionReader(RevisionReader): '-r' + cvs_rev.rev, '-p' ] - if suppress_keyword_substitution: + if cvs_rev.get_property('_keyword_handling') == 'collapsed': pipe_cmd.append('-kk') pipe_cmd.append(project.cvs_module + cvs_rev.cvs_path) return get_command_output(pipe_cmd) diff --git a/cvs2svn_lib/dumpfile_delegate.py b/cvs2svn_lib/dumpfile_delegate.py index e6cd4c0a..b356f651 100644 --- a/cvs2svn_lib/dumpfile_delegate.py +++ b/cvs2svn_lib/dumpfile_delegate.py @@ -268,13 +268,7 @@ class DumpfileDelegate(SVNRepositoryDelegate): prop_contents = '' props_header = '' - # If the file has keywords, we must prevent CVS/RCS from expanding - # the keywords because they must be unexpanded in the repository, - # or Subversion will get confused. - has_keywords = bool(cvs_rev.get_properties().get('svn:keywords', None)) - data = self._revision_reader.get_content( - cvs_rev, suppress_keyword_substitution=has_keywords, - ) + data = self._revision_reader.get_content(cvs_rev) if Ctx().decode_apple_single: # Insert a filter to decode any files that are in AppleSingle diff --git a/cvs2svn_lib/dvcs_common.py b/cvs2svn_lib/dvcs_common.py index 0b819b5c..fe2758d0 100644 --- a/cvs2svn_lib/dvcs_common.py +++ b/cvs2svn_lib/dvcs_common.py @@ -37,6 +37,31 @@ from cvs2svn_lib.svn_revision_range import RevisionScores from cvs2svn_lib.openings_closings import SymbolingsReader from cvs2svn_lib.repository_mirror import RepositoryMirror from cvs2svn_lib.output_option import OutputOption +from cvs2svn_lib.property_setters import FilePropertySetter + + +class KeywordHandlingPropertySetter(FilePropertySetter): + """Set property _keyword_handling to a specified value. + + This keyword is used to tell the RevisionReader whether it has to + collapse/expand RCS keywords when generating the fulltext or leave + them alone.""" + + propname = '_keyword_handling' + + def __init__(self, value): + if value not in ['collapsed', 'expanded', 'untouched', None]: + raise FatalError( + 'Value for %s must be "collapsed", "expanded", or "untouched"' + % (self.propname,) + ) + self.value = value + + def set_properties(self, cvs_file): + if self.propname in cvs_file.properties: + return + + cvs_file.properties[self.propname] = self.value class DVCSRunOptions(RunOptions): @@ -73,6 +98,14 @@ class DVCSRunOptions(RunOptions): self.projects = [project] self.project_symbol_strategy_rules = [symbol_strategy_rules] + def process_property_setter_options(self): + super(DVCSRunOptions, self).process_property_setter_options() + + # Property setters for internal use: + Ctx().file_property_setters.append( + KeywordHandlingPropertySetter('collapsed') + ) + def process_options(self): # Consistency check for options and arguments. if len(self.args) == 0: diff --git a/cvs2svn_lib/git_output_option.py b/cvs2svn_lib/git_output_option.py index 42a25993..dfd5905e 100644 --- a/cvs2svn_lib/git_output_option.py +++ b/cvs2svn_lib/git_output_option.py @@ -124,9 +124,7 @@ class GitRevisionInlineWriter(GitRevisionWriter): # FIXME: We have to decide what to do about keyword substitution # and eol_style here: - fulltext = self.revision_reader.get_content( - cvs_rev, suppress_keyword_substitution=False - ) + fulltext = self.revision_reader.get_content(cvs_rev) self.f.write('data %d\n' % (len(fulltext),)) self.f.write(fulltext) diff --git a/cvs2svn_lib/git_revision_collector.py b/cvs2svn_lib/git_revision_collector.py index 73c843c1..78fcc092 100644 --- a/cvs2svn_lib/git_revision_collector.py +++ b/cvs2svn_lib/git_revision_collector.py @@ -50,9 +50,7 @@ class GitRevisionCollector(RevisionCollector): # FIXME: We have to decide what to do about keyword substitution # and eol_style here: - fulltext = self.revision_reader.get_content( - cvs_rev, suppress_keyword_substitution=False, - ) + fulltext = self.revision_reader.get_content(cvs_rev) mark = self._mark_generator.gen_id() self.dump_file.write('blob\n') diff --git a/cvs2svn_lib/rcs_revision_manager.py b/cvs2svn_lib/rcs_revision_manager.py index 167c5c32..f5af7027 100644 --- a/cvs2svn_lib/rcs_revision_manager.py +++ b/cvs2svn_lib/rcs_revision_manager.py @@ -36,14 +36,14 @@ class RCSRevisionReader(RevisionReader): 'Please check that co is installed and in your PATH\n' '(it is a part of the RCS software).' % (e,)) - def get_content(self, cvs_rev, suppress_keyword_substitution=False): + def get_content(self, cvs_rev): pipe_cmd = [ self.co_executable, '-q', '-x,v', '-p%s' % (cvs_rev.rev,) ] - if suppress_keyword_substitution: + if cvs_rev.get_property('_keyword_handling') == 'collapsed': pipe_cmd.append('-kk') pipe_cmd.append(cvs_rev.cvs_file.filename) return get_command_output(pipe_cmd) diff --git a/cvs2svn_lib/revision_manager.py b/cvs2svn_lib/revision_manager.py index a8e49751..34c11c0c 100644 --- a/cvs2svn_lib/revision_manager.py +++ b/cvs2svn_lib/revision_manager.py @@ -95,12 +95,12 @@ class RevisionReader(object): pass - def get_content(self, cvs_rev, suppress_keyword_substitution=False): + def get_content(self, cvs_rev): """Return the contents of CVS_REV. - CVS_REV is a CVSRevision. If SUPPRESS_KEYWORD_SUBSTITUTION is - True, then suppress the substitution of RCS/CVS keywords in the - output.""" + CVS_REV is a CVSRevision. If CVS_REV has a property + _keyword_handling=='collapsed' then collapse RCS/CVS keywords in + the output.""" raise NotImplementedError() diff --git a/cvs2svn_lib/svn_run_options.py b/cvs2svn_lib/svn_run_options.py index 86054a80..2a9efd61 100644 --- a/cvs2svn_lib/svn_run_options.py +++ b/cvs2svn_lib/svn_run_options.py @@ -39,6 +39,23 @@ from cvs2svn_lib.svn_output_option import NewRepositoryOutputOption from cvs2svn_lib.symbol_strategy import TrunkPathRule from cvs2svn_lib.symbol_strategy import BranchesPathRule from cvs2svn_lib.symbol_strategy import TagsPathRule +from cvs2svn_lib.property_setters import FilePropertySetter + + +class SVNKeywordHandlingPropertySetter(FilePropertySetter): + """Set cvs2svn:_keyword_handling=collapsed if svn:keywords is set. + + This keyword is used to tell the RevisionReader whether it has to + collapse RCS keywords when generating the fulltext.""" + + propname = '_keyword_handling' + + def set_properties(self, cvs_file): + if self.propname in cvs_file.properties: + return + + if cvs_file.properties.get('svn:keywords'): + cvs_file.properties[self.propname] = 'collapsed' class SVNRunOptions(RunOptions): @@ -428,6 +445,12 @@ A directory called \\fIcvs2svn-tmp\\fR (or the directory specified by del self.projects[:] del self.project_symbol_strategy_rules[:] + def process_property_setter_options(self): + super(SVNRunOptions, self).process_property_setter_options() + + # Property setters for internal use: + Ctx().file_property_setters.append(SVNKeywordHandlingPropertySetter()) + def process_options(self): # Consistency check for options and arguments. if len(self.args) == 0: -- 2.11.4.GIT