Index: tests/fake_repos.py |
=================================================================== |
--- tests/fake_repos.py (revision 48611) |
+++ tests/fake_repos.py (working copy) |
@@ -6,13 +6,15 @@ |
"""Generate fake repositories for testing.""" |
import atexit |
+import errno |
import logging |
import os |
import pprint |
import re |
-import shutil |
+import stat |
import subprocess |
import sys |
+import time |
import unittest |
@@ -35,12 +37,71 @@ |
subprocess.kill = kill_nix |
-def rmtree(path): |
- """Delete a directory.""" |
- if os.path.exists(path): |
- shutil.rmtree(path) |
+def rmtree(*path): |
+ """Recursively removes a directory, even if it's marked read-only. |
+ Remove the directory located at *path, if it exists. |
+ shutil.rmtree() doesn't work on Windows if any of the files or directories |
+ are read-only, which svn repositories and some .svn files are. We need to |
+ be able to force the files to be writable (i.e., deletable) as we traverse |
+ the tree. |
+ |
+ Even with all this, Windows still sometimes fails to delete a file, citing |
+ a permission error (maybe something to do with antivirus scans or disk |
+ indexing). The best suggestion any of the user forums had was to wait a |
+ bit and try again, so we do that too. It's hand-waving, but sometimes it |
+ works. :/ |
+ """ |
+ file_path = os.path.join(*path) |
+ if not os.path.exists(file_path): |
+ return |
+ |
+ def RemoveWithRetry_win(rmfunc, path): |
+ os.chmod(path, stat.S_IWRITE) |
+ if win32_api_avail: |
+ win32api.SetFileAttributes(path, win32con.FILE_ATTRIBUTE_NORMAL) |
+ try: |
+ return rmfunc(path) |
+ except EnvironmentError, e: |
+ if e.errno != errno.EACCES: |
+ raise |
+ print 'Failed to delete %s: trying again' % repr(path) |
+ time.sleep(0.1) |
+ return rmfunc(path) |
+ |
+ def RemoveWithRetry_non_win(rmfunc, path): |
+ if os.path.islink(path): |
+ return os.remove(path) |
+ else: |
+ return rmfunc(path) |
+ |
+ win32_api_avail = False |
+ remove_with_retry = None |
+ if sys.platform.startswith('win'): |
bradn
2010/06/01 01:12:04
Pretty sure this is always win32, but anyways. Did
M-A Ruel
2010/06/01 01:26:27
You are right, it's just a copy-paste from scripts
|
+ # Some people don't have the APIs installed. In that case we'll do without. |
+ try: |
+ win32api = __import__('win32api') |
+ win32con = __import__('win32con') |
+ win32_api_avail = True |
+ except ImportError: |
+ pass |
+ remove_with_retry = RemoveWithRetry_win |
+ else: |
+ remove_with_retry = RemoveWithRetry_non_win |
+ |
+ for root, dirs, files in os.walk(file_path, topdown=False): |
+ # For POSIX: making the directory writable guarantees removability. |
+ # Windows will ignore the non-read-only bits in the chmod value. |
+ os.chmod(root, 0770) |
+ for name in files: |
+ remove_with_retry(os.remove, os.path.join(root, name)) |
+ for name in dirs: |
+ remove_with_retry(os.rmdir, os.path.join(root, name)) |
+ |
+ remove_with_retry(os.rmdir, file_path) |
+ |
+ |
def write(path, content): |
f = open(path, 'wb') |
f.write(content) |
@@ -69,7 +130,9 @@ |
for d in filter(lambda x: x.startswith('.'), dirs): |
dirs.remove(d) |
for f in [join(root, f) for f in files if not f.startswith('.')]: |
- tree[f[len(tree_root) + 1:]] = open(join(root, f), 'rb').read() |
+ filepath = f[len(tree_root) + 1:].replace(os.sep, '/') |
+ assert len(filepath), f |
+ tree[filepath] = open(join(root, f), 'rU').read() |
return tree |
@@ -92,7 +155,7 @@ |
for k, v in tree.iteritems(): |
if not k.startswith(old_root): |
continue |
- result[join(new_root, k[len(old_root) + 1:])] = v |
+ result[join(new_root, k[len(old_root) + 1:]).replace(os.sep, '/')] = v |
return result |
@@ -330,8 +393,10 @@ |
def setUpGIT(self): |
"""Creates git repositories and start the servers.""" |
if self.gitdaemon: |
- return |
+ return True |
self.setUp() |
+ if sys.platform == 'win32': |
+ return False |
for repo in ['repo_%d' % r for r in range(1, 5)]: |
check_call(['git', 'init', '-q', join(self.git_root, repo)]) |
self.git_hashes[repo] = [] |
@@ -424,6 +489,7 @@ |
cmd.append('--listen=127.0.0.1') |
logging.debug(cmd) |
self.gitdaemon = Popen(cmd, cwd=self.repos_dir) |
+ return True |
def _commit_svn(self, tree): |
self._genTree(self.svn_root, tree) |