From: david-sarah <david-sarah@jacaranda.org>
Date: Wed, 21 Jul 2010 23:15:07 +0000 (-0700)
Subject: util.fileutil, test.test_util: add abspath_expanduser_unicode function, to work aroun... 
X-Git-Tag: allmydata-tahoe-1.8.0b2~71
X-Git-Url: https://git.rkrishnan.org/%5B/%5D%20/uri/%22doc.html/install.html?a=commitdiff_plain;h=11b18824c7ff3237f4ed0122bcb24fe10b076be0;p=tahoe-lafs%2Ftahoe-lafs.git

util.fileutil, test.test_util: add abspath_expanduser_unicode function, to work around <http://bugs.python.org/issue3426>. util.encodingutil: add a convenience function argv_to_abspath.
---

diff --git a/src/allmydata/test/test_util.py b/src/allmydata/test/test_util.py
index 0a326b36..6ba9ff66 100644
--- a/src/allmydata/test/test_util.py
+++ b/src/allmydata/test/test_util.py
@@ -1,7 +1,7 @@
 
 def foo(): pass # keep the line number constant
 
-import os, time
+import os, time, sys
 from StringIO import StringIO
 from twisted.trial import unittest
 from twisted.internet import defer, reactor
@@ -470,6 +470,37 @@ class FileUtil(unittest.TestCase):
         used = fileutil.du(basedir)
         self.failUnlessEqual(10+11+12+13, used)
 
+    def test_abspath_expanduser_unicode(self):
+        self.failUnlessRaises(AssertionError, fileutil.abspath_expanduser_unicode, "bytestring")
+
+        saved_cwd = os.path.normpath(os.getcwdu())
+        abspath_cwd = fileutil.abspath_expanduser_unicode(u".")
+        self.failUnless(isinstance(saved_cwd, unicode), saved_cwd)
+        self.failUnless(isinstance(abspath_cwd, unicode), abspath_cwd)
+        self.failUnlessEqual(abspath_cwd, saved_cwd)
+
+        # adapted from <http://svn.python.org/view/python/branches/release26-maint/Lib/test/test_posixpath.py?view=markup&pathrev=78279#test_abspath>
+
+        self.failUnlessIn(u"foo", fileutil.abspath_expanduser_unicode(u"foo"))
+        self.failIfIn(u"~", fileutil.abspath_expanduser_unicode(u"~"))
+
+        cwds = ['cwd']
+        try:
+            cwds.append(u'\xe7w\xf0'.encode(sys.getfilesystemencoding()
+                                            or 'ascii'))
+        except UnicodeEncodeError:
+            pass # the cwd can't be encoded -- test with ascii cwd only
+
+        for cwd in cwds:
+            try:
+                os.mkdir(cwd)
+                os.chdir(cwd)
+                for upath in (u'', u'fuu', u'f\xf9\xf9', u'/fuu', u'U:\\', u'~'):
+                    uabspath = fileutil.abspath_expanduser_unicode(upath)
+                    self.failUnless(isinstance(uabspath, unicode), uabspath)
+            finally:
+                os.chdir(saved_cwd)
+
 class PollMixinTests(unittest.TestCase):
     def setUp(self):
         self.pm = pollmixin.PollMixin()
diff --git a/src/allmydata/util/encodingutil.py b/src/allmydata/util/encodingutil.py
index e5787851..d2a65852 100644
--- a/src/allmydata/util/encodingutil.py
+++ b/src/allmydata/util/encodingutil.py
@@ -10,6 +10,7 @@ from allmydata.util.assertutil import precondition
 from twisted.python import usage
 import locale
 from allmydata.util import log
+from allmydata.util.fileutil import abspath_expanduser_unicode
 
 
 def _canonical_encoding(encoding):
@@ -91,6 +92,13 @@ def argv_to_unicode(s):
         raise usage.UsageError("Argument %s cannot be decoded as %s." %
                                (quote_output(s), argv_encoding))
 
+def argv_to_abspath(s):
+    """
+    Convenience function to decode an argv element to an absolute path, with ~ expanded.
+    If this fails, raise a UsageError.
+    """
+    return abspath_expanduser_unicode(argv_to_unicode(s))
+
 def unicode_to_url(s):
     """
     Encode an unicode object used in an URL.
diff --git a/src/allmydata/util/fileutil.py b/src/allmydata/util/fileutil.py
index cf0cb66a..a6b59bc8 100644
--- a/src/allmydata/util/fileutil.py
+++ b/src/allmydata/util/fileutil.py
@@ -272,3 +272,35 @@ def put_file(pathname, inf):
             outf.write(data)
     finally:
         outf.close()
+
+
+# Work around <http://bugs.python.org/issue3426>. This code is adapted from
+# <http://svn.python.org/view/python/trunk/Lib/ntpath.py?revision=78247&view=markup>
+# with some simplifications.
+
+_getfullpathname = None
+try:
+    from nt import _getfullpathname
+except ImportError:
+    pass
+
+def abspath_expanduser_unicode(path):
+    """Return the absolute version of a path."""
+    assert isinstance(path, unicode), path
+
+    path = os.path.expanduser(path)
+
+    if _getfullpathname:
+        # On Windows, os.path.isabs will return True for paths without a drive letter,
+        # e.g. "\\". See <http://bugs.python.org/issue1669539>.
+        try:
+            path = _getfullpathname(path or u".")
+        except WindowsError:
+            pass
+
+    if not os.path.isabs(path):
+        path = os.path.join(os.getcwdu(), path)
+
+    # We won't hit <http://bugs.python.org/issue5827> because
+    # there is always at least one Unicode path component.
+    return os.path.normpath(path)