 Chromium Code Reviews
 Chromium Code Reviews Issue 6627013:
  Correctly kill 'git daemon' child process, fixing a lot of testing issues.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
    
  
    Issue 6627013:
  Correctly kill 'git daemon' child process, fixing a lot of testing issues.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools| 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 errno | 10 import errno | 
| 10 import logging | 11 import logging | 
| 11 import os | 12 import os | 
| 12 import pprint | 13 import pprint | 
| 13 import re | 14 import re | 
| 15 import socket | |
| 14 import stat | 16 import stat | 
| 15 import subprocess | 17 import subprocess | 
| 16 import sys | 18 import sys | 
| 19 import tempfile | |
| 17 import time | 20 import time | 
| 18 import unittest | 21 import unittest | 
| 19 | 22 | 
| 20 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | 23 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | 
| 21 | 24 | 
| 22 import scm | 25 import scm | 
| 23 | 26 | 
| 24 ## Utility functions | 27 ## Utility functions | 
| 25 | 28 | 
| 26 | 29 | 
| 27 def addKill(): | 30 def kill_pid(pid): | 
| 28 """Add kill() method to subprocess.Popen for python <2.6""" | 31 """Kills a process by its process id.""" | 
| 29 if getattr(subprocess.Popen, 'kill', None): | 32 try: | 
| 33 # Unable to import 'module' | |
| 34 # pylint: disable=F0401 | |
| 35 import signal | |
| 36 return os.kill(pid, signal.SIGKILL) | |
| 37 except ImportError: | |
| 38 pass | |
| 39 | |
| 40 | |
| 41 def kill_win(process): | |
| 42 """Kills a process with its windows handle. | |
| 43 | |
| 44 Has no effect on other platforms. | |
| 45 """ | |
| 46 try: | |
| 47 # Unable to import 'module' | |
| 48 # pylint: disable=F0401 | |
| 49 import win32process | |
| 50 # Access to a protected member _handle of a client class | |
| 51 # pylint: disable=W0212 | |
| 52 return win32process.TerminateProcess(process._handle, -1) | |
| 53 except ImportError: | |
| 54 pass | |
| 55 | |
| 56 | |
| 57 def add_kill(): | |
| 58 """Adds kill() method to subprocess.Popen for python <2.6""" | |
| 59 if hasattr(subprocess.Popen, 'kill'): | |
| 30 return | 60 return | 
| 31 # Unable to import 'module' | 61 | 
| 32 # pylint: disable=F0401 | |
| 33 if sys.platform == 'win32': | 62 if sys.platform == 'win32': | 
| 34 def kill_win(process): | |
| 35 import win32process | |
| 36 # Access to a protected member _handle of a client class | |
| 37 # pylint: disable=W0212 | |
| 38 return win32process.TerminateProcess(process._handle, -1) | |
| 39 subprocess.Popen.kill = kill_win | 63 subprocess.Popen.kill = kill_win | 
| 40 else: | 64 else: | 
| 41 def kill_nix(process): | 65 def kill_nix(process): | 
| 42 import signal | 66 return kill_pid(process.pid) | 
| 
Dirk Pranke
2011/03/04 21:15:17
I'd likely just change kill_pid to take process as
 
M-A Ruel
2011/03/04 21:18:21
I can't because I need to kill 'git-daemon' child
 | |
