Commits

philip_thiem committed f2e84bb

Fixed Issue #125: setuptools leaves a ~/.subversion dir laying around
after it completes
This is the best that can probably be done. Temporary directories are used
for get the svn binary version and to get the initial directory info (for
determining if one is, in fact, in a svn working directory)

ALSO: The check for SVN was not right. Decided on files to only check for
.svn/entries because missing properties just leaves out the external refs.
And then incorporated a test on the code to make sure that svn info completed.

Test passed on CPytonh 2.x and 2.3 on windows, travis-ci, and travis-ci/mac.
Note: There seems to be an issue with pypy and a test.

Comments (0)

Files changed (1)

setuptools/svn_utils.py

 from distutils import log
 import xml.dom.pulldom
 import shlex
+import shutil
+import tempfile
 import locale
 import codecs
 import unicodedata
 #       http://stackoverflow.com/questions/5658622/
 #              python-subprocess-popen-environment-path
 
+class TempDir(object):
+    """"
+    Very simple temporary directory context manager.
+    Will try to delete afterward, but will also ignore OS and similar
+    errors on deletion.
+    """
+    def __init__(self):
+        self.path = None
+
+    def __enter__(self):
+        self.path = tempfile.mkdtemp()
+        return self
+
+    def __exit__(self, exctype, excvalue, exctrace):
+        try:
+            shutil.rmtree(self.path, True)
+        except OSError: #removal errors are not the only possible
+            pass
+        self.path = None
 
 def _run_command(args, stdout=_PIPE, stderr=_PIPE, encoding=None, stream=0):
     #regarding the shell argument, see: http://bugs.python.org/issue8557
 
     @staticmethod
     def get_svn_version():
-        code, data = _run_command(['svn', '--version', '--quiet'])
+        # Temp config directory should be enough to check for repository
+        # This is needed because .svn always creates .subversion and 
+        # some operating systems do not handle dot directory correctly.
+        # Real queries in real svn repos with be concerned with it creation
+        with TempDir() as tempdir:
+            code, data = _run_command(['svn', 
+                                       '--config-dir', tempdir.path,
+                                       '--version', 
+                                       '--quiet'])
+
         if code == 0 and data:
             return data.strip()
         else:
     @classmethod
     def load(cls, dirname=''):
         normdir = os.path.normpath(dirname)
-        code, data = _run_command(['svn', 'info', normdir])
+
+        # Temp config directory should be enough to check for repository
+        # This is needed because .svn always creates .subversion and 
+        # some operating systems do not handle dot directory correctly.
+        # Real queries in real svn repos with be concerned with it creation
+        with TempDir() as tempdir:
+            code, data = _run_command(['svn', 
+                                       '--config-dir', tempdir.path,
+                                       'info', normdir])
+
         # Must check for some contents, as some use empty directories
-        # in testcases
+        # in testcases, however only enteries is needed also the info
+        # command above MUST have worked
         svn_dir = os.path.join(normdir, '.svn')
-        has_svn = (os.path.isfile(os.path.join(svn_dir, 'entries')) or
-                   os.path.isfile(os.path.join(svn_dir, 'dir-props')) or
-                   os.path.isfile(os.path.join(svn_dir, 'dir-prop-base')))
+        is_svn_wd = (not code or
+                     os.path.isfile(os.path.join(svn_dir, 'entries')))
 
         svn_version = tuple(cls.get_svn_version().split('.'))
 
         except ValueError:
             base_svn_version = tuple()
 
-        if not has_svn:
+        if not is_svn_wd:
+            #return an instance of this NO-OP class
             return SvnInfo(dirname)
 
         if code or not base_svn_version or base_svn_version < (1, 3):