[PATCH STABLE] util: fix url.__str__() for windows file URLs

Patrick Mezard pmezard at gmail.com
Sun Dec 4 12:21:29 CST 2011


# HG changeset patch
# User Patrick Mezard <pmezard at gmail.com>
# Date 1323019345 -3600
# Branch stable
# Node ID 2d54164b5e39e9d92ae1245d68371fff0c1468bf
# Parent  2f2ca019569feddfc39eae4f1cda0b3da62d4e00
util: fix url.__str__() for windows file URLs

Before:

  >>> str(url('file:///c:/tmp/foo/bar'))
  'file:c%3C/tmp/foo/bar'

After:

  >>> str(url('file:///c:/tmp/foo/bar'))
  'file:///c%3C/tmp/foo/bar'

The previous behaviour had no effect on mercurial itself (clone command for
instance) because we fortunately called .localpath() on the parsed URL.
hgsubversion was not so lucky and cloning a local subversion repository on
Windows no longer worked on the default branch (it works on stable because
de7e2fba4326 defeats the hasdriveletter() test in url class).

I do not know if the %3C is correct or not but svn accepts file:// URLs
containing it. Mads fixed it in de7e2fba4326, so we can always backport should
the need arise.

diff --git a/hgext/schemes.py b/hgext/schemes.py
--- a/hgext/schemes.py
+++ b/hgext/schemes.py
@@ -72,9 +72,10 @@
         return hg._peerlookup(url).instance(ui, url, create)
 
 def hasdriveletter(orig, path):
-    for scheme in schemes:
-        if path.startswith(scheme + ':'):
-            return False
+    if path:
+        for scheme in schemes:
+            if path.startswith(scheme + ':'):
+                return False
     return orig(path)
 
 schemes = {
diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -1629,6 +1629,8 @@
         'path'
         >>> str(url('file:///tmp/foo/bar'))
         'file:///tmp/foo/bar'
+        >>> str(url('file:///c:/tmp/foo/bar'))
+        'file:///c%3A/tmp/foo/bar'
         >>> print url(r'bundle:foo\bar')
         bundle:foo\bar
         """
@@ -1643,8 +1645,11 @@
         s = self.scheme + ':'
         if self.user or self.passwd or self.host:
             s += '//'
-        elif self.scheme and (not self.path or self.path.startswith('/')):
+        elif self.scheme and (not self.path or self.path.startswith('/')
+                              or hasdriveletter(self.path)):
             s += '//'
+            if hasdriveletter(self.path):
+                s += '/'
         if self.user:
             s += urllib.quote(self.user, safe=self._safechars)
         if self.passwd:
@@ -1716,7 +1721,7 @@
     return bool(url(path).scheme)
 
 def hasdriveletter(path):
-    return path[1:2] == ':' and path[0:1].isalpha()
+    return path and path[1:2] == ':' and path[0:1].isalpha()
 
 def urllocalpath(path):
     return url(path, parsequery=False, parsefragment=False).localpath()
diff --git a/tests/test-url.py b/tests/test-url.py
--- a/tests/test-url.py
+++ b/tests/test-url.py
@@ -219,7 +219,7 @@
     >>> u
     <url scheme: 'file', path: 'f:oo/bar/baz'>
     >>> str(u)
-    'file:f%3Aoo/bar/baz'
+    'file:///f%3Aoo/bar/baz'
     >>> u.localpath()
     'f:oo/bar/baz'
 


More information about the Mercurial-devel mailing list