cvs2git enforces SVN file naming on conversions
Daniel Hagerty <[email protected]>
| Newsgroups | gmane.comp.version-control.subversion.cvs2svn.user |
|---|---|
| Message-ID | <[email protected]> |
I've been playing with converting some company cvs repositories
with cvs2git. I ran into a problem with one of them, with the error
message:
ERROR: File '.../file\rname,v' would result in an illegal SVN
filename: Character '\r' in filename 'file\rname' is not supported by
Subversion.
Perhaps this is true for subversion, but git doesn't care.
Attached are two patches that produce "works for me". As I didn't
test what git will and won't let me put into a filename beyond \r, the
regexp is probably still too narrow, but easy to fix.
The first patch refactors common.py so that it can import
context.py. The second is the actual change to use a different regexp
for verify_svn_filename_legal when targetting git, based on a new
git_target variable in the context object.
------------------------------------------------------
http://cvs2svn.tigris.org/ds/viewMessage.do?dsForumId=1670&dsMessageId=2652162
To unsubscribe from this discussion, e-mail: [[email protected]].
0001-Factor-out-CVSTextDecoder-to-its-own-file.patch
(text/plain, 8.7 KB)
From e0b5af72952eb5b61406825824a0980e675a2beb Mon Sep 17 00:00:00 2001 From: Daniel Hagerty <[email protected]> Date: Fri, 27 Aug 2010 14:11:41 -0400 Subject: [PATCH 1/2] Factor out CVSTextDecoder to its own file. --- cvs2bzr-example.options | 2 +- cvs2git-example.options | 2 +- cvs2hg-example.options | 2 +- cvs2svn-example.options | 2 +- cvs2svn_lib/common.py | 74 ---------------------------------------- cvs2svn_lib/context.py | 2 +- cvs2svn_lib/cvstextdecoder.py | 75 +++++++++++++++++++++++++++++++++++++++++ cvs2svn_lib/run_options.py | 2 +- 8 files changed, 81 insertions(+), 80 deletions(-) create mode 100644 cvs2svn_lib/cvstextdecoder.py diff --git a/cvs2bzr-example.options b/cvs2bzr-example.options index 4eba1e8..8ecc771 100644 --- a/cvs2bzr-example.options +++ b/cvs2bzr-example.options @@ -76,7 +76,7 @@ import re from cvs2svn_lib import config from cvs2svn_lib import changeset_database -from cvs2svn_lib.common import CVSTextDecoder +from cvs2svn_lib.cvstextdecoder import CVSTextDecoder from cvs2svn_lib.log import Log from cvs2svn_lib.project import Project from cvs2svn_lib.git_revision_recorder import GitRevisionRecorder diff --git a/cvs2git-example.options b/cvs2git-example.options index ab280dd..136a986 100644 --- a/cvs2git-example.options +++ b/cvs2git-example.options @@ -76,7 +76,7 @@ import re from cvs2svn_lib import config from cvs2svn_lib import changeset_database -from cvs2svn_lib.common import CVSTextDecoder +from cvs2svn_lib.cvstextdecoder import CVSTextDecoder from cvs2svn_lib.log import Log from cvs2svn_lib.project import Project from cvs2svn_lib.git_revision_recorder import GitRevisionRecorder diff --git a/cvs2hg-example.options b/cvs2hg-example.options index 326b16b..d6c23c6 100644 --- a/cvs2hg-example.options +++ b/cvs2hg-example.options @@ -90,7 +90,7 @@ import re from cvs2svn_lib import config from cvs2svn_lib import changeset_database -from cvs2svn_lib.common import CVSTextDecoder +from cvs2svn_lib.cvstextdecoder import CVSTextDecoder from cvs2svn_lib.log import Log from cvs2svn_lib.project import Project from cvs2svn_lib.git_revision_recorder import GitRevisionRecorder diff --git a/cvs2svn-example.options b/cvs2svn-example.options index 660e41d..75addea 100644 --- a/cvs2svn-example.options +++ b/cvs2svn-example.options @@ -63,7 +63,7 @@ import re from cvs2svn_lib import config from cvs2svn_lib import changeset_database -from cvs2svn_lib.common import CVSTextDecoder +from cvs2svn_lib.cvstextdecoder import CVSTextDecoder from cvs2svn_lib.log import Log from cvs2svn_lib.project import Project from cvs2svn_lib.svn_output_option import DumpfileOutputOption diff --git a/cvs2svn_lib/common.py b/cvs2svn_lib/common.py index 8400907..d114912 100644 --- a/cvs2svn_lib/common.py +++ b/cvs2svn_lib/common.py @@ -19,7 +19,6 @@ import re import time -import codecs from cvs2svn_lib.log import Log @@ -282,79 +281,6 @@ def format_date(date): return time.strftime("%Y-%m-%dT%H:%M:%S.000000Z", time.gmtime(date)) -class CVSTextDecoder: - """Callable that decodes CVS strings into Unicode.""" - - def __init__(self, encodings, fallback_encoding=None): - """Create a CVSTextDecoder instance. - - ENCODINGS is a list containing the names of encodings that are - attempted to be used as source encodings in 'strict' mode. - - FALLBACK_ENCODING, if specified, is the name of an encoding that - should be used as a source encoding in lossy 'replace' mode if all - of ENCODINGS failed. - - Raise LookupError if any of the specified encodings is unknown.""" - - self.decoders = [ - (encoding, codecs.lookup(encoding)[1]) - for encoding in encodings] - - if fallback_encoding is None: - self.fallback_decoder = None - else: - self.fallback_decoder = ( - fallback_encoding, codecs.lookup(fallback_encoding)[1] - ) - - def add_encoding(self, encoding): - """Add an encoding to be tried in 'strict' mode. - - ENCODING is the name of an encoding. If it is unknown, raise a - LookupError.""" - - for (name, decoder) in self.decoders: - if name == encoding: - return - else: - self.decoders.append( (encoding, codecs.lookup(encoding)[1]) ) - - def set_fallback_encoding(self, encoding): - """Set the fallback encoding, to be tried in 'replace' mode. - - ENCODING is the name of an encoding. If it is unknown, raise a - LookupError.""" - - if encoding is None: - self.fallback_decoder = None - else: - self.fallback_decoder = (encoding, codecs.lookup(encoding)[1]) - - def __call__(self, s): - """Try to decode string S using our configured source encodings. - - Return the string as a Unicode string. If S is already a unicode - string, do nothing. - - Raise UnicodeError if the string cannot be decoded using any of - the source encodings and no fallback encoding was specified.""" - - if isinstance(s, unicode): - return s - for (name, decoder) in self.decoders: - try: - return decoder(s)[0] - except ValueError: - Log().verbose("Encoding '%s' failed for string %r" % (name, s)) - - if self.fallback_decoder is not None: - (name, decoder) = self.fallback_decoder - return decoder(s, 'replace')[0] - else: - raise UnicodeError - - class Timestamper: """Return monotonic timestamps derived from changeset timestamps.""" diff --git a/cvs2svn_lib/context.py b/cvs2svn_lib/context.py index 89dc16a..a0afd52 100644 --- a/cvs2svn_lib/context.py +++ b/cvs2svn_lib/context.py @@ -20,7 +20,7 @@ import os from cvs2svn_lib import config -from cvs2svn_lib.common import CVSTextDecoder +from cvs2svn_lib.cvstextdecoder import CVSTextDecoder class Ctx: diff --git a/cvs2svn_lib/cvstextdecoder.py b/cvs2svn_lib/cvstextdecoder.py new file mode 100644 index 0000000..12b0f39 --- /dev/null +++ b/cvs2svn_lib/cvstextdecoder.py @@ -0,0 +1,75 @@ +# Somebody put their favorite copyright notice here. + +import codecs + +class CVSTextDecoder: + """Callable that decodes CVS strings into Unicode.""" + + def __init__(self, encodings, fallback_encoding=None): + """Create a CVSTextDecoder instance. + + ENCODINGS is a list containing the names of encodings that are + attempted to be used as source encodings in 'strict' mode. + + FALLBACK_ENCODING, if specified, is the name of an encoding that + should be used as a source encoding in lossy 'replace' mode if all + of ENCODINGS failed. + + Raise LookupError if any of the specified encodings is unknown.""" + + self.decoders = [ + (encoding, codecs.lookup(encoding)[1]) + for encoding in encodings] + + if fallback_encoding is None: + self.fallback_decoder = None + else: + self.fallback_decoder = ( + fallback_encoding, codecs.lookup(fallback_encoding)[1] + ) + + def add_encoding(self, encoding): + """Add an encoding to be tried in 'strict' mode. + + ENCODING is the name of an encoding. If it is unknown, raise a + LookupError.""" + + for (name, decoder) in self.decoders: + if name == encoding: + return + else: + self.decoders.append( (encoding, codecs.lookup(encoding)[1]) ) + + def set_fallback_encoding(self, encoding): + """Set the fallback encoding, to be tried in 'replace' mode. + + ENCODING is the name of an encoding. If it is unknown, raise a + LookupError.""" + + if encoding is None: + self.fallback_decoder = None + else: + self.fallback_decoder = (encoding, codecs.lookup(encoding)[1]) + + def __call__(self, s): + """Try to decode string S using our configured source encodings. + + Return the string as a Unicode string. If S is already a unicode + string, do nothing. + + Raise UnicodeError if the string cannot be decoded using any of + the source encodings and no fallback encoding was specified.""" + + if isinstance(s, unicode): + return s + for (name, decoder) in self.decoders: + try: + return decoder(s)[0] + except ValueError: + Log().verbose("Encoding '%s' failed for string %r" % (name, s)) + + if self.fallback_decoder is not None: + (name, decoder) = self.fallback_decoder + return decoder(s, 'replace')[0] + else: + raise UnicodeError diff --git a/cvs2svn_lib/run_options.py b/cvs2svn_lib/run_options.py index 27d2ea6..68842b9 100644 --- a/cvs2svn_lib/run_options.py +++ b/cvs2svn_lib/run_options.py @@ -27,7 +27,7 @@ from cvs2svn_lib import config from cvs2svn_lib.common import warning_prefix from cvs2svn_lib.common import error_prefix from cvs2svn_lib.common import FatalError -from cvs2svn_lib.common import CVSTextDecoder +from cvs2svn_lib.cvstextdecoder import CVSTextDecoder from cvs2svn_lib.log import Log from cvs2svn_lib.context import Ctx from cvs2svn_lib.man_writer import ManOption -- 1.7.1
0002-Use-different-regexp-for-rejecting-git-filenames.patch
(text/plain, 2.6 KB)
From a173c9605e539e914d9eb338f385d3256ce00bb2 Mon Sep 17 00:00:00 2001 From: Daniel Hagerty <[email protected]> Date: Fri, 27 Aug 2010 13:15:17 -0400 Subject: [PATCH 2/2] Use different regexp for rejecting git filenames. Git is more permissive than subversion. --- cvs2svn_lib/common.py | 11 +++++++++-- cvs2svn_lib/context.py | 1 + cvs2svn_lib/git_run_options.py | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/cvs2svn_lib/common.py b/cvs2svn_lib/common.py index d114912..edb2900 100644 --- a/cvs2svn_lib/common.py +++ b/cvs2svn_lib/common.py @@ -21,7 +21,7 @@ import re import time from cvs2svn_lib.log import Log - +from cvs2svn_lib.context import Ctx # Always use these constants for opening databases. DB_OPEN_READ = 'r' @@ -117,6 +117,8 @@ class IllegalSVNPathError(FatalException): # Control characters (characters not allowed in Subversion filenames): ctrl_characters_regexp = re.compile('[\\\x00-\\\x1f\\\x7f]') +# Git's allowed control characters. Unlikely to be permissive enough. +git_ctrl_characters_regexp = re.compile('[\\\x00-\\\x0c\\\x0e-\\\x1f\\\x7f]') def verify_svn_filename_legal(filename): """Verify that FILENAME is a legal filename. @@ -138,7 +140,12 @@ def verify_svn_filename_legal(filename): if filename in ['.', '..']: raise IllegalSVNPathError("Illegal filename component %r." % (filename,)) - m = ctrl_characters_regexp.search(filename) + if Ctx().git_target: + re = git_ctrl_characters_regexp + else: + re = ctrl_characters_regexp + + m = re.search(filename) if m: raise IllegalSVNPathError( "Character %r in filename %r is not supported by Subversion." diff --git a/cvs2svn_lib/context.py b/cvs2svn_lib/context.py index a0afd52..bf00228 100644 --- a/cvs2svn_lib/context.py +++ b/cvs2svn_lib/context.py @@ -62,6 +62,7 @@ class Ctx: self.cross_project_commits = True self.cross_branch_commits = True self.retain_conflicting_attic_files = False + self.git_target = False self.initial_project_commit_message = ( 'Standard project directories initialized by cvs2svn.' diff --git a/cvs2svn_lib/git_run_options.py b/cvs2svn_lib/git_run_options.py index 726b127..3ea4876 100644 --- a/cvs2svn_lib/git_run_options.py +++ b/cvs2svn_lib/git_run_options.py @@ -92,6 +92,7 @@ class GitRunOptions(RunOptions): def __init__(self, progname, cmd_args, pass_manager): Ctx().cross_project_commits = False Ctx().cross_branch_commits = False + Ctx().git_target= True RunOptions.__init__(self, progname, cmd_args, pass_manager) def _get_output_options_group(self): -- 1.7.1