convert: correctly convert paths to UTF-8 for Subversion
The previous code using encoding.tolocal() only worked by chance in these
situations:
* The string is ASCII: The fast path was triggered and the string was returned
unmodified.
* The local encoding is UTF-8: The source and target encoding is the same.
* The string is not valid UTF-8 and the native encoding is ISO-8859-1: If the
string doesn’t decode using UTF-8, ISO-8859-1 is tried as a fallback. During
`hg convert`, the local encoding is always UTF-8. The irony is that in this
case, encoding.tolocal() behaves like what someone would expect the reverse
function, encoding.fromlocal(), to do.
When the locale encoding is ISO-8859-15, trying to convert a SVN repo `/tmp/a€`
failed before like this:
file:///tmp/a%C2%A4 does not look like a Subversion repository to libsvn version 1.14.0
The correct URL is `file:///tmp/a%E2%82%AC`.
Unlike previously (with the ISO-8859-1 fallback), decoding the path using the
locale encoding can fail. In this case, we have to bail out, as Subversion
won’t be able to do anything useful with the path.
https://bz.mercurial-scm.org/660 and:
https://bz.mercurial-scm.org/322
$ hg init
$ echo a > a
$ mkdir b
$ echo b > b/b
$ hg commit -A -m "a is file, b is dir"
adding a
adding b/b
File replaced with directory:
$ rm a
$ mkdir a
$ echo a > a/a
Should fail - would corrupt dirstate:
$ hg add a/a
abort: file 'a' in dirstate clashes with 'a/a'
[255]
Removing shadow:
$ hg rm --after a
Should succeed - shadow removed:
$ hg add a/a
Directory replaced with file:
$ rm -r b
$ echo b > b
Should fail - would corrupt dirstate:
$ hg add b
abort: directory 'b' already in dirstate
[255]
Removing shadow:
$ hg rm --after b/b
Should succeed - shadow removed:
$ hg add b
Look what we got:
$ hg st
A a/a
A b
R a
R b/b
Revert reintroducing shadow - should fail:
$ rm -r a b
$ hg revert b/b
abort: file 'b' in dirstate clashes with 'b/b'
[255]
Revert all - should succeed:
$ hg revert --all
forgetting a/a
forgetting b
undeleting a
undeleting b/b
$ hg st
Issue3423:
$ hg forget a
$ echo zed > a
$ hg revert a
$ hg st
? a.orig
$ rm a.orig
addremove:
$ rm -r a b
$ mkdir a
$ echo a > a/a
$ echo b > b
$ hg addremove -s 0
removing a
adding a/a
adding b
removing b/b
$ hg st
A a/a
A b
R a
R b/b
commit:
$ hg ci -A -m "a is dir, b is file"
$ hg st --all
C a/a
C b
Long directory replaced with file:
$ mkdir d
$ mkdir d/d
$ echo d > d/d/d
$ hg commit -A -m "d is long directory"
adding d/d/d
$ rm -r d
$ echo d > d
Should fail - would corrupt dirstate:
$ hg add d
abort: directory 'd' already in dirstate
[255]
Removing shadow:
$ hg rm --after d/d/d
Should succeed - shadow removed:
$ hg add d
$ hg ci -md
Update should work at least with clean working directory:
$ rm -r a b d
$ hg up -r 0
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg st --all
C a
C b/b
$ rm -r a b
$ hg up -r 1
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg st --all
C a/a
C b