| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Generate fake repositories for testing.""" | 6 """Generate fake repositories for testing.""" |
| 7 | 7 |
| 8 import atexit | 8 import atexit |
| 9 import datetime | 9 import datetime |
| 10 import errno | |
| 11 import logging | 10 import logging |
| 12 import os | 11 import os |
| 13 import pprint | 12 import pprint |
| 14 import re | 13 import re |
| 15 import socket | 14 import socket |
| 16 import stat | |
| 17 import subprocess | 15 import subprocess |
| 18 import sys | 16 import sys |
| 19 import tempfile | 17 import tempfile |
| 20 import time | |
| 21 | 18 |
| 22 # trial_dir must be first for non-system libraries. | 19 # trial_dir must be first for non-system libraries. |
| 23 from tests import trial_dir | 20 from tests import trial_dir |
| 21 import gclient_utils |
| 24 import scm | 22 import scm |
| 25 | 23 |
| 26 ## Utility functions | 24 ## Utility functions |
| 27 | 25 |
| 28 | 26 |
| 29 def kill_pid(pid): | 27 def kill_pid(pid): |
| 30 """Kills a process by its process id.""" | 28 """Kills a process by its process id.""" |
| 31 try: | 29 try: |
| 32 # Unable to import 'module' | 30 # Unable to import 'module' |
| 33 # pylint: disable=F0401 | 31 # pylint: disable=F0401 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 59 return | 57 return |
| 60 | 58 |
| 61 if sys.platform == 'win32': | 59 if sys.platform == 'win32': |
| 62 subprocess.Popen.kill = kill_win | 60 subprocess.Popen.kill = kill_win |
| 63 else: | 61 else: |
| 64 def kill_nix(process): | 62 def kill_nix(process): |
| 65 return kill_pid(process.pid) | 63 return kill_pid(process.pid) |
| 66 subprocess.Popen.kill = kill_nix | 64 subprocess.Popen.kill = kill_nix |
| 67 | 65 |
| 68 | 66 |
| 69 def rmtree(*path): | |
| 70 """Recursively removes a directory, even if it's marked read-only. | |
| 71 | |
| 72 Remove the directory located at *path, if it exists. | |
| 73 | |
| 74 shutil.rmtree() doesn't work on Windows if any of the files or directories | |
| 75 are read-only, which svn repositories and some .svn files are. We need to | |
| 76 be able to force the files to be writable (i.e., deletable) as we traverse | |
| 77 the tree. | |
| 78 | |
| 79 Even with all this, Windows still sometimes fails to delete a file, citing | |
| 80 a permission error (maybe something to do with antivirus scans or disk | |
| 81 indexing). The best suggestion any of the user forums had was to wait a | |
| 82 bit and try again, so we do that too. It's hand-waving, but sometimes it | |
| 83 works. :/ | |
| 84 """ | |
| 85 file_path = os.path.join(*path) | |
| 86 if not os.path.exists(file_path): | |
| 87 return | |
| 88 | |
| 89 def RemoveWithRetry_win(rmfunc, path): | |
| 90 os.chmod(path, stat.S_IWRITE) | |
| 91 if win32_api_avail: | |
| 92 win32api.SetFileAttributes(path, win32con.FILE_ATTRIBUTE_NORMAL) | |
| 93 try: | |
| 94 return rmfunc(path) | |
| 95 except EnvironmentError, e: | |
| 96 if e.errno != errno.EACCES: | |
| 97 raise | |
| 98 print 'Failed to delete %s: trying again' % repr(path) | |
| 99 time.sleep(0.1) | |
| 100 return rmfunc(path) | |
| 101 | |
| 102 def RemoveWithRetry_non_win(rmfunc, path): | |
| 103 if os.path.islink(path): | |
| 104 return os.remove(path) | |
| 105 else: | |
| 106 return rmfunc(path) | |
| 107 | |
| 108 win32_api_avail = False | |
| 109 remove_with_retry = None | |
| 110 if sys.platform.startswith('win'): | |
| 111 # Some people don't have the APIs installed. In that case we'll do without. | |
| 112 try: | |
| 113 win32api = __import__('win32api') | |
| 114 win32con = __import__('win32con') | |
| 115 win32_api_avail = True | |
| 116 except ImportError: | |
| 117 pass | |
| 118 remove_with_retry = RemoveWithRetry_win | |
| 119 else: | |
| 120 remove_with_retry = RemoveWithRetry_non_win | |
| 121 | |
| 122 for root, dirs, files in os.walk(file_path, topdown=False): | |
| 123 # For POSIX: making the directory writable guarantees removability. | |
| 124 # Windows will ignore the non-read-only bits in the chmod value. | |
| 125 os.chmod(root, 0770) | |
| 126 for name in files: | |
| 127 remove_with_retry(os.remove, os.path.join(root, name)) | |
| 128 for name in dirs: | |
| 129 remove_with_retry(os.rmdir, os.path.join(root, name)) | |
| 130 | |
| 131 remove_with_retry(os.rmdir, file_path) | |
| 132 | |
| 133 | |
| 134 def write(path, content): | 67 def write(path, content): |
| 135 f = open(path, 'wb') | 68 f = open(path, 'wb') |
| 136 f.write(content) | 69 f.write(content) |
| 137 f.close() | 70 f.close() |
| 138 | 71 |
| 139 | 72 |
| 140 join = os.path.join | 73 join = os.path.join |
| 141 | 74 |
| 142 | 75 |
| 143 def check_call(*args, **kwargs): | 76 def check_call(*args, **kwargs): |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 self.trial = None | 235 self.trial = None |
| 303 | 236 |
| 304 def tear_down_svn(self): | 237 def tear_down_svn(self): |
| 305 if self.svnserve: | 238 if self.svnserve: |
| 306 logging.debug('Killing svnserve pid %s' % self.svnserve.pid) | 239 logging.debug('Killing svnserve pid %s' % self.svnserve.pid) |
| 307 self.svnserve.kill() | 240 self.svnserve.kill() |
| 308 self.wait_for_port_to_free(self.svn_port) | 241 self.wait_for_port_to_free(self.svn_port) |
| 309 self.svnserve = None | 242 self.svnserve = None |
| 310 if not self.trial.SHOULD_LEAK: | 243 if not self.trial.SHOULD_LEAK: |
| 311 logging.debug('Removing %s' % self.svn_repo) | 244 logging.debug('Removing %s' % self.svn_repo) |
| 312 rmtree(self.svn_repo) | 245 gclient_utils.rmtree(self.svn_repo) |
| 313 logging.debug('Removing %s' % self.svn_checkout) | 246 logging.debug('Removing %s' % self.svn_checkout) |
| 314 rmtree(self.svn_checkout) | 247 gclient_utils.rmtree(self.svn_checkout) |
| 315 else: | 248 else: |
| 316 return False | 249 return False |
| 317 return True | 250 return True |
| 318 | 251 |
| 319 def tear_down_git(self): | 252 def tear_down_git(self): |
| 320 if self.gitdaemon: | 253 if self.gitdaemon: |
| 321 logging.debug('Killing git-daemon pid %s' % self.gitdaemon.pid) | 254 logging.debug('Killing git-daemon pid %s' % self.gitdaemon.pid) |
| 322 self.gitdaemon.kill() | 255 self.gitdaemon.kill() |
| 323 self.gitdaemon = None | 256 self.gitdaemon = None |
| 324 if self.git_pid_file: | 257 if self.git_pid_file: |
| 325 pid = int(self.git_pid_file.read()) | 258 pid = int(self.git_pid_file.read()) |
| 326 self.git_pid_file.close() | 259 self.git_pid_file.close() |
| 327 logging.debug('Killing git daemon pid %s' % pid) | 260 logging.debug('Killing git daemon pid %s' % pid) |
| 328 kill_pid(pid) | 261 kill_pid(pid) |
| 329 self.git_pid_file = None | 262 self.git_pid_file = None |
| 330 self.wait_for_port_to_free(self.git_port) | 263 self.wait_for_port_to_free(self.git_port) |
| 331 if not self.trial.SHOULD_LEAK: | 264 if not self.trial.SHOULD_LEAK: |
| 332 logging.debug('Removing %s' % self.git_root) | 265 logging.debug('Removing %s' % self.git_root) |
| 333 rmtree(self.git_root) | 266 gclient_utils.rmtree(self.git_root) |
| 334 else: | 267 else: |
| 335 return False | 268 return False |
| 336 return True | 269 return True |
| 337 | 270 |
| 338 @staticmethod | 271 @staticmethod |
| 339 def _genTree(root, tree_dict): | 272 def _genTree(root, tree_dict): |
| 340 """For a dictionary of file contents, generate a filesystem.""" | 273 """For a dictionary of file contents, generate a filesystem.""" |
| 341 if not os.path.isdir(root): | 274 if not os.path.isdir(root): |
| 342 os.makedirs(root) | 275 os.makedirs(root) |
| 343 for (k, v) in tree_dict.iteritems(): | 276 for (k, v) in tree_dict.iteritems(): |
| (...skipping 450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 794 fake.set_up_git() | 727 fake.set_up_git() |
| 795 print('Fake setup, press enter to quit or Ctrl-C to keep the checkouts.') | 728 print('Fake setup, press enter to quit or Ctrl-C to keep the checkouts.') |
| 796 sys.stdin.readline() | 729 sys.stdin.readline() |
| 797 except KeyboardInterrupt: | 730 except KeyboardInterrupt: |
| 798 trial_dir.TrialDir.SHOULD_LEAK.leak = True | 731 trial_dir.TrialDir.SHOULD_LEAK.leak = True |
| 799 return 0 | 732 return 0 |
| 800 | 733 |
| 801 | 734 |
| 802 if __name__ == '__main__': | 735 if __name__ == '__main__': |
| 803 sys.exit(main(sys.argv)) | 736 sys.exit(main(sys.argv)) |
| OLD | NEW |