# HG changeset patch # User FUJIWARA Katsunori # Date 2014-05-08 10:03:00 # Node ID 8dd17b19e722209693c786f1c3c318a1dab05086 # Parent 5900bc09e684446362b8f7744dc3e0cc3908aa3e subrepo: normalize path in the specific way for problematic encodings Before this patch, "reporelpath()" uses "rstrip(os.sep)" to trim "os.sep" at the end of "parent.root" path. But it doesn't work correctly with some problematic encodings on Windows, because some multi-byte characters in such encodings contain '\\' (0x5c) as the tail byte of them. In such cases, "reporelpath()" leaves unexpected '\\' at the beginning of the path returned to callers. "lcalrepository.root" seems not to have tail "os.sep", because it is always normalized by "os.path.realpath()" in "vfs.__init__()", but in fact it has tail "os.sep", if it is a root (of the drive): path normalization trims tail "os.sep" off "/foo/bar/", but doesn't trim one off "/". So, just avoiding "rstrip(os.sep)" in "reporelpath()" causes regression around issue3033 fixed by fccd350acf79. This patch introduces "pathutil.normasprefix" to normalize specified path in the specific way for problematic encodings without regression around issue3033. diff --git a/mercurial/pathutil.py b/mercurial/pathutil.py --- a/mercurial/pathutil.py +++ b/mercurial/pathutil.py @@ -142,3 +142,25 @@ def canonpath(root, cwd, myname, auditor name = dirname raise util.Abort(_("%s not under root '%s'") % (myname, root)) + +def normasprefix(path): + '''normalize the specified path as path prefix + + Returned vaule can be used safely for "p.startswith(prefix)", + "p[len(prefix):]", and so on. + + For efficiency, this expects "path" argument to be already + normalized by "os.path.normpath", "os.path.realpath", and so on. + + See also issue3033 for detail about need of this function. + + >>> normasprefix('/foo/bar').replace(os.sep, '/') + '/foo/bar/' + >>> normasprefix('/').replace(os.sep, '/') + '/' + ''' + d, p = os.path.splitdrive(path) + if len(p) != len(os.sep): + return path + os.sep + else: + return path diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -276,8 +276,7 @@ def reporelpath(repo): parent = repo while util.safehasattr(parent, '_subparent'): parent = parent._subparent - p = parent.root.rstrip(os.sep) - return repo.root[len(p) + 1:] + return repo.root[len(pathutil.normasprefix(parent.root)):] def subrelpath(sub): """return path to this subrepo as seen from outermost repo""" diff --git a/tests/test-doctest.py b/tests/test-doctest.py --- a/tests/test-doctest.py +++ b/tests/test-doctest.py @@ -19,6 +19,7 @@ testmod('mercurial.hg') testmod('mercurial.hgweb.hgwebdir_mod') testmod('mercurial.match') testmod('mercurial.minirst') +testmod('mercurial.pathutil') testmod('mercurial.revset') testmod('mercurial.store') testmod('mercurial.subrepo')