convert: fix builtin cvsps under Windows
authorPatrick Mezard <pmezard@gmail.com>
Mon, 13 Oct 2008 17:31:03 +0100
changeset 7097 d4218edd55bd
parent 7096 6dab29f6df37
child 7100 baf12d52add4
convert: fix builtin cvsps under Windows Drafted and reviewed by Frank Kingswood <frank@kingswood-consulting.co.uk>.
hgext/convert/cvsps.py
tests/test-doctest.py
--- a/hgext/convert/cvsps.py	Wed Oct 15 01:14:29 2008 +0200
+++ b/hgext/convert/cvsps.py	Mon Oct 13 17:31:03 2008 +0100
@@ -41,6 +41,45 @@
 class logerror(Exception):
     pass
 
+def getrepopath(cvspath):
+    """Return the repository path from a CVS path.
+
+    >>> getrepopath('/foo/bar')
+    '/foo/bar'
+    >>> getrepopath('c:/foo/bar')
+    'c:/foo/bar'
+    >>> getrepopath(':pserver:10/foo/bar')
+    '/foo/bar'
+    >>> getrepopath(':pserver:10c:/foo/bar')
+    '/foo/bar'
+    >>> getrepopath(':pserver:/foo/bar')
+    '/foo/bar'
+    >>> getrepopath(':pserver:c:/foo/bar')
+    'c:/foo/bar'
+    >>> getrepopath(':pserver:truc@foo.bar:/foo/bar')
+    '/foo/bar'
+    >>> getrepopath(':pserver:truc@foo.bar:c:/foo/bar')
+    'c:/foo/bar'
+    """
+    # According to CVS manual, CVS paths are expressed like:
+    # [:method:][[user][:password]@]hostname[:[port]]/path/to/repository
+    #
+    # Unfortunately, Windows absolute paths start with a drive letter
+    # like 'c:' making it harder to parse. Here we assume that drive
+    # letters are only one character long and any CVS component before
+    # the repository path is at least 2 characters long, and use this
+    # to disambiguate.
+    parts = cvspath.split(':')
+    if len(parts) == 1:
+        return parts[0]
+    # Here there is an ambiguous case if we have a port number
+    # immediately followed by a Windows driver letter. We assume this
+    # never happens and decide it must be CVS path component,
+    # therefore ignoring it.
+    if len(parts[-2]) > 1:
+        return parts[-1].lstrip('0123456789')
+    return parts[-2] + ':' + parts[-1]
+
 def createlog(ui, directory=None, root="", rlog=True, cache=None):
     '''Collect the CVS rlog'''
 
@@ -83,8 +122,8 @@
         except IOError:
             raise logerror('Not a CVS sandbox')
 
-        if prefix and not prefix.endswith('/'):
-            prefix += '/'
+        if prefix and not prefix.endswith(os.sep):
+            prefix += os.sep
 
         # Use the Root file in the sandbox, if it exists
         try:
@@ -134,10 +173,10 @@
     cmd = ['cvs', '-q']
     if root:
         cmd.append('-d%s' % root)
-        p = root.split(':')[-1]
+        p = util.normpath(getrepopath(root))
         if not p.endswith('/'):
             p += '/'
-        prefix = p + prefix
+        prefix = p + util.normpath(prefix)
     cmd.append(['log', 'rlog'][rlog])
     if date:
         # no space between option and date string
@@ -165,7 +204,7 @@
                 rcs = match.group(1)
                 tags = {}
                 if rlog:
-                    filename = rcs[:-2]
+                    filename = util.normpath(rcs[:-2])
                     if filename.startswith(prefix):
                         filename = filename[len(prefix):]
                     if filename.startswith('/'):
@@ -191,7 +230,7 @@
             # expect 'Working file' (only when using log instead of rlog)
             match = re_10.match(line)
             assert match, _('RCS file must be followed by working file')
-            filename = match.group(1)
+            filename = util.normpath(match.group(1))
             state = 2
 
         elif state == 2:
--- a/tests/test-doctest.py	Wed Oct 15 01:14:29 2008 +0200
+++ b/tests/test-doctest.py	Mon Oct 13 17:31:03 2008 +0100
@@ -14,3 +14,6 @@
 
 import mercurial.util
 doctest.testmod(mercurial.util)
+
+import hgext.convert.cvsps
+doctest.testmod(hgext.convert.cvsps)