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 errno | |
9 import logging | 10 import logging |
10 import os | 11 import os |
11 import pprint | 12 import pprint |
12 import re | 13 import re |
13 import shutil | 14 import stat |
14 import subprocess | 15 import subprocess |
15 import sys | 16 import sys |
17 import time | |
16 import unittest | 18 import unittest |
17 | 19 |
18 | 20 |
19 ## Utility functions | 21 ## Utility functions |
20 | 22 |
21 | 23 |
22 def addKill(): | 24 def addKill(): |
23 """Add kill() method to subprocess.Popen for python <2.6""" | 25 """Add kill() method to subprocess.Popen for python <2.6""" |
24 if getattr(subprocess.Popen, 'kill', None): | 26 if getattr(subprocess.Popen, 'kill', None): |
25 return | 27 return |
26 if sys.platform.startswith('win'): | 28 if sys.platform.startswith('win'): |
27 def kill_win(process): | 29 def kill_win(process): |
28 import win32process | 30 import win32process |
29 return win32process.TerminateProcess(process._handle, -1) | 31 return win32process.TerminateProcess(process._handle, -1) |
30 subprocess.kill = kill_win | 32 subprocess.kill = kill_win |
31 else: | 33 else: |
32 def kill_nix(process): | 34 def kill_nix(process): |
33 import signal | 35 import signal |
34 return os.kill(process.pid, signal.SIGKILL) | 36 return os.kill(process.pid, signal.SIGKILL) |
35 subprocess.kill = kill_nix | 37 subprocess.kill = kill_nix |
36 | 38 |
37 | 39 |
38 def rmtree(path): | 40 def rmtree(*path): |
39 """Delete a directory.""" | 41 """Recursively removes a directory, even if it's marked read-only. |
40 if os.path.exists(path): | 42 |
41 shutil.rmtree(path) | 43 Remove the directory located at *path, if it exists. |
44 | |
45 shutil.rmtree() doesn't work on Windows if any of the files or directories | |
46 are read-only, which svn repositories and some .svn files are. We need to | |
47 be able to force the files to be writable (i.e., deletable) as we traverse | |
48 the tree. | |
49 | |
50 Even with all this, Windows still sometimes fails to delete a file, citing | |
51 a permission error (maybe something to do with antivirus scans or disk | |
52 indexing). The best suggestion any of the user forums had was to wait a | |
53 bit and try again, so we do that too. It's hand-waving, but sometimes it | |
54 works. :/ | |
55 """ | |
56 file_path = os.path.join(*path) | |
57 if not os.path.exists(file_path): | |
58 return | |
59 | |
60 def RemoveWithRetry_win(rmfunc, path): | |
61 os.chmod(path, stat.S_IWRITE) | |
62 if win32_api_avail: | |
63 win32api.SetFileAttributes(path, win32con.FILE_ATTRIBUTE_NORMAL) | |
64 try: | |
65 return rmfunc(path) | |
66 except EnvironmentError, e: | |
67 if e.errno != errno.EACCES: | |
68 raise | |
69 print 'Failed to delete %s: trying again' % repr(path) | |
70 time.sleep(0.1) | |
71 return rmfunc(path) | |
72 | |
73 def RemoveWithRetry_non_win(rmfunc, path): | |
74 if os.path.islink(path): | |
75 return os.remove(path) | |
76 else: | |
77 return rmfunc(path) | |
78 | |
79 win32_api_avail = False | |
80 remove_with_retry = None | |
81 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
| |
82 # Some people don't have the APIs installed. In that case we'll do without. | |
83 try: | |
84 win32api = __import__('win32api') | |
85 win32con = __import__('win32con') | |
86 win32_api_avail = True | |
87 except ImportError: | |
88 pass | |
89 remove_with_retry = RemoveWithRetry_win | |
90 else: | |
91 remove_with_retry = RemoveWithRetry_non_win | |
92 | |
93 for root, dirs, files in os.walk(file_path, topdown=False): | |
94 # For POSIX: making the directory writable guarantees removability. | |
95 # Windows will ignore the non-read-only bits in the chmod value. | |
96 os.chmod(root, 0770) | |
97 for name in files: | |
98 remove_with_retry(os.remove, os.path.join(root, name)) | |
99 for name in dirs: | |
100 remove_with_retry(os.rmdir, os.path.join(root, name)) | |
101 | |
102 remove_with_retry(os.rmdir, file_path) | |
42 | 103 |
43 | 104 |
44 def write(path, content): | 105 def write(path, content): |
45 f = open(path, 'wb') | 106 f = open(path, 'wb') |
46 f.write(content) | 107 f.write(content) |
47 f.close() | 108 f.close() |
48 | 109 |
49 | 110 |
50 join = os.path.join | 111 join = os.path.join |
51 | 112 |
(...skipping 10 matching lines...) Expand all Loading... | |
62 return subprocess.Popen(*args, **kwargs) | 123 return subprocess.Popen(*args, **kwargs) |
63 | 124 |
64 | 125 |
65 def read_tree(tree_root): | 126 def read_tree(tree_root): |
66 """Returns a dict of all the files in a tree. Defaults to self.root_dir.""" | 127 """Returns a dict of all the files in a tree. Defaults to self.root_dir.""" |
67 tree = {} | 128 tree = {} |
68 for root, dirs, files in os.walk(tree_root): | 129 for root, dirs, files in os.walk(tree_root): |
69 for d in filter(lambda x: x.startswith('.'), dirs): | 130 for d in filter(lambda x: x.startswith('.'), dirs): |
70 dirs.remove(d) | 131 dirs.remove(d) |
71 for f in [join(root, f) for f in files if not f.startswith('.')]: | 132 for f in [join(root, f) for f in files if not f.startswith('.')]: |
72 tree[f[len(tree_root) + 1:]] = open(join(root, f), 'rb').read() | 133 filepath = f[len(tree_root) + 1:].replace(os.sep, '/') |
134 assert len(filepath), f | |
135 tree[filepath] = open(join(root, f), 'rU').read() | |
73 return tree | 136 return tree |
74 | 137 |
75 | 138 |
76 def dict_diff(dict1, dict2): | 139 def dict_diff(dict1, dict2): |
77 diff = {} | 140 diff = {} |
78 for k, v in dict1.iteritems(): | 141 for k, v in dict1.iteritems(): |
79 if k not in dict2: | 142 if k not in dict2: |
80 diff[k] = v | 143 diff[k] = v |
81 elif v != dict2[k]: | 144 elif v != dict2[k]: |
82 diff[k] = (v, dict2[k]) | 145 diff[k] = (v, dict2[k]) |
83 for k, v in dict2.iteritems(): | 146 for k, v in dict2.iteritems(): |
84 if k not in dict1: | 147 if k not in dict1: |
85 diff[k] = v | 148 diff[k] = v |
86 return diff | 149 return diff |
87 | 150 |
88 | 151 |
89 def mangle_svn_tree(*args): | 152 def mangle_svn_tree(*args): |
90 result = {} | 153 result = {} |
91 for old_root, new_root, tree in args: | 154 for old_root, new_root, tree in args: |
92 for k, v in tree.iteritems(): | 155 for k, v in tree.iteritems(): |
93 if not k.startswith(old_root): | 156 if not k.startswith(old_root): |
94 continue | 157 continue |
95 result[join(new_root, k[len(old_root) + 1:])] = v | 158 result[join(new_root, k[len(old_root) + 1:]).replace(os.sep, '/')] = v |
96 return result | 159 return result |
97 | 160 |
98 | 161 |
99 def mangle_git_tree(*args): | 162 def mangle_git_tree(*args): |
100 result = {} | 163 result = {} |
101 for new_root, tree in args: | 164 for new_root, tree in args: |
102 for k, v in tree.iteritems(): | 165 for k, v in tree.iteritems(): |
103 result[join(new_root, k)] = v | 166 result[join(new_root, k)] = v |
104 return result | 167 return result |
105 | 168 |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
323 'pattern': 'nonexistent', | 386 'pattern': 'nonexistent', |
324 'action': ['python', '-c', | 387 'action': ['python', '-c', |
325 'open(\\'src/svn_hooked2\\', \\'w\\').write(\\'svn_hooked2\\')'], | 388 'open(\\'src/svn_hooked2\\', \\'w\\').write(\\'svn_hooked2\\')'], |
326 }, | 389 }, |
327 ] | 390 ] |
328 """ % { 'host': self.HOST })) | 391 """ % { 'host': self.HOST })) |
329 | 392 |
330 def setUpGIT(self): | 393 def setUpGIT(self): |
331 """Creates git repositories and start the servers.""" | 394 """Creates git repositories and start the servers.""" |
332 if self.gitdaemon: | 395 if self.gitdaemon: |
333 return | 396 return True |
334 self.setUp() | 397 self.setUp() |
398 if sys.platform == 'win32': | |
399 return False | |
335 for repo in ['repo_%d' % r for r in range(1, 5)]: | 400 for repo in ['repo_%d' % r for r in range(1, 5)]: |
336 check_call(['git', 'init', '-q', join(self.git_root, repo)]) | 401 check_call(['git', 'init', '-q', join(self.git_root, repo)]) |
337 self.git_hashes[repo] = [] | 402 self.git_hashes[repo] = [] |
338 | 403 |
339 # Testing: | 404 # Testing: |
340 # - dependency disapear | 405 # - dependency disapear |
341 # - dependency renamed | 406 # - dependency renamed |
342 # - versioned and unversioned reference | 407 # - versioned and unversioned reference |
343 # - relative and full reference | 408 # - relative and full reference |
344 # - deps_os | 409 # - deps_os |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
417 }, | 482 }, |
418 'origin': "git/repo_1@2\n" | 483 'origin': "git/repo_1@2\n" |
419 }) | 484 }) |
420 | 485 |
421 # Start the daemon. | 486 # Start the daemon. |
422 cmd = ['git', 'daemon', '--export-all', '--base-path=' + self.repos_dir] | 487 cmd = ['git', 'daemon', '--export-all', '--base-path=' + self.repos_dir] |
423 if self.HOST == '127.0.0.1': | 488 if self.HOST == '127.0.0.1': |
424 cmd.append('--listen=127.0.0.1') | 489 cmd.append('--listen=127.0.0.1') |
425 logging.debug(cmd) | 490 logging.debug(cmd) |
426 self.gitdaemon = Popen(cmd, cwd=self.repos_dir) | 491 self.gitdaemon = Popen(cmd, cwd=self.repos_dir) |
492 return True | |
427 | 493 |
428 def _commit_svn(self, tree): | 494 def _commit_svn(self, tree): |
429 self._genTree(self.svn_root, tree) | 495 self._genTree(self.svn_root, tree) |
430 commit_svn(self.svn_root) | 496 commit_svn(self.svn_root) |
431 if self.svn_revs and self.svn_revs[-1]: | 497 if self.svn_revs and self.svn_revs[-1]: |
432 new_tree = self.svn_revs[-1].copy() | 498 new_tree = self.svn_revs[-1].copy() |
433 new_tree.update(tree) | 499 new_tree.update(tree) |
434 else: | 500 else: |
435 new_tree = tree.copy() | 501 new_tree = tree.copy() |
436 self.svn_revs.append(new_tree) | 502 self.svn_revs.append(new_tree) |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
511 fake.setUp() | 577 fake.setUp() |
512 print('Fake setup, press enter to quit or Ctrl-C to keep the checkouts.') | 578 print('Fake setup, press enter to quit or Ctrl-C to keep the checkouts.') |
513 sys.stdin.readline() | 579 sys.stdin.readline() |
514 except KeyboardInterrupt: | 580 except KeyboardInterrupt: |
515 fake.SHOULD_LEAK = True | 581 fake.SHOULD_LEAK = True |
516 return 0 | 582 return 0 |
517 | 583 |
518 | 584 |
519 if __name__ == '__main__': | 585 if __name__ == '__main__': |
520 sys.exit(main(sys.argv)) | 586 sys.exit(main(sys.argv)) |
OLD | NEW |