Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r73221:6bb6900ae05e
Date: 2014-08-31 12:18 +0200
http://bitbucket.org/pypy/pypy/changeset/6bb6900ae05e/

Log:    Extend rpython.rlib.rpath to include the following functions:

         risabs rabspath rsplitdrive rjoin

diff --git a/rpython/rlib/rpath.py b/rpython/rlib/rpath.py
--- a/rpython/rlib/rpath.py
+++ b/rpython/rlib/rpath.py
@@ -2,24 +2,122 @@
 Minimal (and limited) RPython version of some functions contained in os.path.
 """
 
-import os.path
+import os
 from rpython.rlib import rposix
 
-if os.name == 'posix':
-    # the posix version is already RPython, just use it
-    # (but catch exceptions)
-    def rabspath(path):
-        try:
-            return os.path.abspath(path)
-        except OSError:
-            return path
-elif os.name == 'nt':
-    def rabspath(path):
+
+def _posix_risabs(s):
+    """Test whether a path is absolute"""
+    return s.startswith('/')
+
+def _posix_rabspath(path):
+    """Return an absolute, **non-normalized** path.
+      **This version does not let exceptions propagate.**"""
+    try:
+        if not _posix_risabs(path):
+            cwd = os.getcwd()
+            path = _posix_rjoin(cwd, path)
+        return path
+    except OSError:
+        return path
+
+def _posix_rjoin(a, b):
+    """Join two pathname components, inserting '/' as needed.
+    If the second component is an absolute path, the first one
+    will be discarded.  An empty last part will result in a path that
+    ends with a separator."""
+    path = a
+    if b.startswith('/'):
+        path = b
+    elif path == '' or path.endswith('/'):
+        path +=  b
+    else:
+        path += '/' + b
+    return path
+
+
+def _nt_risabs(s):
+    """Test whether a path is absolute"""
+    s = _nt_rsplitdrive(s)[1]
+    return s.startswith('/') or s.startswith('\\')
+
+def _nt_rabspath(path):
+    try:
         if path == '':
             path = os.getcwd()
-        try:
-            return rposix._getfullpathname(path)
-        except OSError:
-            return path
+        return rposix._getfullpathname(path)
+    except OSError:
+        return path
+
+def _nt_rsplitdrive(p):
+    """Split a pathname into drive/UNC sharepoint and relative path
+    specifiers.
+    Returns a 2-tuple (drive_or_unc, path); either part may be empty.
+    """
+    if len(p) > 1:
+        normp = p.replace(altsep, sep)
+        if normp.startswith('\\\\') and not normp.startswith('\\\\\\'):
+            # is a UNC path:
+            # vvvvvvvvvvvvvvvvvvvv drive letter or UNC path
+            # \\machine\mountpoint\directory\etc\...
+            #           directory ^^^^^^^^^^^^^^^
+            index = normp.find('\\', 2)
+            if index < 0:
+                return '', p
+            index2 = normp.find('\\', index + 1)
+            # a UNC path can't have two slashes in a row
+            # (after the initial two)
+            if index2 == index + 1:
+                return '', p
+            if index2 < 0:
+                index2 = len(p)
+            return p[:index2], p[index2:]
+        if normp[1] == ':':
+            return p[:2], p[2:]
+    return '', p
+
+def _nt_rjoin(path, p):
+    """Join two or more pathname components, inserting "\\" as needed."""
+    result_drive, result_path = _nt_rsplitdrive(path)
+    p_drive, p_path = _nt_rsplitdrive(p)
+    p_is_rel = True
+    if p_path and p_path[0] in '\\/':
+        # Second path is absolute
+        if p_drive or not result_drive:
+            result_drive = p_drive
+        result_path = p_path
+        p_is_rel = False
+    elif p_drive and p_drive != result_drive:
+        if p_drive.lower() != result_drive.lower():
+            # Different drives => ignore the first path entirely
+            result_drive = p_drive
+            result_path = p_path
+            p_is_rel = False
+        else:
+            # Same drive in different case
+            result_drive = p_drive
+    if p_is_rel:
+        # Second path is relative to the first
+        if result_path and result_path[-1] not in '\\/':
+            result_path = result_path + '\\'
+        result_path = result_path + p_path
+    ## add separator between UNC and non-absolute path
+    if (result_path and result_path[0] not in '\\/' and
+        result_drive and result_drive[-1] != ':'):
+        return result_drive + '\\' + result_path
+    return result_drive + result_path
+
+
+if os.name == 'posix':
+    sep = altsep = '/'
+    risabs      = _posix_risabs
+    rabspath    = _posix_rabspath
+    rjoin       = _posix_rjoin
+elif os.name == 'nt':
+    sep, altsep = '\\', '/'
+    risabs      = _nt_risabs
+    rabspath    = _nt_rabspath
+    rsplitdrive = _nt_rsplitdrive
+    rjoin       = _nt_rjoin
 else:
     raise ImportError('Unsupported os: %s' % os.name)
diff --git a/rpython/rlib/test/test_rpath.py b/rpython/rlib/test/test_rpath.py
--- a/rpython/rlib/test/test_rpath.py
+++ b/rpython/rlib/test/test_rpath.py
@@ -2,17 +2,14 @@
 import os
 from rpython.rlib import rpath
 
-IS_WINDOWS = os.name == 'nt'
-
 def test_rabspath_relative(tmpdir):
     tmpdir.chdir()
     assert rpath.rabspath('foo') == os.path.realpath(str(tmpdir.join('foo')))
 
-@py.test.mark.skipif("IS_WINDOWS")
 def test_rabspath_absolute_posix():
-    assert rpath.rabspath('/foo') == '/foo'
+    assert rpath._posix_rabspath('/foo') == '/foo'
 
-@py.test.mark.skipif("IS_WINDOWS")
+@py.test.mark.skipif("os.name == 'nt'")
 def test_missing_current_dir(tmpdir):
     tmpdir1 = str(tmpdir) + '/temporary_removed'
     curdir1 = os.getcwd()
@@ -25,7 +22,25 @@
         os.chdir(curdir1)
     assert result == '.'
 
-@py.test.mark.skipif("not IS_WINDOWS")
+def test_rsplitdrive_nt():
+    assert rpath._nt_rsplitdrive('D:\\FOO/BAR') == ('D:', '\\FOO/BAR')
+    assert rpath._nt_rsplitdrive('//') == ('', '//')
+
+@py.test.mark.skipif("os.name != 'nt'")
 def test_rabspath_absolute_nt():
-    curdrive, _ = os.path.splitdrive(os.getcwd())
+    curdrive = _ = rpath._nt_rsplitdrive(os.getcwd())
+    assert len(curdrive) == 2 and curdrive[1] == ':'
     assert rpath.rabspath('\\foo') == '%s\\foo' % curdrive
+
+def test_risabs_posix():
+    assert rpath._posix_risabs('/foo/bar')
+    assert not rpath._posix_risabs('foo/bar')
+    assert not rpath._posix_risabs('\\foo\\bar')
+    assert not rpath._posix_risabs('C:\\foo\\bar')
+
+def test_risabs_nt():
+    assert rpath._nt_risabs('/foo/bar')
+    assert not rpath._nt_risabs('foo/bar')
+    assert rpath._nt_risabs('\\foo\\bar')
+    assert rpath._nt_risabs('C:\\FOO')
+    assert not rpath._nt_risabs('C:FOO')
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to