changeset 484:c2d0e738c899

Merge win32 fixes
author Augie Fackler <durin42@gmail.com>
date Sat, 08 Aug 2009 08:01:24 -0500
parents 3855865ba53d (current diff) 37718f514acb (diff)
children c07bcdc6e1bd
files tests/test_push_command.py
diffstat 3 files changed, 75 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/tests/test_push_command.py
+++ b/tests/test_push_command.py
@@ -131,7 +131,8 @@ class PushTests(test_util.TestBase):
             self.assertNotEqual('an_author', tip.user())
             self.assertEqual('None', tip.user().rsplit('@', 1)[0])
         finally:
-            os.kill(self.svnserve_pid, 9)
+            # TODO: use svnserve.kill() in Python >2.5
+            test_util.kill_process(svnserve)
 
     def test_push_to_default(self, commit=True):
         repo = self.repo
--- a/tests/test_svnwrap.py
+++ b/tests/test_svnwrap.py
@@ -9,23 +9,33 @@ import test_util
 
 from hgsubversion import svnwrap
 
+import os
+import stat
+def force_rm(path):
+    os.chmod(
+        path,
+        os.stat(path).st_mode | stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH
+    )
+    os.remove(path)
+
 class TestBasicRepoLayout(unittest.TestCase):
     def setUp(self):
         self.tmpdir = tempfile.mkdtemp('svnwrap_test')
         self.repo_path = '%s/testrepo' % self.tmpdir
-        os.spawnvp(os.P_WAIT, 'svnadmin', ['svnadmin', 'create',
-                                           self.repo_path,])
+        subprocess.call(['svnadmin', 'create', self.repo_path,])
         inp = open(os.path.join(os.path.dirname(__file__), 'fixtures',
                                 'project_root_at_repo_root.svndump'))
         proc = subprocess.call(['svnadmin', 'load', self.repo_path,],
-                                stdin=inp, close_fds=True,
+                                stdin=inp,
+                                close_fds=test_util.canCloseFds,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.STDOUT)
         assert proc == 0
-        self.repo = svnwrap.SubversionRepo('file://%s' % self.repo_path)
+        self.repo = svnwrap.SubversionRepo(test_util.fileurl(self.repo_path))
 
     def tearDown(self):
-        shutil.rmtree(self.tmpdir)
+        del self.repo
+        shutil.rmtree(self.tmpdir, onerror=lambda func, path, e: force_rm(path))
 
 
     def test_num_revs(self):
@@ -59,17 +69,19 @@ class TestRootAsSubdirOfRepo(TestBasicRe
     def setUp(self):
         self.tmpdir = tempfile.mkdtemp('svnwrap_test')
         self.repo_path = '%s/testrepo' % self.tmpdir
-        os.spawnvp(os.P_WAIT, 'svnadmin', ['svnadmin', 'create',
-                                           self.repo_path,])
+        subprocess.call(['svnadmin', 'create', self.repo_path,])
         inp = open(os.path.join(os.path.dirname(__file__), 'fixtures',
                                 'project_root_not_repo_root.svndump'))
         ret = subprocess.call(['svnadmin', 'load', self.repo_path,],
-                              stdin=inp, close_fds=True,
+                              stdin=inp,
+                              close_fds=test_util.canCloseFds,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.STDOUT)
         assert ret == 0
-        self.repo = svnwrap.SubversionRepo('file://%s/dummyproj' %
-                                           self.repo_path)
+        self.repo = svnwrap.SubversionRepo(test_util.fileurl(
+            self.repo_path + '/dummyproj'
+        ))
+
 def suite():
     all = [unittest.TestLoader().loadTestsFromTestCase(TestBasicRepoLayout),
            unittest.TestLoader().loadTestsFromTestCase(TestRootAsSubdirOfRepo)]
--- a/tests/test_util.py
+++ b/tests/test_util.py
@@ -19,6 +19,57 @@ from mercurial import ui
 
 from hgsubversion import util
 
+import sys
+# Documentation for Subprocess.Popen() says:
+#   "Note that on Windows, you cannot set close_fds to true and
+#   also redirect the standard handles by setting stdin, stdout or
+#   stderr."
+canCloseFds='win32' not in sys.platform
+
+if not 'win32' in sys.platform:
+    def kill_process(popen_obj):
+        os.kill(popen_obj.pid, 9)
+else:
+    import ctypes
+    from ctypes.wintypes import BOOL, DWORD, HANDLE, UINT
+
+    def win_status_check(result, func, args):
+        if result == 0:
+            raise ctypes.WinError()
+        return args
+
+    def WINAPI(returns, func, *params):
+        assert len(params) % 2 == 0
+    
+        func.argtypes = tuple(params[0::2])
+        func.resvalue = returns
+        func.errcheck = win_status_check
+
+        return func
+
+    # dwDesiredAccess
+    PROCESS_TERMINATE = 0x0001
+
+    OpenProcess = WINAPI(HANDLE, ctypes.windll.kernel32.OpenProcess,
+        DWORD, 'dwDesiredAccess',
+        BOOL, 'bInheritHandle',
+        DWORD, 'dwProcessId',
+    )
+
+    CloseHandle =  WINAPI(BOOL, ctypes.windll.kernel32.CloseHandle,
+        HANDLE, 'hObject'
+    )
+
+    TerminateProcess = WINAPI(BOOL, ctypes.windll.kernel32.TerminateProcess,
+        HANDLE, 'hProcess',
+        UINT, 'uExitCode'
+    )
+
+    def kill_process(popen_obj):
+        phnd = OpenProcess(PROCESS_TERMINATE, False, popen_obj.pid)
+        TerminateProcess(phnd, 1)
+        CloseHandle(phnd)
+
 # Fixtures that need to be pulled at a subdirectory of the repo path
 subdir = {'truncatedhistory.svndump': '/project2',
           'fetch_missing_files_subdir.svndump': '/foo',