Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Side by Side Diff: checkout.py

Issue 11368148: Revert r166725 "Enforce 15 minutes timeout for all operations and 30 minutes..." (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # coding=utf8 1 # coding=utf8
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 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 """Manages a project checkout. 5 """Manages a project checkout.
6 6
7 Includes support for svn, git-svn and git. 7 Includes support for svn, git-svn and git.
8 """ 8 """
9 9
10 import ConfigParser 10 import ConfigParser
11 import fnmatch 11 import fnmatch
12 import logging 12 import logging
13 import os 13 import os
14 import re 14 import re
15 import shutil 15 import shutil
16 import subprocess 16 import subprocess
17 import sys 17 import sys
18 import tempfile 18 import tempfile
19 19
20 import patch 20 import patch
21 import scm 21 import scm
22 import subprocess2 22 import subprocess2
23 23
24 24
25 # Default timeout of 15 minutes.
26 GLOBAL_TIMEOUT = 15*60
27 # Use a larger timeout for checkout since it can be a genuinely slower
28 # operation.
29 FETCH_TIMEOUT = 30*60
30
31
32 def get_code_review_setting(path, key, 25 def get_code_review_setting(path, key,
33 codereview_settings_file='codereview.settings'): 26 codereview_settings_file='codereview.settings'):
34 """Parses codereview.settings and return the value for the key if present. 27 """Parses codereview.settings and return the value for the key if present.
35 28
36 Don't cache the values in case the file is changed.""" 29 Don't cache the values in case the file is changed."""
37 # TODO(maruel): Do not duplicate code. 30 # TODO(maruel): Do not duplicate code.
38 settings = {} 31 settings = {}
39 try: 32 try:
40 settings_file = open(os.path.join(path, codereview_settings_file), 'r') 33 settings_file = open(os.path.join(path, codereview_settings_file), 'r')
41 try: 34 try:
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 stdout.append('Copied %s -> %s' % (p.source_filename, p.filename)) 190 stdout.append('Copied %s -> %s' % (p.source_filename, p.filename))
198 if p.diff_hunks: 191 if p.diff_hunks:
199 cmd = ['patch', '-u', '--binary', '-p%s' % p.patchlevel] 192 cmd = ['patch', '-u', '--binary', '-p%s' % p.patchlevel]
200 if verbose: 193 if verbose:
201 cmd.append('--verbose') 194 cmd.append('--verbose')
202 stdout.append( 195 stdout.append(
203 subprocess2.check_output( 196 subprocess2.check_output(
204 cmd, 197 cmd,
205 stdin=p.get(False), 198 stdin=p.get(False),
206 stderr=subprocess2.STDOUT, 199 stderr=subprocess2.STDOUT,
207 cwd=self.project_path, 200 cwd=self.project_path))
208 timeout=GLOBAL_TIMEOUT))
209 elif p.is_new and not os.path.exists(filepath): 201 elif p.is_new and not os.path.exists(filepath):
210 # There is only a header. Just create the file. 202 # There is only a header. Just create the file.
211 open(filepath, 'w').close() 203 open(filepath, 'w').close()
212 stdout.append('Created an empty file.') 204 stdout.append('Created an empty file.')
213 for post in post_processors: 205 for post in post_processors:
214 post(self, p) 206 post(self, p)
215 if verbose: 207 if verbose:
216 print p.filename 208 print p.filename
217 print align_stdout(stdout) 209 print align_stdout(stdout)
218 except OSError, e: 210 except OSError, e:
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 if self.commit_user: 269 if self.commit_user:
278 args.extend(['--username', self.commit_user]) 270 args.extend(['--username', self.commit_user])
279 if self.commit_pwd: 271 if self.commit_pwd:
280 args.extend(['--password', self.commit_pwd]) 272 args.extend(['--password', self.commit_pwd])
281 return args 273 return args
282 274
283 def _check_call_svn(self, args, **kwargs): 275 def _check_call_svn(self, args, **kwargs):
284 """Runs svn and throws an exception if the command failed.""" 276 """Runs svn and throws an exception if the command failed."""
285 kwargs.setdefault('cwd', self.project_path) 277 kwargs.setdefault('cwd', self.project_path)
286 kwargs.setdefault('stdout', self.VOID) 278 kwargs.setdefault('stdout', self.VOID)
287 kwargs.setdefault('timeout', GLOBAL_TIMEOUT)
288 return subprocess2.check_call_out( 279 return subprocess2.check_call_out(
289 self._add_svn_flags(args, False), 280 self._add_svn_flags(args, False), **kwargs)
290 **kwargs)
291 281
292 def _check_output_svn(self, args, credentials=True, **kwargs): 282 def _check_output_svn(self, args, credentials=True, **kwargs):
293 """Runs svn and throws an exception if the command failed. 283 """Runs svn and throws an exception if the command failed.
294 284
295 Returns the output. 285 Returns the output.
296 """ 286 """
297 kwargs.setdefault('cwd', self.project_path) 287 kwargs.setdefault('cwd', self.project_path)
298 return subprocess2.check_output( 288 return subprocess2.check_output(
299 self._add_svn_flags(args, True, credentials), 289 self._add_svn_flags(args, True, credentials),
300 stderr=subprocess2.STDOUT, 290 stderr=subprocess2.STDOUT,
301 timeout=GLOBAL_TIMEOUT,
302 **kwargs) 291 **kwargs)
303 292
304 @staticmethod 293 @staticmethod
305 def _parse_svn_info(output, key): 294 def _parse_svn_info(output, key):
306 """Returns value for key from svn info output. 295 """Returns value for key from svn info output.
307 296
308 Case insensitive. 297 Case insensitive.
309 """ 298 """
310 values = {} 299 values = {}
311 key = key.lower() 300 key = key.lower()
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 if p.diff_hunks: 380 if p.diff_hunks:
392 cmd = [ 381 cmd = [
393 'patch', 382 'patch',
394 '-p%s' % p.patchlevel, 383 '-p%s' % p.patchlevel,
395 '--forward', 384 '--forward',
396 '--force', 385 '--force',
397 '--no-backup-if-mismatch', 386 '--no-backup-if-mismatch',
398 ] 387 ]
399 stdout.append( 388 stdout.append(
400 subprocess2.check_output( 389 subprocess2.check_output(
401 cmd, 390 cmd, stdin=p.get(False), cwd=self.project_path))
402 stdin=p.get(False),
403 cwd=self.project_path,
404 timeout=GLOBAL_TIMEOUT))
405 elif p.is_new and not os.path.exists(filepath): 391 elif p.is_new and not os.path.exists(filepath):
406 # There is only a header. Just create the file if it doesn't 392 # There is only a header. Just create the file if it doesn't
407 # exist. 393 # exist.
408 open(filepath, 'w').close() 394 open(filepath, 'w').close()
409 stdout.append('Created an empty file.') 395 stdout.append('Created an empty file.')
410 if p.is_new and not p.source_filename: 396 if p.is_new and not p.source_filename:
411 # Do not run it if p.source_filename is defined, since svn copy was 397 # Do not run it if p.source_filename is defined, since svn copy was
412 # using above. 398 # using above.
413 stdout.append( 399 stdout.append(
414 self._check_output_svn( 400 self._check_output_svn(
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 """Reverts local modifications or checks out if the directory is not 476 """Reverts local modifications or checks out if the directory is not
491 present. Use depot_tools's functionality to do this. 477 present. Use depot_tools's functionality to do this.
492 """ 478 """
493 flags = ['--ignore-externals'] 479 flags = ['--ignore-externals']
494 if revision: 480 if revision:
495 flags.extend(['--revision', str(revision)]) 481 flags.extend(['--revision', str(revision)])
496 if not os.path.isdir(self.project_path): 482 if not os.path.isdir(self.project_path):
497 logging.info( 483 logging.info(
498 'Directory %s is not present, checking it out.' % self.project_path) 484 'Directory %s is not present, checking it out.' % self.project_path)
499 self._check_call_svn( 485 self._check_call_svn(
500 ['checkout', self.svn_url, self.project_path] + flags, 486 ['checkout', self.svn_url, self.project_path] + flags, cwd=None)
501 cwd=None,
502 timeout=FETCH_TIMEOUT)
503 else: 487 else:
504 # TODO(maruel): This command will shell out without a timeout.
505 scm.SVN.Revert(self.project_path, no_ignore=True) 488 scm.SVN.Revert(self.project_path, no_ignore=True)
506 # Revive files that were deleted in scm.SVN.Revert(). 489 # Revive files that were deleted in scm.SVN.Revert().
507 self._check_call_svn(['update', '--force'] + flags, timeout=FETCH_TIMEOUT) 490 self._check_call_svn(['update', '--force'] + flags)
508 return self._get_revision() 491 return self._get_revision()
509 492
510 def _get_revision(self): 493 def _get_revision(self):
511 out = self._check_output_svn(['info', '.']) 494 out = self._check_output_svn(['info', '.'])
512 revision = int(self._parse_svn_info(out, 'revision')) 495 revision = int(self._parse_svn_info(out, 'revision'))
513 if revision != self._last_seen_revision: 496 if revision != self._last_seen_revision:
514 logging.info('Updated to revision %d' % revision) 497 logging.info('Updated to revision %d' % revision)
515 self._last_seen_revision = revision 498 self._last_seen_revision = revision
516 return revision 499 return revision
517 500
(...skipping 29 matching lines...) Expand all
547 530
548 Checks it out if not present and deletes the working branch. 531 Checks it out if not present and deletes the working branch.
549 """ 532 """
550 assert self.remote_branch 533 assert self.remote_branch
551 assert os.path.isdir(self.project_path) 534 assert os.path.isdir(self.project_path)
552 self._check_call_git(['reset', '--hard', '--quiet']) 535 self._check_call_git(['reset', '--hard', '--quiet'])
553 if revision: 536 if revision:
554 try: 537 try:
555 revision = self._check_output_git(['rev-parse', revision]) 538 revision = self._check_output_git(['rev-parse', revision])
556 except subprocess.CalledProcessError: 539 except subprocess.CalledProcessError:
557 self._fetch_remote() 540 self._check_call_git(
541 ['fetch', self.remote, self.remote_branch, '--quiet'])
558 revision = self._check_output_git(['rev-parse', revision]) 542 revision = self._check_output_git(['rev-parse', revision])
559 self._check_call_git(['checkout', '--force', '--quiet', revision]) 543 self._check_call_git(['checkout', '--force', '--quiet', revision])
560 else: 544 else:
561 branches, active = self._branches() 545 branches, active = self._branches()
562 if active != 'master': 546 if active != 'master':
563 self._check_call_git(['checkout', '--force', '--quiet', 'master']) 547 self._check_call_git(['checkout', '--force', '--quiet', 'master'])
564 self._check_call_git(['pull', self.remote, self.remote_branch, '--quiet']) 548 self._check_call_git(['pull', self.remote, self.remote_branch, '--quiet'])
565 if self.working_branch in branches: 549 if self.working_branch in branches:
566 self._call_git(['branch', '-D', self.working_branch]) 550 self._call_git(['branch', '-D', self.working_branch])
567 551
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
658 642
659 Subclass needs to dcommit or push. 643 Subclass needs to dcommit or push.
660 """ 644 """
661 assert isinstance(commit_message, unicode) 645 assert isinstance(commit_message, unicode)
662 self._check_call_git(['commit', '--amend', '-m', commit_message]) 646 self._check_call_git(['commit', '--amend', '-m', commit_message])
663 return self._check_output_git(['rev-parse', 'HEAD']).strip() 647 return self._check_output_git(['rev-parse', 'HEAD']).strip()
664 648
665 def _check_call_git(self, args, **kwargs): 649 def _check_call_git(self, args, **kwargs):
666 kwargs.setdefault('cwd', self.project_path) 650 kwargs.setdefault('cwd', self.project_path)
667 kwargs.setdefault('stdout', self.VOID) 651 kwargs.setdefault('stdout', self.VOID)
668 kwargs.setdefault('timeout', GLOBAL_TIMEOUT) 652 return subprocess2.check_call_out(['git'] + args, **kwargs)
669 return subprocess2.check_call_out(
670 ['git'] + args, **kwargs)
671 653
672 def _call_git(self, args, **kwargs): 654 def _call_git(self, args, **kwargs):
673 """Like check_call but doesn't throw on failure.""" 655 """Like check_call but doesn't throw on failure."""
674 kwargs.setdefault('cwd', self.project_path) 656 kwargs.setdefault('cwd', self.project_path)
675 kwargs.setdefault('stdout', self.VOID) 657 kwargs.setdefault('stdout', self.VOID)
676 return subprocess2.call(['git'] + args, timeout=GLOBAL_TIMEOUT, **kwargs) 658 return subprocess2.call(['git'] + args, **kwargs)
677 659
678 def _check_output_git(self, args, **kwargs): 660 def _check_output_git(self, args, **kwargs):
679 kwargs.setdefault('cwd', self.project_path) 661 kwargs.setdefault('cwd', self.project_path)
680 return subprocess2.check_output( 662 return subprocess2.check_output(
681 ['git'] + args, 663 ['git'] + args, stderr=subprocess2.STDOUT, **kwargs)
682 stderr=subprocess2.STDOUT,
683 timeout=GLOBAL_TIMEOUT,
684 **kwargs)
685 664
686 def _branches(self): 665 def _branches(self):
687 """Returns the list of branches and the active one.""" 666 """Returns the list of branches and the active one."""
688 out = self._check_output_git(['branch']).splitlines(False) 667 out = self._check_output_git(['branch']).splitlines(False)
689 branches = [l[2:] for l in out] 668 branches = [l[2:] for l in out]
690 active = None 669 active = None
691 for l in out: 670 for l in out:
692 if l.startswith('*'): 671 if l.startswith('*'):
693 active = l[2:] 672 active = l[2:]
694 break 673 break
(...skipping 14 matching lines...) Expand all
709 688
710 def _fetch_remote(self): 689 def _fetch_remote(self):
711 """Fetches the remote without rebasing.""" 690 """Fetches the remote without rebasing."""
712 raise NotImplementedError() 691 raise NotImplementedError()
713 692
714 693
715 class GitCheckout(GitCheckoutBase): 694 class GitCheckout(GitCheckoutBase):
716 """Git checkout implementation.""" 695 """Git checkout implementation."""
717 def _fetch_remote(self): 696 def _fetch_remote(self):
718 # git fetch is always verbose even with -q -q so redirect its output. 697 # git fetch is always verbose even with -q -q so redirect its output.
719 self._check_call_git( 698 self._check_output_git(['fetch', self.remote, self.remote_branch])
720 ['fetch', self.remote, self.remote_branch, '--quiet'],
721 timeout=FETCH_TIMEOUT)
722 699
723 700
724 class ReadOnlyCheckout(object): 701 class ReadOnlyCheckout(object):
725 """Converts a checkout into a read-only one.""" 702 """Converts a checkout into a read-only one."""
726 def __init__(self, checkout, post_processors=None): 703 def __init__(self, checkout, post_processors=None):
727 super(ReadOnlyCheckout, self).__init__() 704 super(ReadOnlyCheckout, self).__init__()
728 self.checkout = checkout 705 self.checkout = checkout
729 self.post_processors = (post_processors or []) + ( 706 self.post_processors = (post_processors or []) + (
730 self.checkout.post_processors or []) 707 self.checkout.post_processors or [])
731 708
(...skipping 15 matching lines...) Expand all
747 def revisions(self, rev1, rev2): 724 def revisions(self, rev1, rev2):
748 return self.checkout.revisions(rev1, rev2) 725 return self.checkout.revisions(rev1, rev2)
749 726
750 @property 727 @property
751 def project_name(self): 728 def project_name(self):
752 return self.checkout.project_name 729 return self.checkout.project_name
753 730
754 @property 731 @property
755 def project_path(self): 732 def project_path(self):
756 return self.checkout.project_path 733 return self.checkout.project_path
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698