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 |