| 43 return os.kill(process.pid, signal.SIGKILL) | |
| 44 subprocess.Popen.kill = kill_nix | 67 subprocess.Popen.kill = kill_nix | 
| 45 | 68 | 
| 46 | 69 | 
| 47 def rmtree(*path): | 70 def rmtree(*path): | 
| 48 """Recursively removes a directory, even if it's marked read-only. | 71 """Recursively removes a directory, even if it's marked read-only. | 
| 49 | 72 | 
| 50 Remove the directory located at *path, if it exists. | 73 Remove the directory located at *path, if it exists. | 
| 51 | 74 | 
| 52 shutil.rmtree() doesn't work on Windows if any of the files or directories | 75 shutil.rmtree() doesn't work on Windows if any of the files or directories | 
| 53 are read-only, which svn repositories and some .svn files are. We need to | 76 are read-only, which svn repositories and some .svn files are. We need to | 
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 243 self.svn_revs = [None] | 266 self.svn_revs = [None] | 
| 244 # Format is { repo: [ None, (hash, tree), (hash, tree), ... ], ... } | 267 # Format is { repo: [ None, (hash, tree), (hash, tree), ... ], ... } | 
| 245 # so reference looks like self.git_hashes[repo][rev][0] for hash and | 268 # so reference looks like self.git_hashes[repo][rev][0] for hash and | 
| 246 # self.git_hashes[repo][rev][1] for it's tree snapshot. | 269 # self.git_hashes[repo][rev][1] for it's tree snapshot. | 
| 247 # For consistency with self.svn_revs, it is 1-based too. | 270 # For consistency with self.svn_revs, it is 1-based too. | 
| 248 self.git_hashes = {} | 271 self.git_hashes = {} | 
| 249 self.svnserve = None | 272 self.svnserve = None | 
| 250 self.gitdaemon = None | 273 self.gitdaemon = None | 
| 251 self.common_init = False | 274 self.common_init = False | 
| 252 self.repos_dir = None | 275 self.repos_dir = None | 
| 276 self.git_pid_file = None | |
| 253 self.git_root = None | 277 self.git_root = None | 
| 254 self.svn_checkout = None | 278 self.svn_checkout = None | 
| 255 self.svn_repo = None | 279 self.svn_repo = None | 
| 256 self.git_dirty = False | 280 self.git_dirty = False | 
| 257 self.svn_dirty = False | 281 self.svn_dirty = False | 
| 282 self.svn_port = 3690 | |
| 283 self.git_port = 9418 | |
| 258 | 284 | 
| 259 def trial_dir(self): | 285 def trial_dir(self): | 
| 260 if not self.TRIAL_DIR: | 286 if not self.TRIAL_DIR: | 
| 261 self.TRIAL_DIR = os.path.join( | 287 self.TRIAL_DIR = os.path.join( | 
| 262 os.path.dirname(os.path.abspath(__file__)), '_trial') | 288 os.path.dirname(os.path.abspath(__file__)), '_trial') | 
| 263 return self.TRIAL_DIR | 289 return self.TRIAL_DIR | 
| 264 | 290 | 
| 265 def setUp(self): | 291 def set_up(self): | 
| 266 """All late initialization comes here. | 292 """All late initialization comes here. | 
| 267 | 293 | 
| 268 Note that it deletes all trial_dir() and not only repos_dir. | 294 Note that it deletes all trial_dir() and not only repos_dir. | 
| 269 """ | 295 """ | 
| 270 self.cleanup_dirt() | 296 self.cleanup_dirt() | 
| 271 if not self.common_init: | 297 if not self.common_init: | 
| 272 self.common_init = True | 298 self.common_init = True | 
| 273 self.repos_dir = os.path.join(self.trial_dir(), 'repos') | 299 self.repos_dir = os.path.join(self.trial_dir(), 'repos') | 
| 274 self.git_root = join(self.repos_dir, 'git') | 300 self.git_root = join(self.repos_dir, 'git') | 
| 275 self.svn_checkout = join(self.repos_dir, 'svn_checkout') | 301 self.svn_checkout = join(self.repos_dir, 'svn_checkout') | 
| 276 self.svn_repo = join(self.repos_dir, 'svn') | 302 self.svn_repo = join(self.repos_dir, 'svn') | 
| 277 addKill() | 303 add_kill() | 
| 278 rmtree(self.trial_dir()) | 304 rmtree(self.trial_dir()) | 
| 279 os.makedirs(self.repos_dir) | 305 os.makedirs(self.repos_dir) | 
| 280 atexit.register(self.tearDown) | 306 atexit.register(self.tear_down) | 
| 281 | 307 | 
| 282 def cleanup_dirt(self): | 308 def cleanup_dirt(self): | 
| 283 """For each dirty repository, regenerate it.""" | 309 """For each dirty repository, regenerate it.""" | 
| 284 if self.svnserve and self.svn_dirty: | 310 if self.svn_dirty: | 
| 285 logging.debug('Killing svnserve pid %s' % self.svnserve.pid) | 311 if not self.tear_down_svn(): | 
| 286 self.svnserve.kill() | 312 logging.warning('Using both leaking checkout and svn dirty checkout') | 
| 287 self.svnserve = None | 313 if self.git_dirty: | 
| 288 if not self.SHOULD_LEAK: | 314 if not self.tear_down_git(): | 
| 289 logging.debug('Removing dirty %s' % self.svn_repo) | 315 logging.warning('Using both leaking checkout and git dirty checkout') | 
| 290 rmtree(self.svn_repo) | |
| 291 logging.debug('Removing dirty %s' % self.svn_checkout) | |
| 292 rmtree(self.svn_checkout) | |
| 293 else: | |
| 294 logging.warning('Using both leaking checkout and dirty checkout') | |
| 295 if self.gitdaemon and self.git_dirty: | |
| 296 logging.debug('Killing git-daemon pid %s' % self.gitdaemon.pid) | |
| 297 self.gitdaemon.kill() | |
| 298 self.gitdaemon = None | |
| 299 if not self.SHOULD_LEAK: | |
| 300 logging.debug('Removing dirty %s' % self.git_root) | |
| 301 rmtree(self.git_root) | |
| 302 else: | |
| 303 logging.warning('Using both leaking checkout and dirty checkout') | |
| 304 | 316 | 
| 305 def tearDown(self): | 317 def tear_down(self): | 
| 318 self.tear_down_svn() | |
| 319 self.tear_down_git() | |
| 320 if not self.SHOULD_LEAK: | |
| 321 logging.debug('Removing %s' % self.trial_dir()) | |
| 322 rmtree(self.trial_dir()) | |
| 323 | |
| 324 def tear_down_svn(self): | |
| 306 if self.svnserve: | 325 if self.svnserve: | 
| 307 logging.debug('Killing svnserve pid %s' % self.svnserve.pid) | 326 logging.debug('Killing svnserve pid %s' % self.svnserve.pid) | 
| 308 self.svnserve.kill() | 327 self.svnserve.kill() | 
| 328 self.wait_for_port_to_free(self.svn_port) | |
| 309 self.svnserve = None | 329 self.svnserve = None | 
| 330 if not self.SHOULD_LEAK: | |
| 331 logging.debug('Removing %s' % self.svn_repo) | |
| 332 rmtree(self.svn_repo) | |
| 333 logging.debug('Removing %s' % self.svn_checkout) | |
| 334 rmtree(self.svn_checkout) | |
| 335 else: | |
| 336 return False | |
| 337 return True | |
| 338 | |
| 339 def tear_down_git(self): | |
| 310 if self.gitdaemon: | 340 if self.gitdaemon: | 
| 311 logging.debug('Killing git-daemon pid %s' % self.gitdaemon.pid) | 341 logging.debug('Killing git-daemon pid %s' % self.gitdaemon.pid) | 
| 312 self.gitdaemon.kill() | 342 self.gitdaemon.kill() | 
| 313 self.gitdaemon = None | 343 self.gitdaemon = None | 
| 314 if not self.SHOULD_LEAK: | 344 if self.git_pid_file: | 
| 315 logging.debug('Removing %s' % self.trial_dir()) | 345 pid = int(self.git_pid_file.read()) | 
| 316 rmtree(self.trial_dir()) | 346 self.git_pid_file.close() | 
| 347 kill_pid(pid) | |
| 348 self.git_pid_file = None | |
| 349 self.wait_for_port_to_free(self.git_port) | |
| 350 if not self.SHOULD_LEAK: | |
| 351 logging.debug('Removing %s' % self.git_root) | |
| 352 rmtree(self.git_root) | |
| 353 else: | |
| 354 return False | |
| 355 return True | |
| 317 | 356 | 
| 318 @staticmethod | 357 @staticmethod | 
| 319 def _genTree(root, tree_dict): | 358 def _genTree(root, tree_dict): | 
| 320 """For a dictionary of file contents, generate a filesystem.""" | 359 """For a dictionary of file contents, generate a filesystem.""" | 
| 321 if not os.path.isdir(root): | 360 if not os.path.isdir(root): | 
| 322 os.makedirs(root) | 361 os.makedirs(root) | 
| 323 for (k, v) in tree_dict.iteritems(): | 362 for (k, v) in tree_dict.iteritems(): | 
| 324 k_os = k.replace('/', os.sep) | 363 k_os = k.replace('/', os.sep) | 
| 325 k_arr = k_os.split(os.sep) | 364 k_arr = k_os.split(os.sep) | 
| 326 if len(k_arr) > 1: | 365 if len(k_arr) > 1: | 
| 327 p = os.sep.join([root] + k_arr[:-1]) | 366 p = os.sep.join([root] + k_arr[:-1]) | 
| 328 if not os.path.isdir(p): | 367 if not os.path.isdir(p): | 
| 329 os.makedirs(p) | 368 os.makedirs(p) | 
| 330 if v is None: | 369 if v is None: | 
| 331 os.remove(join(root, k)) | 370 os.remove(join(root, k)) | 
| 332 else: | 371 else: | 
| 333 write(join(root, k), v) | 372 write(join(root, k), v) | 
| 334 | 373 | 
| 335 def setUpSVN(self): | 374 def set_up_svn(self): | 
| 336 """Creates subversion repositories and start the servers.""" | 375 """Creates subversion repositories and start the servers.""" | 
| 337 self.setUp() | 376 self.set_up() | 
| 338 if self.svnserve: | 377 if self.svnserve: | 
| 339 return True | 378 return True | 
| 340 try: | 379 try: | 
| 341 check_call(['svnadmin', 'create', self.svn_repo]) | 380 check_call(['svnadmin', 'create', self.svn_repo]) | 
| 342 except OSError: | 381 except OSError: | 
| 343 return False | 382 return False | 
| 344 write(join(self.svn_repo, 'conf', 'svnserve.conf'), | 383 write(join(self.svn_repo, 'conf', 'svnserve.conf'), | 
| 345 '[general]\n' | 384 '[general]\n' | 
| 346 'anon-access = read\n' | 385 'anon-access = read\n' | 
| 347 'auth-access = write\n' | 386 'auth-access = write\n' | 
| 348 'password-db = passwd\n') | 387 'password-db = passwd\n') | 
| 349 text = '[users]\n' | 388 text = '[users]\n' | 
| 350 text += ''.join('%s = %s\n' % (usr, pwd) for usr, pwd in self.USERS) | 389 text += ''.join('%s = %s\n' % (usr, pwd) for usr, pwd in self.USERS) | 
| 351 write(join(self.svn_repo, 'conf', 'passwd'), text) | 390 write(join(self.svn_repo, 'conf', 'passwd'), text) | 
| 352 | 391 | 
| 353 # Start the daemon. | 392 # Start the daemon. | 
| 354 cmd = ['svnserve', '-d', '--foreground', '-r', self.repos_dir] | 393 cmd = ['svnserve', '-d', '--foreground', '-r', self.repos_dir] | 
| 355 if self.HOST == '127.0.0.1': | 394 if self.HOST == '127.0.0.1': | 
| 356 cmd.append('--listen-host=127.0.0.1') | 395 cmd.append('--listen-host=127.0.0.1') | 
| 396 self.check_port_is_free(self.svn_port) | |
| 357 self.svnserve = Popen(cmd, cwd=self.svn_repo) | 397 self.svnserve = Popen(cmd, cwd=self.svn_repo) | 
| 398 self.wait_for_port_to_bind(self.svn_port, self.svnserve) | |
| 358 self.populateSvn() | 399 self.populateSvn() | 
| 359 self.svn_dirty = False | 400 self.svn_dirty = False | 
| 360 return True | 401 return True | 
| 361 | 402 | 
| 362 def setUpGIT(self): | 403 def set_up_git(self): | 
| 363 """Creates git repositories and start the servers.""" | 404 """Creates git repositories and start the servers.""" | 
| 364 self.setUp() | 405 self.set_up() | 
| 365 if self.gitdaemon: | 406 if self.gitdaemon: | 
| 366 return True | 407 return True | 
| 367 if sys.platform == 'win32': | 408 if sys.platform == 'win32': | 
| 368 return False | 409 return False | 
| 410 assert self.git_pid_file == None | |
| 369 for repo in ['repo_%d' % r for r in range(1, self.NB_GIT_REPOS + 1)]: | 411 for repo in ['repo_%d' % r for r in range(1, self.NB_GIT_REPOS + 1)]: | 
| 370 check_call(['git', 'init', '-q', join(self.git_root, repo)]) | 412 check_call(['git', 'init', '-q', join(self.git_root, repo)]) | 
| 371 self.git_hashes[repo] = [None] | 413 self.git_hashes[repo] = [None] | 
| 414 # Unlike svn, populate git before starting the server. | |
| 372 self.populateGit() | 415 self.populateGit() | 
| 373 # Start the daemon. | 416 # Start the daemon. | 
| 374 cmd = ['git', 'daemon', '--export-all', '--base-path=' + self.repos_dir] | 417 self.git_pid_file = tempfile.NamedTemporaryFile() | 
| 418 cmd = ['git', 'daemon', | |
| 419 '--export-all', | |
| 420 '--reuseaddr', | |
| 421 '--base-path=' + self.repos_dir, | |
| 422 '--pid-file=' + self.git_pid_file.name] | |
| 375 if self.HOST == '127.0.0.1': | 423 if self.HOST == '127.0.0.1': | 
| 376 cmd.append('--listen=127.0.0.1') | 424 cmd.append('--listen=127.0.0.1') | 
| 377 logging.debug(cmd) | 425 self.check_port_is_free(self.git_port) | 
| 378 self.gitdaemon = Popen(cmd, cwd=self.repos_dir) | 426 self.gitdaemon = Popen(cmd, cwd=self.repos_dir) | 
| 427 self.wait_for_port_to_bind(self.git_port, self.gitdaemon) | |
| 379 self.git_dirty = False | 428 self.git_dirty = False | 
| 380 return True | 429 return True | 
| 381 | 430 | 
| 382 def _commit_svn(self, tree): | 431 def _commit_svn(self, tree): | 
| 383 self._genTree(self.svn_checkout, tree) | 432 self._genTree(self.svn_checkout, tree) | 
| 384 commit_svn(self.svn_checkout, self.USERS[0][0], self.USERS[0][1]) | 433 commit_svn(self.svn_checkout, self.USERS[0][0], self.USERS[0][1]) | 
| 385 if self.svn_revs and self.svn_revs[-1]: | 434 if self.svn_revs and self.svn_revs[-1]: | 
| 386 new_tree = self.svn_revs[-1].copy() | 435 new_tree = self.svn_revs[-1].copy() | 
| 387 new_tree.update(tree) | 436 new_tree.update(tree) | 
| 388 else: | 437 else: | 
| 389 new_tree = tree.copy() | 438 new_tree = tree.copy() | 
| 390 self.svn_revs.append(new_tree) | 439 self.svn_revs.append(new_tree) | 
| 391 | 440 | 
| 392 def _commit_git(self, repo, tree): | 441 def _commit_git(self, repo, tree): | 
| 393 repo_root = join(self.git_root, repo) | 442 repo_root = join(self.git_root, repo) | 
| 394 self._genTree(repo_root, tree) | 443 self._genTree(repo_root, tree) | 
| 395 commit_hash = commit_git(repo_root) | 444 commit_hash = commit_git(repo_root) | 
| 396 if self.git_hashes[repo][-1]: | 445 if self.git_hashes[repo][-1]: | 
| 397 new_tree = self.git_hashes[repo][-1][1].copy() | 446 new_tree = self.git_hashes[repo][-1][1].copy() | 
| 398 new_tree.update(tree) | 447 new_tree.update(tree) | 
| 399 else: | 448 else: | 
| 400 new_tree = tree.copy() | 449 new_tree = tree.copy() | 
| 401 self.git_hashes[repo].append((commit_hash, new_tree)) | 450 self.git_hashes[repo].append((commit_hash, new_tree)) | 
| 402 | 451 | 
| 452 def check_port_is_free(self, port): | |
| 453 sock = socket.socket() | |
| 454 try: | |
| 455 sock.connect((self.HOST, port)) | |
| 456 # It worked, throw. | |
| 457 assert False, '%d shouldn\'t be bound' % port | |
| 458 except EnvironmentError: | |
| 459 pass | |
| 460 finally: | |
| 461 sock.close() | |
| 462 | |
| 463 def wait_for_port_to_bind(self, port, process): | |
| 464 sock = socket.socket() | |
| 465 try: | |
| 466 start = datetime.datetime.utcnow() | |
| 
Dirk Pranke
2011/03/04 21:15:17
Curious why you're using datetime instead of just
 
