unionrepo: use pathutil.normasprefix to ensure os.sep at the end of cwd
Since Python 2.7.9, "os.path.join(path, '')" doesn't add "os.sep" at
the end of UNC path (see
issue4557 for detail).
This makes unionrepo incorrectly work, if:
1. cwd is the root of UNC share (e.g. "\host\share"), and
2. mainreporoot is near cwd (e.g. "\host\sharefoo\repo")
- host of UNC path is same as one of cwd
- share of UNC path starts with one of cwd
3. "repopath" isn't specified in URI (e.g. "union:path/to/repo2")
For example:
$ hg --cwd \host\share -R \host\sharefoo\repo incoming union:path\to\repo2
In this case:
- os.path.join(r"\host\share", "") returns r"\host\share",
- r"\host\sharefoo\repo".startswith(r"\host\share") returns True, then
- r"foo\repo" is treated as repopath of unionrepo instead of
r"\host\sharefoo\repo"
This causes failure of combining "\host\sharefoo\repo" and another
repository: in addition to it, "\host\share\foo\repo" may be combined
with another repository, if it accidentally exists.
This patch uses "pathutil.normasprefix()" to ensure "os.sep" at the
end of cwd safely, even with some problematic encodings, which use
0x5c (= "os.sep" on Windows) as the tail byte of some multi-byte
characters.
BTW, normalization before "pathutil.normasprefix()" isn't needed in
this case, because "os.getcwd()" always returns normalized one.
bundlerepo: use pathutil.normasprefix to ensure os.sep at the end of cwd
Since Python 2.7.9, "os.path.join(path, '')" doesn't add "os.sep" at
the end of UNC path (see
issue4557 for detail).
This makes bundlerepo incorrectly work, if:
1. cwd is the root of UNC share (e.g. "\host\share"), and
2. mainreporoot is near cwd (e.g. "\host\sharefoo\repo")
- host of UNC path is same as one of cwd
- share of UNC path starts with one of cwd
3. "repopath" isn't specified in bundle URI
(e.g. "bundle:bundlefile" or just "bundlefile")
For example:
$ hg --cwd \host\share -R \host\sharefoo\repo incoming bundle
In this case:
- os.path.join(r"\host\share", "") returns r"\host\share",
- r"\host\sharefoo\repo".startswith(r"\host\share") returns True, then
- r"foo\repo" is treated as repopath of bundlerepo instead of
r"\host\sharefoo\repo"
This causes failure of combining "\host\sharefoo\repo" and bundle
file: in addition to it, "\host\share\foo\repo" may be combined with
bundle file, if it accidentally exists.
This patch uses "pathutil.normasprefix()" to ensure "os.sep" at the
end of cwd safely, even with some problematic encodings, which use
0x5c (= "os.sep" on Windows) as the tail byte of some multi-byte
characters.
BTW, normalization before "pathutil.normasprefix()" isn't needed in
this case, because "os.getcwd()" always returns normalized one.
dirstate: use pathutil.normasprefix to ensure os.sep at the end of root
3cc630be5f09 replaced "os.path.join(root, '')" by
"root.endswith(os.sep)" examination, because Python 2.7.9 changes
behavior of "os.path.join(path, '')" on UNC path.
But some problematic encodings use 0x5c (= "os.sep" on Windows) as the
tail byte of some multi-byte characters, and replacement above
prevents Mercurial from working on the repository, of which root path
ends with such multi-byte character, regardless of enabling win32mbcs.
This patch uses "pathutil.normasprefix()" instead of
"root.endswith(os.sep)" examination, to ensure "os.sep" at the end of
"dirstate._rootdir" even with problematic encodings.
"root" of dirstate can be passed to "pathutil.normasprefix()" without
normalization, because it is always given from "repo.root" =
"repo.wvfs.base", which is normalized by "os.path.realpath()".
Using "util.endswithsep()" instead of "str.endswith(os.sep)" also
fixes this problem, but this patch chooses "pathutil.normasprefix()"
to centralize "adding os.sep if endswith(os.sep)" logic into it.