OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 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 | 10 import errno |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
52 if k not in dict2: | 52 if k not in dict2: |
53 diff[k] = v | 53 diff[k] = v |
54 elif v != dict2[k]: | 54 elif v != dict2[k]: |
55 diff[k] = (v, dict2[k]) | 55 diff[k] = (v, dict2[k]) |
56 for k, v in dict2.iteritems(): | 56 for k, v in dict2.iteritems(): |
57 if k not in dict1: | 57 if k not in dict1: |
58 diff[k] = v | 58 diff[k] = v |
59 return diff | 59 return diff |
60 | 60 |
61 | 61 |
62 def commit_svn(repo, usr, pwd): | |
63 """Commits the changes and returns the new revision number.""" | |
64 to_add = [] | |
65 to_remove = [] | |
66 for status, filepath in scm.SVN.CaptureStatus(None, repo): | |
67 if status[0] == '?': | |
68 to_add.append(filepath) | |
69 elif status[0] == '!': | |
70 to_remove.append(filepath) | |
71 if to_add: | |
72 subprocess2.check_output( | |
73 ['svn', 'add', '--no-auto-props', '-q'] + to_add, cwd=repo) | |
74 if to_remove: | |
75 subprocess2.check_output(['svn', 'remove', '-q'] + to_remove, cwd=repo) | |
76 | |
77 out = subprocess2.check_output( | |
78 ['svn', 'commit', repo, '-m', 'foo', '--non-interactive', | |
79 '--no-auth-cache', | |
80 '--username', usr, '--password', pwd], | |
81 cwd=repo) | |
82 match = re.search(r'(\d+)', out) | |
83 if not match: | |
84 raise Exception('Commit failed', out) | |
85 rev = match.group(1) | |
86 status = subprocess2.check_output(['svn', 'status'], cwd=repo) | |
87 assert len(status) == 0, status | |
88 logging.debug('At revision %s' % rev) | |
89 return rev | |
90 | |
91 | |
92 def commit_git(repo): | 62 def commit_git(repo): |
93 """Commits the changes and returns the new hash.""" | 63 """Commits the changes and returns the new hash.""" |
94 subprocess2.check_call(['git', 'add', '-A', '-f'], cwd=repo) | 64 subprocess2.check_call(['git', 'add', '-A', '-f'], cwd=repo) |
95 subprocess2.check_call(['git', 'commit', '-q', '--message', 'foo'], cwd=repo) | 65 subprocess2.check_call(['git', 'commit', '-q', '--message', 'foo'], cwd=repo) |
96 rev = subprocess2.check_output( | 66 rev = subprocess2.check_output( |
97 ['git', 'show-ref', '--head', 'HEAD'], cwd=repo).split(' ', 1)[0] | 67 ['git', 'show-ref', '--head', 'HEAD'], cwd=repo).split(' ', 1)[0] |
98 logging.debug('At revision %s' % rev) | 68 logging.debug('At revision %s' % rev) |
99 return rev | 69 return rev |
100 | 70 |
101 | 71 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
155 logging.debug('%d was bound, waiting to free' % port) | 125 logging.debug('%d was bound, waiting to free' % port) |
156 except (socket.error, EnvironmentError): | 126 except (socket.error, EnvironmentError): |
157 logging.debug('%d now free' % port) | 127 logging.debug('%d now free' % port) |
158 return | 128 return |
159 finally: | 129 finally: |
160 sock.close() | 130 sock.close() |
161 assert False, '%d is still bound' % port | 131 assert False, '%d is still bound' % port |
162 | 132 |
163 | 133 |
164 class FakeReposBase(object): | 134 class FakeReposBase(object): |
165 """Generate both svn and git repositories to test gclient functionality. | 135 """Generategit repositories to test gclient functionality. |
iannucci
2015/05/26 18:36:43
typo
M-A Ruel
2015/05/26 19:15:49
Done.
| |
166 | 136 |
167 Many DEPS functionalities need to be tested: Var, File, From, deps_os, hooks, | 137 Many DEPS functionalities need to be tested: Var, File, From, deps_os, hooks, |
168 use_relative_paths. | 138 use_relative_paths. |
169 | 139 |
170 And types of dependencies: Relative urls, Full urls, both svn and git. | 140 And types of dependencies: Relative urls, Full urls, git. |
171 | 141 |
172 populateSvn() and populateGit() need to be implemented by the subclass. | 142 populateGit() needs to be implemented by the subclass. |
173 """ | 143 """ |
174 # Hostname | 144 # Hostname |
175 NB_GIT_REPOS = 1 | 145 NB_GIT_REPOS = 1 |
176 USERS = [ | 146 USERS = [ |
177 ('user1@example.com', 'foo'), | 147 ('user1@example.com', 'foo'), |
178 ('user2@example.com', 'bar'), | 148 ('user2@example.com', 'bar'), |
179 ] | 149 ] |
180 | 150 |
181 def __init__(self, host=None): | 151 def __init__(self, host=None): |
182 self.trial = trial_dir.TrialDir('repos') | 152 self.trial = trial_dir.TrialDir('repos') |
183 self.host = host or '127.0.0.1' | 153 self.host = host or '127.0.0.1' |
184 # Format is [ None, tree, tree, ...] | |
185 # i.e. revisions are 1-based. | |
186 self.svn_revs = [None] | |
187 # Format is { repo: [ None, (hash, tree), (hash, tree), ... ], ... } | 154 # Format is { repo: [ None, (hash, tree), (hash, tree), ... ], ... } |
188 # so reference looks like self.git_hashes[repo][rev][0] for hash and | 155 # so reference looks like self.git_hashes[repo][rev][0] for hash and |
189 # self.git_hashes[repo][rev][1] for it's tree snapshot. | 156 # self.git_hashes[repo][rev][1] for it's tree snapshot. |
190 # For consistency with self.svn_revs, it is 1-based too. | 157 # It is 1-based too. |
191 self.git_hashes = {} | 158 self.git_hashes = {} |
192 self.svnserve = None | |
193 self.gitdaemon = None | 159 self.gitdaemon = None |
194 self.git_pid_file = None | 160 self.git_pid_file = None |
195 self.git_root = None | 161 self.git_root = None |
196 self.svn_checkout = None | |
197 self.svn_repo = None | |
198 self.git_dirty = False | 162 self.git_dirty = False |
199 self.svn_dirty = False | |
200 self.svn_port = None | |
201 self.git_port = None | 163 self.git_port = None |
202 self.svn_base = None | |
203 self.git_base = None | 164 self.git_base = None |
204 | 165 |
205 @property | 166 @property |
206 def root_dir(self): | 167 def root_dir(self): |
207 return self.trial.root_dir | 168 return self.trial.root_dir |
208 | 169 |
209 def set_up(self): | 170 def set_up(self): |
210 """All late initialization comes here.""" | 171 """All late initialization comes here.""" |
211 self.cleanup_dirt() | 172 self.cleanup_dirt() |
212 if not self.root_dir: | 173 if not self.root_dir: |
213 try: | 174 try: |
214 # self.root_dir is not set before this call. | 175 # self.root_dir is not set before this call. |
215 self.trial.set_up() | 176 self.trial.set_up() |
216 self.git_root = join(self.root_dir, 'git') | 177 self.git_root = join(self.root_dir, 'git') |
217 self.svn_checkout = join(self.root_dir, 'svn_checkout') | |
218 self.svn_repo = join(self.root_dir, 'svn') | |
219 finally: | 178 finally: |
220 # Registers cleanup. | 179 # Registers cleanup. |
221 atexit.register(self.tear_down) | 180 atexit.register(self.tear_down) |
222 | 181 |
223 def cleanup_dirt(self): | 182 def cleanup_dirt(self): |
224 """For each dirty repository, destroy it.""" | 183 """For each dirty repository, destroy it.""" |
225 if self.svn_dirty: | |
226 if not self.tear_down_svn(): | |
227 logging.error('Using both leaking checkout and svn dirty checkout') | |
228 if self.git_dirty: | 184 if self.git_dirty: |
229 if not self.tear_down_git(): | 185 if not self.tear_down_git(): |
230 logging.error('Using both leaking checkout and git dirty checkout') | 186 logging.error('Using both leaking checkout and git dirty checkout') |
231 | 187 |
232 def tear_down(self): | 188 def tear_down(self): |
233 """Kills the servers and delete the directories.""" | 189 """Kills the servers and delete the directories.""" |
234 self.tear_down_svn() | |
235 self.tear_down_git() | 190 self.tear_down_git() |
236 # This deletes the directories. | 191 # This deletes the directories. |
237 self.trial.tear_down() | 192 self.trial.tear_down() |
238 self.trial = None | 193 self.trial = None |
239 | 194 |
240 def tear_down_svn(self): | |
241 if self.svnserve: | |
242 logging.debug('Killing svnserve pid %s' % self.svnserve.pid) | |
243 try: | |
244 self.svnserve.kill() | |
245 except OSError as e: | |
246 if e.errno != errno.ESRCH: # no such process | |
247 raise | |
248 wait_for_port_to_free(self.host, self.svn_port) | |
249 self.svnserve = None | |
250 self.svn_port = None | |
251 self.svn_base = None | |
252 if not self.trial.SHOULD_LEAK: | |
253 logging.debug('Removing %s' % self.svn_repo) | |
254 gclient_utils.rmtree(self.svn_repo) | |
255 logging.debug('Removing %s' % self.svn_checkout) | |
256 gclient_utils.rmtree(self.svn_checkout) | |
257 else: | |
258 return False | |
259 return True | |
260 | |
261 def tear_down_git(self): | 195 def tear_down_git(self): |
262 if self.gitdaemon: | 196 if self.gitdaemon: |
263 logging.debug('Killing git-daemon pid %s' % self.gitdaemon.pid) | 197 logging.debug('Killing git-daemon pid %s' % self.gitdaemon.pid) |
264 self.gitdaemon.kill() | 198 self.gitdaemon.kill() |
265 self.gitdaemon = None | 199 self.gitdaemon = None |
266 if self.git_pid_file: | 200 if self.git_pid_file: |
267 pid = int(self.git_pid_file.read()) | 201 pid = int(self.git_pid_file.read()) |
268 self.git_pid_file.close() | 202 self.git_pid_file.close() |
269 logging.debug('Killing git daemon pid %s' % pid) | 203 logging.debug('Killing git daemon pid %s' % pid) |
270 try: | 204 try: |
(...skipping 22 matching lines...) Expand all Loading... | |
293 k_arr = k_os.split(os.sep) | 227 k_arr = k_os.split(os.sep) |
294 if len(k_arr) > 1: | 228 if len(k_arr) > 1: |
295 p = os.sep.join([root] + k_arr[:-1]) | 229 p = os.sep.join([root] + k_arr[:-1]) |
296 if not os.path.isdir(p): | 230 if not os.path.isdir(p): |
297 os.makedirs(p) | 231 os.makedirs(p) |
298 if v is None: | 232 if v is None: |
299 os.remove(join(root, k)) | 233 os.remove(join(root, k)) |
300 else: | 234 else: |
301 write(join(root, k), v) | 235 write(join(root, k), v) |
302 | 236 |
303 def set_up_svn(self): | |
304 """Creates subversion repositories and start the servers.""" | |
305 self.set_up() | |
306 if self.svnserve: | |
307 return True | |
308 try: | |
309 subprocess2.check_call(['svnadmin', 'create', self.svn_repo]) | |
310 except (OSError, subprocess2.CalledProcessError): | |
311 return False | |
312 write(join(self.svn_repo, 'conf', 'svnserve.conf'), | |
313 '[general]\n' | |
314 'anon-access = read\n' | |
315 'auth-access = write\n' | |
316 'password-db = passwd\n') | |
317 text = '[users]\n' | |
318 text += ''.join('%s = %s\n' % (usr, pwd) for usr, pwd in self.USERS) | |
319 write(join(self.svn_repo, 'conf', 'passwd'), text) | |
320 | |
321 # Necessary to be able to change revision properties | |
322 revprop_hook_filename = join(self.svn_repo, 'hooks', 'pre-revprop-change') | |
323 if sys.platform == 'win32': | |
324 # TODO(kustermann): Test on Windows one day. | |
325 write("%s.bat" % revprop_hook_filename, "") | |
326 else: | |
327 write(revprop_hook_filename, | |
328 '#!/bin/sh\n' | |
329 'exit 0\n') | |
330 os.chmod(revprop_hook_filename, 0755) | |
331 | |
332 # Mac 10.6 ships with a buggy subversion build and we need this line | |
333 # to work around the bug. | |
334 write(join(self.svn_repo, 'db', 'fsfs.conf'), | |
335 '[rep-sharing]\n' | |
336 'enable-rep-sharing = false\n') | |
337 | |
338 # Start the daemon. | |
339 self.svn_port = find_free_port(self.host, 10000) | |
340 logging.debug('Using port %d' % self.svn_port) | |
341 cmd = ['svnserve', '-d', '--foreground', '-r', self.root_dir, | |
342 '--listen-port=%d' % self.svn_port] | |
343 if self.host == '127.0.0.1': | |
344 cmd.append('--listen-host=' + self.host) | |
345 self.check_port_is_free(self.svn_port) | |
346 self.svnserve = subprocess2.Popen( | |
347 cmd, | |
348 cwd=self.svn_repo, | |
349 stdout=subprocess2.PIPE, | |
350 stderr=subprocess2.PIPE) | |
351 wait_for_port_to_bind(self.host, self.svn_port, self.svnserve) | |
352 self.svn_base = 'svn://%s:%d/svn/' % (self.host, self.svn_port) | |
353 self.populateSvn() | |
354 self.svn_dirty = False | |
355 return True | |
356 | |
357 def set_up_git(self): | 237 def set_up_git(self): |
358 """Creates git repositories and start the servers.""" | 238 """Creates git repositories and start the servers.""" |
359 self.set_up() | 239 self.set_up() |
360 if self.gitdaemon: | 240 if self.gitdaemon: |
361 return True | 241 return True |
362 assert self.git_pid_file == None | 242 assert self.git_pid_file == None |
363 try: | 243 try: |
364 subprocess2.check_output(['git', '--version']) | 244 subprocess2.check_output(['git', '--version']) |
365 except (OSError, subprocess2.CalledProcessError): | 245 except (OSError, subprocess2.CalledProcessError): |
366 return False | 246 return False |
(...skipping 16 matching lines...) Expand all Loading... | |
383 self.gitdaemon = subprocess2.Popen( | 263 self.gitdaemon = subprocess2.Popen( |
384 cmd, | 264 cmd, |
385 cwd=self.root_dir, | 265 cwd=self.root_dir, |
386 stdout=subprocess2.PIPE, | 266 stdout=subprocess2.PIPE, |
387 stderr=subprocess2.PIPE) | 267 stderr=subprocess2.PIPE) |
388 wait_for_port_to_bind(self.host, self.git_port, self.gitdaemon) | 268 wait_for_port_to_bind(self.host, self.git_port, self.gitdaemon) |
389 self.populateGit() | 269 self.populateGit() |
390 self.git_dirty = False | 270 self.git_dirty = False |
391 return True | 271 return True |
392 | 272 |
393 def _commit_svn(self, tree): | |
394 self._genTree(self.svn_checkout, tree) | |
395 commit_svn(self.svn_checkout, self.USERS[0][0], self.USERS[0][1]) | |
396 if self.svn_revs and self.svn_revs[-1]: | |
397 new_tree = self.svn_revs[-1].copy() | |
398 new_tree.update(tree) | |
399 else: | |
400 new_tree = tree.copy() | |
401 self.svn_revs.append(new_tree) | |
402 | |
403 def _set_svn_commit_date(self, revision, date): | |
404 subprocess2.check_output( | |
405 ['svn', 'propset', 'svn:date', '--revprop', '-r', revision, date, | |
406 self.svn_base, | |
407 '--username', self.USERS[0][0], | |
408 '--password', self.USERS[0][1], | |
409 '--non-interactive']) | |
410 | |
411 def _commit_git(self, repo, tree): | 273 def _commit_git(self, repo, tree): |
412 repo_root = join(self.git_root, repo) | 274 repo_root = join(self.git_root, repo) |
413 self._genTree(repo_root, tree) | 275 self._genTree(repo_root, tree) |
414 commit_hash = commit_git(repo_root) | 276 commit_hash = commit_git(repo_root) |
415 if self.git_hashes[repo][-1]: | 277 if self.git_hashes[repo][-1]: |
416 new_tree = self.git_hashes[repo][-1][1].copy() | 278 new_tree = self.git_hashes[repo][-1][1].copy() |
417 new_tree.update(tree) | 279 new_tree.update(tree) |
418 else: | 280 else: |
419 new_tree = tree.copy() | 281 new_tree = tree.copy() |
420 self.git_hashes[repo].append((commit_hash, new_tree)) | 282 self.git_hashes[repo].append((commit_hash, new_tree)) |
421 | 283 |
422 def check_port_is_free(self, port): | 284 def check_port_is_free(self, port): |
423 sock = socket.socket() | 285 sock = socket.socket() |
424 try: | 286 try: |
425 sock.connect((self.host, port)) | 287 sock.connect((self.host, port)) |
426 # It worked, throw. | 288 # It worked, throw. |
427 assert False, '%d shouldn\'t be bound' % port | 289 assert False, '%d shouldn\'t be bound' % port |
428 except (socket.error, EnvironmentError): | 290 except (socket.error, EnvironmentError): |
429 pass | 291 pass |
430 finally: | 292 finally: |
431 sock.close() | 293 sock.close() |
432 | 294 |
433 def populateSvn(self): | |
434 raise NotImplementedError() | |
435 | |
436 def populateGit(self): | 295 def populateGit(self): |
437 raise NotImplementedError() | 296 raise NotImplementedError() |
438 | 297 |
439 | 298 |
440 class FakeRepos(FakeReposBase): | 299 class FakeRepos(FakeReposBase): |
441 """Implements populateSvn() and populateGit().""" | 300 """Implements populateGit().""" |
442 NB_GIT_REPOS = 5 | 301 NB_GIT_REPOS = 5 |
443 | 302 |
444 def populateSvn(self): | |
445 """Creates a few revisions of changes including DEPS files.""" | |
446 # Repos | |
447 subprocess2.check_call( | |
448 ['svn', 'checkout', self.svn_base, self.svn_checkout, | |
449 '-q', '--non-interactive', '--no-auth-cache', | |
450 '--username', self.USERS[0][0], '--password', self.USERS[0][1]]) | |
451 assert os.path.isdir(join(self.svn_checkout, '.svn')) | |
452 def file_system(rev, DEPS, DEPS_ALT=None): | |
453 fs = { | |
454 'origin': 'svn@%(rev)d\n', | |
455 'trunk/origin': 'svn/trunk@%(rev)d\n', | |
456 'trunk/src/origin': 'svn/trunk/src@%(rev)d\n', | |
457 'trunk/src/third_party/origin': 'svn/trunk/src/third_party@%(rev)d\n', | |
458 'trunk/other/origin': 'src/trunk/other@%(rev)d\n', | |
459 'trunk/third_party/origin': 'svn/trunk/third_party@%(rev)d\n', | |
460 'trunk/third_party/foo/origin': 'svn/trunk/third_party/foo@%(rev)d\n', | |
461 'trunk/third_party/prout/origin': 'svn/trunk/third_party/foo@%(rev)d\n', | |
462 } | |
463 for k in fs.iterkeys(): | |
464 fs[k] = fs[k] % { 'rev': rev } | |
465 fs['trunk/src/DEPS'] = DEPS | |
466 if DEPS_ALT: | |
467 fs['trunk/src/DEPS.alt'] = DEPS_ALT | |
468 return fs | |
469 | |
470 # Testing: | |
471 # - dependency disapear | |
472 # - dependency renamed | |
473 # - versioned and unversioned reference | |
474 # - relative and full reference | |
475 # - deps_os | |
476 # - var | |
477 # - hooks | |
478 # - From | |
479 # - File | |
480 # TODO(maruel): | |
481 # - $matching_files | |
482 # - use_relative_paths | |
483 DEPS = """ | |
484 vars = { | |
485 'DummyVariable': 'third_party', | |
486 } | |
487 deps = { | |
488 'src/other': '%(svn_base)strunk/other@1', | |
489 'src/third_party/fpp': '/trunk/' + Var('DummyVariable') + '/foo', | |
490 } | |
491 deps_os = { | |
492 'mac': { | |
493 'src/third_party/prout': '/trunk/third_party/prout', | |
494 }, | |
495 }""" % { 'svn_base': self.svn_base } | |
496 | |
497 DEPS_ALT = """ | |
498 deps = { | |
499 'src/other2': '%(svn_base)strunk/other@2' | |
500 } | |
501 """ % { 'svn_base': self.svn_base } | |
502 | |
503 fs = file_system(1, DEPS, DEPS_ALT) | |
504 self._commit_svn(fs) | |
505 | |
506 fs = file_system(2, """ | |
507 deps = { | |
508 'src/other': '%(svn_base)strunk/other', | |
509 # Load another DEPS and load a dependency from it. That's an example of | |
510 # WebKit's chromium checkout flow. Verify it works out of order. | |
511 'src/third_party/foo': From('src/file/other', 'foo/bar'), | |
512 'src/file/other': File('%(svn_base)strunk/other/DEPS'), | |
513 } | |
514 # I think this is wrong to have the hooks run from the base of the gclient | |
515 # checkout. It's maybe a bit too late to change that behavior. | |
516 hooks = [ | |
517 { | |
518 'pattern': '.', | |
519 'action': ['python', '-c', | |
520 'open(\\'src/svn_hooked1\\', \\'w\\').write(\\'svn_hooked1\\')'], | |
521 }, | |
522 { | |
523 # Should not be run. | |
524 'pattern': 'nonexistent', | |
525 'action': ['python', '-c', | |
526 'open(\\'src/svn_hooked2\\', \\'w\\').write(\\'svn_hooked2\\')'], | |
527 }, | |
528 ] | |
529 """ % { 'svn_base': self.svn_base }) | |
530 fs['trunk/other/DEPS'] = """ | |
531 deps = { | |
532 'foo/bar': '/trunk/third_party/foo@1', | |
533 # Only the requested deps should be processed. | |
534 'invalid': '/does_not_exist', | |
535 } | |
536 """ | |
537 # WebKit abuses this. | |
538 fs['trunk/webkit/.gclient'] = """ | |
539 solutions = [ | |
540 { | |
541 'name': './', | |
542 'url': None, | |
543 }, | |
544 ] | |
545 """ | |
546 fs['trunk/webkit/DEPS'] = """ | |
547 deps = { | |
548 'foo/bar': '%(svn_base)strunk/third_party/foo@1' | |
549 } | |
550 | |
551 hooks = [ | |
552 { | |
553 'pattern': '.*', | |
554 'action': ['echo', 'foo'], | |
555 }, | |
556 ] | |
557 """ % { 'svn_base': self.svn_base } | |
558 self._commit_svn(fs) | |
559 | |
560 def populateGit(self): | 303 def populateGit(self): |
561 # Testing: | 304 # Testing: |
562 # - dependency disappear | 305 # - dependency disappear |
563 # - dependency renamed | 306 # - dependency renamed |
564 # - versioned and unversioned reference | 307 # - versioned and unversioned reference |
565 # - relative and full reference | 308 # - relative and full reference |
566 # - deps_os | 309 # - deps_os |
567 # - var | 310 # - var |
568 # - hooks | 311 # - hooks |
569 # - From | 312 # - From |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
700 ] | 443 ] |
701 """ % { | 444 """ % { |
702 'git_base': self.git_base, | 445 'git_base': self.git_base, |
703 'hash1': self.git_hashes['repo_1'][2][0][:7], | 446 'hash1': self.git_hashes['repo_1'][2][0][:7], |
704 'hash2': self.git_hashes['repo_2'][1][0][:7], | 447 'hash2': self.git_hashes['repo_2'][1][0][:7], |
705 }, | 448 }, |
706 'origin': 'git/repo_5@3\n', | 449 'origin': 'git/repo_5@3\n', |
707 }) | 450 }) |
708 | 451 |
709 | 452 |
710 class FakeRepoTransitive(FakeReposBase): | |
711 """Implements populateSvn()""" | |
712 | |
713 def populateSvn(self): | |
714 """Creates a few revisions of changes including a DEPS file.""" | |
715 # Repos | |
716 subprocess2.check_call( | |
717 ['svn', 'checkout', self.svn_base, self.svn_checkout, | |
718 '-q', '--non-interactive', '--no-auth-cache', | |
719 '--username', self.USERS[0][0], '--password', self.USERS[0][1]]) | |
720 assert os.path.isdir(join(self.svn_checkout, '.svn')) | |
721 | |
722 def file_system(rev): | |
723 DEPS = """deps = { | |
724 'src/different_repo': '%(svn_base)strunk/third_party', | |
725 'src/different_repo_fixed': '%(svn_base)strunk/third_party@1', | |
726 'src/same_repo': '/trunk/third_party', | |
727 'src/same_repo_fixed': '/trunk/third_party@1', | |
728 }""" % { 'svn_base': self.svn_base } | |
729 return { | |
730 'trunk/src/DEPS': DEPS, | |
731 'trunk/src/origin': 'svn/trunk/src@%(rev)d' % { 'rev': rev }, | |
732 'trunk/third_party/origin': | |
733 'svn/trunk/third_party@%(rev)d' % { 'rev': rev }, | |
734 } | |
735 | |
736 # We make three commits. We use always the same DEPS contents but | |
737 # - 'trunk/src/origin' contains 'svn/trunk/src/origin@rX' | |
738 # - 'trunk/third_party/origin' contains 'svn/trunk/third_party/origin@rX' | |
739 # where 'X' is the revision number. | |
740 # So the 'origin' files will change in every commit. | |
741 self._commit_svn(file_system(1)) | |
742 self._commit_svn(file_system(2)) | |
743 self._commit_svn(file_system(3)) | |
744 # We rewrite the timestamps so we can test that '--transitive' will take the | |
745 # parent timestamp on different repositories and the parent revision | |
746 # otherwise. | |
747 self._set_svn_commit_date('1', '2011-10-01T03:00:00.000000Z') | |
748 self._set_svn_commit_date('2', '2011-10-09T03:00:00.000000Z') | |
749 self._set_svn_commit_date('3', '2011-10-02T03:00:00.000000Z') | |
750 | |
751 def populateGit(self): | |
752 pass | |
753 | |
754 | |
755 class FakeRepoSkiaDEPS(FakeReposBase): | 453 class FakeRepoSkiaDEPS(FakeReposBase): |
756 """Simulates the Skia DEPS transition in Chrome.""" | 454 """Simulates the Skia DEPS transition in Chrome.""" |
757 | 455 |
758 NB_GIT_REPOS = 5 | 456 NB_GIT_REPOS = 5 |
759 | 457 |
760 DEPS_svn_pre = """deps = { | |
761 'src/third_party/skia/gyp': '%(svn_base)sskia/gyp', | |
762 'src/third_party/skia/include': '%(svn_base)sskia/include', | |
763 'src/third_party/skia/src': '%(svn_base)sskia/src', | |
764 }""" | |
765 | |
766 DEPS_git_pre = """deps = { | 458 DEPS_git_pre = """deps = { |
767 'src/third_party/skia/gyp': '%(git_base)srepo_3', | 459 'src/third_party/skia/gyp': '%(git_base)srepo_3', |
768 'src/third_party/skia/include': '%(git_base)srepo_4', | 460 'src/third_party/skia/include': '%(git_base)srepo_4', |
769 'src/third_party/skia/src': '%(git_base)srepo_5', | 461 'src/third_party/skia/src': '%(git_base)srepo_5', |
770 }""" | 462 }""" |
771 | 463 |
772 DEPS_post = """deps = { | 464 DEPS_post = """deps = { |
773 'src/third_party/skia': '%(git_base)srepo_1', | 465 'src/third_party/skia': '%(git_base)srepo_1', |
774 }""" | 466 }""" |
775 | 467 |
776 def populateSvn(self): | |
777 """Create revisions which simulate the Skia DEPS transition in Chrome.""" | |
778 subprocess2.check_call( | |
779 ['svn', 'checkout', self.svn_base, self.svn_checkout, | |
780 '-q', '--non-interactive', '--no-auth-cache', | |
781 '--username', self.USERS[0][0], '--password', self.USERS[0][1]]) | |
782 assert os.path.isdir(join(self.svn_checkout, '.svn')) | |
783 | |
784 # Skia repo. | |
785 self._commit_svn({ | |
786 'skia/skia_base_file': 'root-level file.', | |
787 'skia/gyp/gyp_file': 'file in the gyp directory', | |
788 'skia/include/include_file': 'file in the include directory', | |
789 'skia/src/src_file': 'file in the src directory', | |
790 }) | |
791 | |
792 # Chrome repo. | |
793 self._commit_svn({ | |
794 'trunk/src/DEPS': self.DEPS_svn_pre % {'svn_base': self.svn_base}, | |
795 'trunk/src/myfile': 'svn/trunk/src@1' | |
796 }) | |
797 self._commit_svn({ | |
798 'trunk/src/DEPS': self.DEPS_post % {'git_base': self.git_base}, | |
799 'trunk/src/myfile': 'svn/trunk/src@2' | |
800 }) | |
801 | |
802 def populateGit(self): | 468 def populateGit(self): |
803 # Skia repo. | 469 # Skia repo. |
804 self._commit_git('repo_1', { | 470 self._commit_git('repo_1', { |
805 'skia_base_file': 'root-level file.', | 471 'skia_base_file': 'root-level file.', |
806 'gyp/gyp_file': 'file in the gyp directory', | 472 'gyp/gyp_file': 'file in the gyp directory', |
807 'include/include_file': 'file in the include directory', | 473 'include/include_file': 'file in the include directory', |
808 'src/src_file': 'file in the src directory', | 474 'src/src_file': 'file in the src directory', |
809 }) | 475 }) |
810 self._commit_git('repo_3', { # skia/gyp | 476 self._commit_git('repo_3', { # skia/gyp |
811 'gyp_file': 'file in the gyp directory', | 477 'gyp_file': 'file in the gyp directory', |
812 }) | 478 }) |
813 self._commit_git('repo_4', { # skia/include | 479 self._commit_git('repo_4', { # skia/include |
814 'include_file': 'file in the include directory', | 480 'include_file': 'file in the include directory', |
815 }) | 481 }) |
816 self._commit_git('repo_5', { # skia/src | 482 self._commit_git('repo_5', { # skia/src |
817 'src_file': 'file in the src directory', | 483 'src_file': 'file in the src directory', |
818 }) | 484 }) |
819 | 485 |
820 # Chrome repo. | 486 # Chrome repo. |
821 self._commit_git('repo_2', { | 487 self._commit_git('repo_2', { |
822 'DEPS': self.DEPS_git_pre % {'git_base': self.git_base}, | 488 'DEPS': self.DEPS_git_pre % {'git_base': self.git_base}, |
823 'myfile': 'svn/trunk/src@1' | 489 'myfile': 'src/trunk/src@1' |
824 }) | 490 }) |
825 self._commit_git('repo_2', { | 491 self._commit_git('repo_2', { |
826 'DEPS': self.DEPS_post % {'git_base': self.git_base}, | 492 'DEPS': self.DEPS_post % {'git_base': self.git_base}, |
827 'myfile': 'svn/trunk/src@2' | 493 'myfile': 'src/trunk/src@2' |
828 }) | 494 }) |
829 | 495 |
830 | 496 |
831 class FakeRepoBlinkDEPS(FakeReposBase): | 497 class FakeRepoBlinkDEPS(FakeReposBase): |
832 """Simulates the Blink DEPS transition in Chrome.""" | 498 """Simulates the Blink DEPS transition in Chrome.""" |
833 | 499 |
834 NB_GIT_REPOS = 2 | 500 NB_GIT_REPOS = 2 |
835 DEPS_pre = 'deps = {"src/third_party/WebKit": "%(git_base)srepo_2",}' | 501 DEPS_pre = 'deps = {"src/third_party/WebKit": "%(git_base)srepo_2",}' |
836 DEPS_post = 'deps = {}' | 502 DEPS_post = 'deps = {}' |
837 | 503 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
873 super(FakeReposTestBase, self).setUp() | 539 super(FakeReposTestBase, self).setUp() |
874 if not self.FAKE_REPOS_CLASS in self.CACHED_FAKE_REPOS: | 540 if not self.FAKE_REPOS_CLASS in self.CACHED_FAKE_REPOS: |
875 self.CACHED_FAKE_REPOS[self.FAKE_REPOS_CLASS] = self.FAKE_REPOS_CLASS() | 541 self.CACHED_FAKE_REPOS[self.FAKE_REPOS_CLASS] = self.FAKE_REPOS_CLASS() |
876 self.FAKE_REPOS = self.CACHED_FAKE_REPOS[self.FAKE_REPOS_CLASS] | 542 self.FAKE_REPOS = self.CACHED_FAKE_REPOS[self.FAKE_REPOS_CLASS] |
877 # No need to call self.FAKE_REPOS.setUp(), it will be called by the child | 543 # No need to call self.FAKE_REPOS.setUp(), it will be called by the child |
878 # class. | 544 # class. |
879 # Do not define tearDown(), since super's version does the right thing and | 545 # Do not define tearDown(), since super's version does the right thing and |
880 # self.FAKE_REPOS is kept across tests. | 546 # self.FAKE_REPOS is kept across tests. |
881 | 547 |
882 @property | 548 @property |
883 def svn_base(self): | |
884 """Shortcut.""" | |
885 return self.FAKE_REPOS.svn_base | |
886 | |
887 @property | |
888 def git_base(self): | 549 def git_base(self): |
889 """Shortcut.""" | 550 """Shortcut.""" |
890 return self.FAKE_REPOS.git_base | 551 return self.FAKE_REPOS.git_base |
891 | 552 |
892 def checkString(self, expected, result, msg=None): | 553 def checkString(self, expected, result, msg=None): |
893 """Prints the diffs to ease debugging.""" | 554 """Prints the diffs to ease debugging.""" |
894 if expected != result: | 555 if expected != result: |
895 # Strip the begining | 556 # Strip the begining |
896 while expected and result and expected[0] == result[0]: | 557 while expected and result and expected[0] == result[0]: |
897 expected = expected[1:] | 558 expected = expected[1:] |
(...skipping 14 matching lines...) Expand all Loading... | |
912 if not tree_root: | 573 if not tree_root: |
913 tree_root = self.root_dir | 574 tree_root = self.root_dir |
914 actual = read_tree(tree_root) | 575 actual = read_tree(tree_root) |
915 diff = dict_diff(tree, actual) | 576 diff = dict_diff(tree, actual) |
916 if diff: | 577 if diff: |
917 logging.debug('Actual %s\n%s' % (tree_root, pprint.pformat(actual))) | 578 logging.debug('Actual %s\n%s' % (tree_root, pprint.pformat(actual))) |
918 logging.debug('Expected\n%s' % pprint.pformat(tree)) | 579 logging.debug('Expected\n%s' % pprint.pformat(tree)) |
919 logging.debug('Diff\n%s' % pprint.pformat(diff)) | 580 logging.debug('Diff\n%s' % pprint.pformat(diff)) |
920 self.assertEquals(diff, {}) | 581 self.assertEquals(diff, {}) |
921 | 582 |
922 def mangle_svn_tree(self, *args): | |
923 """Creates a 'virtual directory snapshot' to compare with the actual result | |
924 on disk.""" | |
925 result = {} | |
926 for item, new_root in args: | |
927 old_root, rev = item.split('@', 1) | |
928 tree = self.FAKE_REPOS.svn_revs[int(rev)] | |
929 for k, v in tree.iteritems(): | |
930 if not k.startswith(old_root): | |
931 continue | |
932 item = k[len(old_root) + 1:] | |
933 if item.startswith('.'): | |
934 continue | |
935 result[join(new_root, item).replace(os.sep, '/')] = v | |
936 return result | |
937 | |
938 def mangle_git_tree(self, *args): | 583 def mangle_git_tree(self, *args): |
939 """Creates a 'virtual directory snapshot' to compare with the actual result | 584 """Creates a 'virtual directory snapshot' to compare with the actual result |
940 on disk.""" | 585 on disk.""" |
941 result = {} | 586 result = {} |
942 for item, new_root in args: | 587 for item, new_root in args: |
943 repo, rev = item.split('@', 1) | 588 repo, rev = item.split('@', 1) |
944 tree = self.gittree(repo, rev) | 589 tree = self.gittree(repo, rev) |
945 for k, v in tree.iteritems(): | 590 for k, v in tree.iteritems(): |
946 result[join(new_root, k)] = v | 591 result[join(new_root, k)] = v |
947 return result | 592 return result |
948 | 593 |
949 def githash(self, repo, rev): | 594 def githash(self, repo, rev): |
950 """Sort-hand: Returns the hash for a git 'revision'.""" | 595 """Sort-hand: Returns the hash for a git 'revision'.""" |
951 return self.FAKE_REPOS.git_hashes[repo][int(rev)][0] | 596 return self.FAKE_REPOS.git_hashes[repo][int(rev)][0] |
952 | 597 |
953 def gittree(self, repo, rev): | 598 def gittree(self, repo, rev): |
954 """Sort-hand: returns the directory tree for a git 'revision'.""" | 599 """Sort-hand: returns the directory tree for a git 'revision'.""" |
955 return self.FAKE_REPOS.git_hashes[repo][int(rev)][1] | 600 return self.FAKE_REPOS.git_hashes[repo][int(rev)][1] |
956 | 601 |
957 | 602 |
958 def main(argv): | 603 def main(argv): |
959 fake = FakeRepos() | 604 fake = FakeRepos() |
960 print 'Using %s' % fake.root_dir | 605 print 'Using %s' % fake.root_dir |
961 try: | 606 try: |
962 fake.set_up_svn() | |
963 fake.set_up_git() | 607 fake.set_up_git() |
964 print('Fake setup, press enter to quit or Ctrl-C to keep the checkouts.') | 608 print('Fake setup, press enter to quit or Ctrl-C to keep the checkouts.') |
965 sys.stdin.readline() | 609 sys.stdin.readline() |
966 except KeyboardInterrupt: | 610 except KeyboardInterrupt: |
967 trial_dir.TrialDir.SHOULD_LEAK.leak = True | 611 trial_dir.TrialDir.SHOULD_LEAK.leak = True |
968 return 0 | 612 return 0 |
969 | 613 |
970 | 614 |
971 if __name__ == '__main__': | 615 if __name__ == '__main__': |
972 sys.exit(main(sys.argv)) | 616 sys.exit(main(sys.argv)) |
OLD | NEW |