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 |