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

Side by Side Diff: checkout.py

Issue 12440058: Enforce 15 minutes timeout for all operations and 30 minutes for checkouts. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Created 7 years, 9 months 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
« 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 if sys.platform in ('cygwin', 'win32'):
26 # Disable timeouts on Windows since we can't have shells with timeouts.
27 GLOBAL_TIMEOUT = None
28 FETCH_TIMEOUT = None
29 else:
30 # Default timeout of 15 minutes.
31 GLOBAL_TIMEOUT = 15*60
32 # Use a larger timeout for checkout since it can be a genuinely slower
33 # operation.
34 FETCH_TIMEOUT = 30*60
35
36
25 def get_code_review_setting(path, key, 37 def get_code_review_setting(path, key,
26 codereview_settings_file='codereview.settings'): 38 codereview_settings_file='codereview.settings'):
27 """Parses codereview.settings and return the value for the key if present. 39 """Parses codereview.settings and return the value for the key if present.
28 40
29 Don't cache the values in case the file is changed.""" 41 Don't cache the values in case the file is changed."""
30 # TODO(maruel): Do not duplicate code. 42 # TODO(maruel): Do not duplicate code.
31 settings = {} 43 settings = {}
32 try: 44 try:
33 settings_file = open(os.path.join(path, codereview_settings_file), 'r') 45 settings_file = open(os.path.join(path, codereview_settings_file), 'r')
34 try: 46 try:
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
190 stdout.append('Copied %s -> %s' % (p.source_filename, p.filename)) 202 stdout.append('Copied %s -> %s' % (p.source_filename, p.filename))
191 if p.diff_hunks: 203 if p.diff_hunks:
192 cmd = ['patch', '-u', '--binary', '-p%s' % p.patchlevel] 204 cmd = ['patch', '-u', '--binary', '-p%s' % p.patchlevel]
193 if verbose: 205 if verbose:
194 cmd.append('--verbose') 206 cmd.append('--verbose')
195 stdout.append( 207 stdout.append(
196 subprocess2.check_output( 208 subprocess2.check_output(
197 cmd, 209 cmd,
198 stdin=p.get(False), 210 stdin=p.get(False),
199 stderr=subprocess2.STDOUT, 211 stderr=subprocess2.STDOUT,
200 cwd=self.project_path)) 212 cwd=self.project_path,
213 timeout=GLOBAL_TIMEOUT))
201 elif p.is_new and not os.path.exists(filepath): 214 elif p.is_new and not os.path.exists(filepath):
202 # There is only a header. Just create the file. 215 # There is only a header. Just create the file.
203 open(filepath, 'w').close() 216 open(filepath, 'w').close()
204 stdout.append('Created an empty file.') 217 stdout.append('Created an empty file.')
205 for post in post_processors: 218 for post in post_processors:
206 post(self, p) 219 post(self, p)
207 if verbose: 220 if verbose:
208 print p.filename 221 print p.filename
209 print align_stdout(stdout) 222 print align_stdout(stdout)
210 except OSError, e: 223 except OSError, e:
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 if self.commit_user: 282 if self.commit_user:
270 args.extend(['--username', self.commit_user]) 283 args.extend(['--username', self.commit_user])
271 if self.commit_pwd: 284 if self.commit_pwd:
272 args.extend(['--password', self.commit_pwd]) 285 args.extend(['--password', self.commit_pwd])
273 return args 286 return args
274 287
275 def _check_call_svn(self, args, **kwargs): 288 def _check_call_svn(self, args, **kwargs):
276 """Runs svn and throws an exception if the command failed.""" 289 """Runs svn and throws an exception if the command failed."""
277 kwargs.setdefault('cwd', self.project_path) 290 kwargs.setdefault('cwd', self.project_path)
278 kwargs.setdefault('stdout', self.VOID) 291 kwargs.setdefault('stdout', self.VOID)
292 kwargs.setdefault('timeout', GLOBAL_TIMEOUT)
279 return subprocess2.check_call_out( 293 return subprocess2.check_call_out(
280 self._add_svn_flags(args, False), **kwargs) 294 self._add_svn_flags(args, False), **kwargs)
281 295
282 def _check_output_svn(self, args, credentials=True, **kwargs): 296 def _check_output_svn(self, args, credentials=True, **kwargs):
283 """Runs svn and throws an exception if the command failed. 297 """Runs svn and throws an exception if the command failed.
284 298
285 Returns the output. 299 Returns the output.
286 """ 300 """
287 kwargs.setdefault('cwd', self.project_path) 301 kwargs.setdefault('cwd', self.project_path)
288 return subprocess2.check_output( 302 return subprocess2.check_output(
289 self._add_svn_flags(args, True, credentials), 303 self._add_svn_flags(args, True, credentials),
290 stderr=subprocess2.STDOUT, 304 stderr=subprocess2.STDOUT,
305 timeout=GLOBAL_TIMEOUT,
291 **kwargs) 306 **kwargs)
292 307
293 @staticmethod 308 @staticmethod
294 def _parse_svn_info(output, key): 309 def _parse_svn_info(output, key):
295 """Returns value for key from svn info output. 310 """Returns value for key from svn info output.
296 311
297 Case insensitive. 312 Case insensitive.
298 """ 313 """
299 values = {} 314 values = {}
300 key = key.lower() 315 key = key.lower()
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 if p.diff_hunks: 395 if p.diff_hunks:
381 cmd = [ 396 cmd = [
382 'patch', 397 'patch',
383 '-p%s' % p.patchlevel, 398 '-p%s' % p.patchlevel,
384 '--forward', 399 '--forward',
385 '--force', 400 '--force',
386 '--no-backup-if-mismatch', 401 '--no-backup-if-mismatch',
387 ] 402 ]
388 stdout.append( 403 stdout.append(
389 subprocess2.check_output( 404 subprocess2.check_output(
390 cmd, stdin=p.get(False), cwd=self.project_path)) 405 cmd,
406 stdin=p.get(False),
407 cwd=self.project_path,
408 timeout=GLOBAL_TIMEOUT))
391 elif p.is_new and not os.path.exists(filepath): 409 elif p.is_new and not os.path.exists(filepath):
392 # There is only a header. Just create the file if it doesn't 410 # There is only a header. Just create the file if it doesn't
393 # exist. 411 # exist.
394 open(filepath, 'w').close() 412 open(filepath, 'w').close()
395 stdout.append('Created an empty file.') 413 stdout.append('Created an empty file.')
396 if p.is_new and not p.source_filename: 414 if p.is_new and not p.source_filename:
397 # Do not run it if p.source_filename is defined, since svn copy was 415 # Do not run it if p.source_filename is defined, since svn copy was
398 # using above. 416 # using above.
399 stdout.append( 417 stdout.append(
400 self._check_output_svn( 418 self._check_output_svn(
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
478 """ 496 """
479 flags = ['--ignore-externals'] 497 flags = ['--ignore-externals']
480 if revision: 498 if revision:
481 flags.extend(['--revision', str(revision)]) 499 flags.extend(['--revision', str(revision)])
482 if os.path.isdir(self.project_path): 500 if os.path.isdir(self.project_path):
483 # This may remove any part (or all) of the checkout. 501 # This may remove any part (or all) of the checkout.
484 scm.SVN.Revert(self.project_path, no_ignore=True) 502 scm.SVN.Revert(self.project_path, no_ignore=True)
485 503
486 if os.path.isdir(self.project_path): 504 if os.path.isdir(self.project_path):
487 # Revive files that were deleted in scm.SVN.Revert(). 505 # Revive files that were deleted in scm.SVN.Revert().
488 self._check_call_svn(['update', '--force'] + flags) 506 self._check_call_svn(['update', '--force'] + flags,
507 timeout=FETCH_TIMEOUT)
489 else: 508 else:
490 logging.info( 509 logging.info(
491 'Directory %s is not present, checking it out.' % self.project_path) 510 'Directory %s is not present, checking it out.' % self.project_path)
492 self._check_call_svn( 511 self._check_call_svn(
493 ['checkout', self.svn_url, self.project_path] + flags, cwd=None) 512 ['checkout', self.svn_url, self.project_path] + flags, cwd=None,
513 timeout=FETCH_TIMEOUT)
494 return self._get_revision() 514 return self._get_revision()
495 515
496 def _get_revision(self): 516 def _get_revision(self):
497 out = self._check_output_svn(['info', '.']) 517 out = self._check_output_svn(['info', '.'])
498 revision = int(self._parse_svn_info(out, 'revision')) 518 revision = int(self._parse_svn_info(out, 'revision'))
499 if revision != self._last_seen_revision: 519 if revision != self._last_seen_revision:
500 logging.info('Updated to revision %d' % revision) 520 logging.info('Updated to revision %d' % revision)
501 self._last_seen_revision = revision 521 self._last_seen_revision = revision
502 return revision 522 return revision
503 523
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 665
646 Subclass needs to dcommit or push. 666 Subclass needs to dcommit or push.
647 """ 667 """
648 assert isinstance(commit_message, unicode) 668 assert isinstance(commit_message, unicode)
649 self._check_call_git(['commit', '--amend', '-m', commit_message]) 669 self._check_call_git(['commit', '--amend', '-m', commit_message])
650 return self._check_output_git(['rev-parse', 'HEAD']).strip() 670 return self._check_output_git(['rev-parse', 'HEAD']).strip()
651 671
652 def _check_call_git(self, args, **kwargs): 672 def _check_call_git(self, args, **kwargs):
653 kwargs.setdefault('cwd', self.project_path) 673 kwargs.setdefault('cwd', self.project_path)
654 kwargs.setdefault('stdout', self.VOID) 674 kwargs.setdefault('stdout', self.VOID)
675 kwargs.setdefault('timeout', GLOBAL_TIMEOUT)
655 return subprocess2.check_call_out(['git'] + args, **kwargs) 676 return subprocess2.check_call_out(['git'] + args, **kwargs)
656 677
657 def _call_git(self, args, **kwargs): 678 def _call_git(self, args, **kwargs):
658 """Like check_call but doesn't throw on failure.""" 679 """Like check_call but doesn't throw on failure."""
659 kwargs.setdefault('cwd', self.project_path) 680 kwargs.setdefault('cwd', self.project_path)
660 kwargs.setdefault('stdout', self.VOID) 681 kwargs.setdefault('stdout', self.VOID)
682 kwargs.setdefault('timeout', GLOBAL_TIMEOUT)
661 return subprocess2.call(['git'] + args, **kwargs) 683 return subprocess2.call(['git'] + args, **kwargs)
662 684
663 def _check_output_git(self, args, **kwargs): 685 def _check_output_git(self, args, **kwargs):
664 kwargs.setdefault('cwd', self.project_path) 686 kwargs.setdefault('cwd', self.project_path)
687 kwargs.setdefault('timeout', GLOBAL_TIMEOUT)
665 return subprocess2.check_output( 688 return subprocess2.check_output(
666 ['git'] + args, stderr=subprocess2.STDOUT, **kwargs) 689 ['git'] + args, stderr=subprocess2.STDOUT, **kwargs)
667 690
668 def _branches(self): 691 def _branches(self):
669 """Returns the list of branches and the active one.""" 692 """Returns the list of branches and the active one."""
670 out = self._check_output_git(['branch']).splitlines(False) 693 out = self._check_output_git(['branch']).splitlines(False)
671 branches = [l[2:] for l in out] 694 branches = [l[2:] for l in out]
672 active = None 695 active = None
673 for l in out: 696 for l in out:
674 if l.startswith('*'): 697 if l.startswith('*'):
(...skipping 16 matching lines...) Expand all
691 714
692 def _fetch_remote(self): 715 def _fetch_remote(self):
693 """Fetches the remote without rebasing.""" 716 """Fetches the remote without rebasing."""
694 raise NotImplementedError() 717 raise NotImplementedError()
695 718
696 719
697 class GitCheckout(GitCheckoutBase): 720 class GitCheckout(GitCheckoutBase):
698 """Git checkout implementation.""" 721 """Git checkout implementation."""
699 def _fetch_remote(self): 722 def _fetch_remote(self):
700 # git fetch is always verbose even with -q -q so redirect its output. 723 # git fetch is always verbose even with -q -q so redirect its output.
701 self._check_output_git(['fetch', self.remote, self.remote_branch]) 724 self._check_output_git(['fetch', self.remote, self.remote_branch],
725 timeout=FETCH_TIMEOUT)
702 726
703 727
704 class ReadOnlyCheckout(object): 728 class ReadOnlyCheckout(object):
705 """Converts a checkout into a read-only one.""" 729 """Converts a checkout into a read-only one."""
706 def __init__(self, checkout, post_processors=None): 730 def __init__(self, checkout, post_processors=None):
707 super(ReadOnlyCheckout, self).__init__() 731 super(ReadOnlyCheckout, self).__init__()
708 self.checkout = checkout 732 self.checkout = checkout
709 self.post_processors = (post_processors or []) + ( 733 self.post_processors = (post_processors or []) + (
710 self.checkout.post_processors or []) 734 self.checkout.post_processors or [])
711 735
(...skipping 15 matching lines...) Expand all
727 def revisions(self, rev1, rev2): 751 def revisions(self, rev1, rev2):
728 return self.checkout.revisions(rev1, rev2) 752 return self.checkout.revisions(rev1, rev2)
729 753
730 @property 754 @property
731 def project_name(self): 755 def project_name(self):
732 return self.checkout.project_name 756 return self.checkout.project_name
733 757
734 @property 758 @property
735 def project_path(self): 759 def project_path(self):
736 return self.checkout.project_path 760 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