convert/svn: fix URL quoting issue with svn 1.7 stable
authorPatrick Mezard <pmezard@gmail.com>
Thu, 01 Dec 2011 20:42:24 +0100
branchstable
changeset 15599 c6be93a4c378
parent 15598 a77ce45584ef
child 15600 195dbd1cef0c
convert/svn: fix URL quoting issue with svn 1.7 As of svn 1.7, many svn calls expect "canonical" paths. In theory, we should call svn.core.*canonicalize() on all paths before passing them to the API. Instead, we assume the base url is canonical and copy the behaviour of svn URL encoding function so we can extend it safely with new components.
hgext/convert/subversion.py
hgext/convert/transport.py
--- a/hgext/convert/subversion.py	Wed Nov 30 15:11:00 2011 +0100
+++ b/hgext/convert/subversion.py	Thu Dec 01 20:42:24 2011 +0100
@@ -50,10 +50,21 @@
         mod = '/' + parts[1]
     return parts[0][4:], mod, int(revnum)
 
+def quote(s):
+    # As of svn 1.7, many svn calls expect "canonical" paths. In
+    # theory, we should call svn.core.*canonicalize() on all paths
+    # before passing them to the API.  Instead, we assume the base url
+    # is canonical and copy the behaviour of svn URL encoding function
+    # so we can extend it safely with new components. The "safe"
+    # characters were taken from the "svn_uri__char_validity" table in
+    # libsvn_subr/path.c.
+    return urllib.quote(s, "!$&'()*+,-./:=@_~")
+
 def geturl(path):
     try:
         return svn.client.url_from_path(svn.core.svn_path_canonicalize(path))
     except SubversionException:
+        # svn.client.url_from_path() fails with local repositories
         pass
     if os.path.isdir(path):
         path = os.path.normpath(os.path.abspath(path))
@@ -62,8 +73,8 @@
         # Module URL is later compared with the repository URL returned
         # by svn API, which is UTF-8.
         path = encoding.tolocal(path)
-        return 'file://%s' % urllib.quote(path)
-    return path
+        path = 'file://%s' % quote(path)
+    return svn.core.svn_path_canonicalize(path)
 
 def optrev(number):
     optrev = svn.core.svn_opt_revision_t()
@@ -306,7 +317,7 @@
 
     def exists(self, path, optrev):
         try:
-            svn.client.ls(self.url.rstrip('/') + '/' + urllib.quote(path),
+            svn.client.ls(self.url.rstrip('/') + '/' + quote(path),
                                  optrev, False, self.ctx)
             return True
         except SubversionException:
@@ -358,7 +369,7 @@
         # Check if branches bring a few more heads to the list
         if branches:
             rpath = self.url.strip('/')
-            branchnames = svn.client.ls(rpath + '/' + urllib.quote(branches),
+            branchnames = svn.client.ls(rpath + '/' + quote(branches),
                                         rev, False, self.ctx)
             for branch in branchnames.keys():
                 module = '%s/%s/%s' % (oldmodule, branches, branch)
@@ -394,7 +405,7 @@
         else:
             # Perform a full checkout on roots
             uuid, module, revnum = revsplit(rev)
-            entries = svn.client.ls(self.baseurl + urllib.quote(module),
+            entries = svn.client.ls(self.baseurl + quote(module),
                                     optrev(revnum), True, self.ctx)
             files = [n for n, e in entries.iteritems()
                      if e.kind == svn.core.svn_node_file]
@@ -595,7 +606,7 @@
         """Reparent the svn transport and return the previous parent."""
         if self.prevmodule == module:
             return module
-        svnurl = self.baseurl + urllib.quote(module)
+        svnurl = self.baseurl + quote(module)
         prevmodule = self.prevmodule
         if prevmodule is None:
             prevmodule = ''
@@ -866,7 +877,7 @@
         """Enumerate all files in path at revnum, recursively."""
         path = path.strip('/')
         pool = Pool()
-        rpath = '/'.join([self.baseurl, urllib.quote(path)]).strip('/')
+        rpath = '/'.join([self.baseurl, quote(path)]).strip('/')
         entries = svn.client.ls(rpath, optrev(revnum), True, self.ctx, pool)
         if path:
             path += '/'
--- a/hgext/convert/transport.py	Wed Nov 30 15:11:00 2011 +0100
+++ b/hgext/convert/transport.py	Thu Dec 01 20:42:24 2011 +0100
@@ -86,7 +86,7 @@
             self.client.config = svn_config
             try:
                 self.ra = svn.client.open_ra_session(
-                    self.svn_url.encode('utf8'),
+                    self.svn_url,
                     self.client, self.pool)
             except SubversionException, (inst, num):
                 if num in (svn.core.SVN_ERR_RA_ILLEGAL_URL,