M-A Ruel
2011/03/04 21:18:21
Habit, no real reason.
 | |
| 467 maxdelay = datetime.timedelta(seconds=30) | |
| 468 while (datetime.datetime.utcnow() - start) < maxdelay: | |
| 469 try: | |
| 470 sock.connect((self.HOST, port)) | |
| 471 logging.debug('%d is now bound' % port) | |
| 472 return | |
| 473 except EnvironmentError: | |
| 474 pass | |
| 475 logging.debug('%d is still not bound' % port) | |
| 476 finally: | |
| 477 sock.close() | |
| 478 # The process failed to bind. Kill it and dump its ouput. | |
| 479 process.kill() | |
| 480 logging.error('%s' % process.communicate()[0]) | |
| 481 assert False, '%d is still not bound' % port | |
| 482 | |
| 483 def wait_for_port_to_free(self, port): | |
| 484 start = datetime.datetime.utcnow() | |
| 485 maxdelay = datetime.timedelta(seconds=30) | |
| 486 while (datetime.datetime.utcnow() - start) < maxdelay: | |
| 487 try: | |
| 488 sock = socket.socket() | |
| 489 sock.connect((self.HOST, port)) | |
| 490 logging.debug('%d was bound, waiting to free' % port) | |
| 491 except EnvironmentError: | |
| 492 logging.debug('%d now free' % port) | |
| 493 return | |
| 494 finally: | |
| 495 sock.close() | |
| 496 assert False, '%d is still bound' % port | |
| 497 | |
| 403 def populateSvn(self): | 498 def populateSvn(self): | 
| 404 raise NotImplementedError() | 499 raise NotImplementedError() | 
| 405 | 500 | 
| 406 def populateGit(self): | 501 def populateGit(self): | 
| 407 raise NotImplementedError() | 502 raise NotImplementedError() | 
| 408 | 503 | 
| 409 | 504 | 
| 410 class FakeRepos(FakeReposBase): | 505 class FakeRepos(FakeReposBase): | 
| 411 """Implements populateSvn() and populateGit().""" | 506 """Implements populateSvn() and populateGit().""" | 
| 412 NB_GIT_REPOS = 4 | 507 NB_GIT_REPOS = 4 | 
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 628 # Override if necessary. | 723 # Override if necessary. | 
| 629 FAKE_REPOS_CLASS = FakeRepos | 724 FAKE_REPOS_CLASS = FakeRepos | 
| 630 | 725 | 
| 631 def __init__(self, *args, **kwargs): | 726 def __init__(self, *args, **kwargs): | 
| 632 unittest.TestCase.__init__(self, *args, **kwargs) | 727 unittest.TestCase.__init__(self, *args, **kwargs) | 
| 633 if not FakeReposTestBase.FAKE_REPOS: | 728 if not FakeReposTestBase.FAKE_REPOS: | 
| 634 FakeReposTestBase.FAKE_REPOS = self.FAKE_REPOS_CLASS() | 729 FakeReposTestBase.FAKE_REPOS = self.FAKE_REPOS_CLASS() | 
| 635 | 730 | 
| 636 def setUp(self): | 731 def setUp(self): | 
| 637 unittest.TestCase.setUp(self) | 732 unittest.TestCase.setUp(self) | 
| 638 self.FAKE_REPOS.setUp() | 733 self.FAKE_REPOS.set_up() | 
| 639 | 734 | 
| 640 # Remove left overs and start fresh. | 735 # Remove left overs and start fresh. | 
| 641 if not self.CLASS_ROOT_DIR: | 736 if not self.CLASS_ROOT_DIR: | 
| 642 self.CLASS_ROOT_DIR = join(self.FAKE_REPOS.trial_dir(), 'smoke') | 737 self.CLASS_ROOT_DIR = join(self.FAKE_REPOS.trial_dir(), 'smoke') | 
| 643 self.root_dir = join(self.CLASS_ROOT_DIR, self.id()) | 738 self.root_dir = join(self.CLASS_ROOT_DIR, self.id()) | 
| 644 rmtree(self.root_dir) | 739 rmtree(self.root_dir) | 
| 645 os.makedirs(self.root_dir) | 740 os.makedirs(self.root_dir) | 
| 646 self.svn_base = 'svn://%s/svn/' % self.FAKE_REPOS.HOST | 741 self.svn_base = 'svn://%s/svn/' % self.FAKE_REPOS.HOST | 
| 647 self.git_base = 'git://%s/git/' % self.FAKE_REPOS.HOST | 742 self.git_base = 'git://%s/git/' % self.FAKE_REPOS.HOST | 
| 648 | 743 | 
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 713 | 808 | 
| 714 def gittree(self, repo, rev): | 809 def gittree(self, repo, rev): | 
| 715 """Sort-hand: returns the directory tree for a git 'revision'.""" | 810 """Sort-hand: returns the directory tree for a git 'revision'.""" | 
| 716 return self.FAKE_REPOS.git_hashes[repo][int(rev)][1] | 811 return self.FAKE_REPOS.git_hashes[repo][int(rev)][1] | 
| 717 | 812 | 
| 718 | 813 | 
| 719 def main(argv): | 814 def main(argv): | 
| 720 fake = FakeRepos() | 815 fake = FakeRepos() | 
| 721 print 'Using %s' % fake.trial_dir() | 816 print 'Using %s' % fake.trial_dir() | 
| 722 try: | 817 try: | 
| 723 fake.setUp() | 818 fake.set_up_svn() | 
| 819 fake.set_up_git() | |
| 724 print('Fake setup, press enter to quit or Ctrl-C to keep the checkouts.') | 820 print('Fake setup, press enter to quit or Ctrl-C to keep the checkouts.') | 
| 725 sys.stdin.readline() | 821 sys.stdin.readline() | 
| 726 except KeyboardInterrupt: | 822 except KeyboardInterrupt: | 
| 727 fake.SHOULD_LEAK = True | 823 fake.SHOULD_LEAK = True | 
| 728 return 0 | 824 return 0 | 
| 729 | 825 | 
| 730 | 826 | 
| 731 if '-l' in sys.argv: | 827 if '-l' in sys.argv: | 
| 732 # See SHOULD_LEAK definition in FakeReposBase for its purpose. | 828 # See SHOULD_LEAK definition in FakeReposBase for its purpose. | 
| 733 FakeReposBase.SHOULD_LEAK = True | 829 FakeReposBase.SHOULD_LEAK = True | 
| 734 print 'Leaking!' | 830 print 'Leaking!' | 
| 735 sys.argv.remove('-l') | 831 sys.argv.remove('-l') | 
| 736 | 832 | 
| 737 | 833 | 
| 738 if __name__ == '__main__': | 834 if __name__ == '__main__': | 
| 739 sys.exit(main(sys.argv)) | 835 sys.exit(main(sys.argv)) | 
| OLD | NEW |