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

Side by Side Diff: trychange.py

Issue 184343003: Now trychange can store patches in a Git repo (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: use contextmanager Created 6 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 | Annotate | Revision Log
« no previous file with comments | « tests/trychange_unittest.py ('k') | 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 #!/usr/bin/env python 1 #!/usr/bin/env python
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 5
6 """Client-side script to send a try job to the try server. It communicates to 6 """Client-side script to send a try job to the try server. It communicates to
7 the try server by either writting to a svn repository or by directly connecting 7 the try server by either writting to a svn/git repository or by directly
8 to the server by HTTP. 8 connecting to the server by HTTP.
9 """ 9 """
10 10
11
12 import contextlib
11 import datetime 13 import datetime
12 import errno 14 import errno
13 import getpass 15 import getpass
14 import itertools 16 import itertools
15 import json 17 import json
16 import logging 18 import logging
17 import optparse 19 import optparse
18 import os 20 import os
19 import posixpath 21 import posixpath
20 import re 22 import re
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 premade diff file on the local drive: 65 premade diff file on the local drive:
64 %(prog)s --email user@example.com 66 %(prog)s --email user@example.com
65 --svn_repo svn://svn.chromium.org/chrome-try/try --diff foo.diff 67 --svn_repo svn://svn.chromium.org/chrome-try/try --diff foo.diff
66 68
67 Running only on a 'mac' slave with revision 123 and clobber first; specify 69 Running only on a 'mac' slave with revision 123 and clobber first; specify
68 manually the 3 source files to use for the try job: 70 manually the 3 source files to use for the try job:
69 %(prog)s --bot mac --revision 123 --clobber -f src/a.cc -f src/a.h 71 %(prog)s --bot mac --revision 123 --clobber -f src/a.cc -f src/a.h
70 -f include/b.h 72 -f include/b.h
71 """ 73 """
72 74
75 GIT_PATCH_DIR_BASENAME = os.path.join('git-try', 'patches-git')
73 76
74 def DieWithError(message): 77 def DieWithError(message):
75 print >> sys.stderr, message 78 print >> sys.stderr, message
76 sys.exit(1) 79 sys.exit(1)
77 80
78 81
79 def RunCommand(args, error_ok=False, error_message=None, **kwargs): 82 def RunCommand(args, error_ok=False, error_message=None, **kwargs):
80 try: 83 try:
81 return subprocess2.check_output(args, shell=False, **kwargs) 84 return subprocess2.check_output(args, shell=False, **kwargs)
82 except subprocess2.CalledProcessError, e: 85 except subprocess2.CalledProcessError, e:
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 """Set default settings based on the gcl-style settings from the repository. 160 """Set default settings based on the gcl-style settings from the repository.
158 161
159 The settings in the self.options object will only be set if no previous 162 The settings in the self.options object will only be set if no previous
160 value exists (i.e. command line flags to the try command will override the 163 value exists (i.e. command line flags to the try command will override the
161 settings in codereview.settings). 164 settings in codereview.settings).
162 """ 165 """
163 settings = { 166 settings = {
164 'port': self.GetCodeReviewSetting('TRYSERVER_HTTP_PORT'), 167 'port': self.GetCodeReviewSetting('TRYSERVER_HTTP_PORT'),
165 'host': self.GetCodeReviewSetting('TRYSERVER_HTTP_HOST'), 168 'host': self.GetCodeReviewSetting('TRYSERVER_HTTP_HOST'),
166 'svn_repo': self.GetCodeReviewSetting('TRYSERVER_SVN_URL'), 169 'svn_repo': self.GetCodeReviewSetting('TRYSERVER_SVN_URL'),
170 'git_repo': self.GetCodeReviewSetting('TRYSERVER_GIT_URL'),
167 'project': self.GetCodeReviewSetting('TRYSERVER_PROJECT'), 171 'project': self.GetCodeReviewSetting('TRYSERVER_PROJECT'),
172 # primarily for revision=auto
173 'revision': self.GetCodeReviewSetting('TRYSERVER_REVISION'),
168 'root': self.GetCodeReviewSetting('TRYSERVER_ROOT'), 174 'root': self.GetCodeReviewSetting('TRYSERVER_ROOT'),
169 'patchlevel': self.GetCodeReviewSetting('TRYSERVER_PATCHLEVEL'), 175 'patchlevel': self.GetCodeReviewSetting('TRYSERVER_PATCHLEVEL'),
170 } 176 }
171 logging.info('\n'.join(['%s: %s' % (k, v) 177 logging.info('\n'.join(['%s: %s' % (k, v)
172 for (k, v) in settings.iteritems() if v])) 178 for (k, v) in settings.iteritems() if v]))
173 for (k, v) in settings.iteritems(): 179 for (k, v) in settings.iteritems():
174 # Avoid overwriting options already set using command line flags. 180 # Avoid overwriting options already set using command line flags.
175 if v and getattr(self.options, k) is None: 181 if v and getattr(self.options, k) is None:
176 setattr(self.options, k, v) 182 setattr(self.options, k, v)
177 183
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 285
280 The files in the list should either be absolute paths or relative to the 286 The files in the list should either be absolute paths or relative to the
281 given root. 287 given root.
282 """ 288 """
283 return scm.SVN.GenerateDiff(self.files, self.checkout_root, full_move=True, 289 return scm.SVN.GenerateDiff(self.files, self.checkout_root, full_move=True,
284 revision=self.diff_against) 290 revision=self.diff_against)
285 291
286 292
287 class GIT(SCM): 293 class GIT(SCM):
288 """Gathers the options and diff for a git checkout.""" 294 """Gathers the options and diff for a git checkout."""
295
289 def __init__(self, *args, **kwargs): 296 def __init__(self, *args, **kwargs):
290 SCM.__init__(self, *args, **kwargs) 297 SCM.__init__(self, *args, **kwargs)
291 self.checkout_root = scm.GIT.GetCheckoutRoot(self.checkout_root) 298 self.checkout_root = scm.GIT.GetCheckoutRoot(self.checkout_root)
292 if not self.options.name: 299 if not self.options.name:
293 self.options.name = scm.GIT.GetPatchName(self.checkout_root) 300 self.options.name = scm.GIT.GetPatchName(self.checkout_root)
294 if not self.options.email: 301 if not self.options.email:
295 self.options.email = scm.GIT.GetEmail(self.checkout_root) 302 self.options.email = scm.GIT.GetEmail(self.checkout_root)
296 if not self.diff_against: 303 if not self.diff_against:
297 self.diff_against = scm.GIT.GetUpstreamBranch(self.checkout_root) 304 self.diff_against = scm.GIT.GetUpstreamBranch(self.checkout_root)
298 if not self.diff_against: 305 if not self.diff_against:
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 410
404 bot_spec.extend(_ApplyTestFilter(options.testfilter, new_style)) 411 bot_spec.extend(_ApplyTestFilter(options.testfilter, new_style))
405 412
406 except ImportError: 413 except ImportError:
407 pass 414 pass
408 415
409 return bot_spec 416 return bot_spec
410 417
411 418
412 def _ParseSendChangeOptions(bot_spec, options): 419 def _ParseSendChangeOptions(bot_spec, options):
413 """Parse common options passed to _SendChangeHTTP and _SendChangeSVN.""" 420 """Parse common options passed to _SendChangeHTTP, _SendChangeSVN and
421 _SendChangeGit.
422 """
414 values = [ 423 values = [
415 ('user', options.user), 424 ('user', options.user),
416 ('name', options.name), 425 ('name', options.name),
417 ] 426 ]
418 if options.email: 427 if options.email:
419 values.append(('email', options.email)) 428 values.append(('email', options.email))
420 if options.revision: 429 if options.revision:
421 values.append(('revision', options.revision)) 430 values.append(('revision', options.revision))
422 if options.clobber: 431 if options.clobber:
423 values.append(('clobber', 'true')) 432 values.append(('clobber', 'true'))
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 str(e.args))) 483 str(e.args)))
475 if not connection: 484 if not connection:
476 raise NoTryServerAccess('%s is unaccessible.' % url) 485 raise NoTryServerAccess('%s is unaccessible.' % url)
477 logging.info('Reading response...') 486 logging.info('Reading response...')
478 response = connection.read() 487 response = connection.read()
479 logging.info('Done') 488 logging.info('Done')
480 if response != 'OK': 489 if response != 'OK':
481 raise NoTryServerAccess('%s is unaccessible. Got:\n%s' % (url, response)) 490 raise NoTryServerAccess('%s is unaccessible. Got:\n%s' % (url, response))
482 491
483 492
493 @contextlib.contextmanager
494 def _PrepareDescriptionAndPatchFiles(description, options):
495 """Create temporary files with description and patch, yield execution,
496 and delete the files.
497
498
499 __enter__ called on the return value returns a tuple of patch_filename and
500 description_filename.
501
502 Args:
503 description: contents of description file.
504 options: patchset options object. Must have attributes: user,
505 name (of patch) and diff (contents of patch).
506 """
507
508 # Create a temporary file and put description into it.
509 with tempfile.NamedTemporaryFile() as description_file:
510 description_file.write(description)
511 description_file.flush()
512
513 # Create a temporary directory, put a uniquely named file in it with the
514 # diff content
515 temp_dir = tempfile.mkdtemp()
516 try:
517 current_time = str(datetime.datetime.now()).replace(':', '.')
518 file_name = '%s.%s.%s.diff' % (Escape(options.user),
519 Escape(options.name), current_time)
520 full_patch_filename = os.path.join(temp_dir, file_name)
521 with open(full_patch_filename, 'wb') as f:
522 f.write(options.diff)
523
524 yield full_patch_filename, description_file.name
M-A Ruel 2014/03/25 01:42:56 If description_file.name is to be opened by anothe
nodir 2014/03/26 05:26:52 Done.
525 finally:
526 shutil.rmtree(temp_dir, True)
527
528
484 def _SendChangeSVN(bot_spec, options): 529 def _SendChangeSVN(bot_spec, options):
485 """Send a change to the try server by committing a diff file on a subversion 530 """Send a change to the try server by committing a diff file on a subversion
486 server.""" 531 server."""
487 if not options.svn_repo: 532 if not options.svn_repo:
488 raise NoTryServerAccess('Please use the --svn_repo option to specify the' 533 raise NoTryServerAccess('Please use the --svn_repo option to specify the'
489 ' try server svn repository to connect to.') 534 ' try server svn repository to connect to.')
490 535
491 values = _ParseSendChangeOptions(bot_spec, options) 536 values = _ParseSendChangeOptions(bot_spec, options)
492 description = ''.join("%s=%s\n" % (k, v) for k, v in values) 537 description = ''.join("%s=%s\n" % (k, v) for k, v in values)
493 logging.info('Sending by SVN') 538 logging.info('Sending by SVN')
494 logging.info(description) 539 logging.info(description)
495 logging.info(options.svn_repo) 540 logging.info(options.svn_repo)
496 logging.info(options.diff) 541 logging.info(options.diff)
497 if options.dry_run: 542 if options.dry_run:
498 return 543 return
499 544
500 # Create a temporary directory, put a uniquely named file in it with the diff 545 with _PrepareDescriptionAndPatchFiles(description, options) as (
501 # content and svn import that. 546 patch_filename, description_filename):
502 temp_dir = tempfile.mkdtemp() 547 if sys.platform == "cygwin":
503 temp_file = tempfile.NamedTemporaryFile() 548 # Small chromium-specific issue here:
504 try: 549 # git-try uses /usr/bin/python on cygwin but svn.bat will be used
550 # instead of /usr/bin/svn by default. That causes bad things(tm) since
551 # Windows' svn.exe has no clue about cygwin paths. Hence force to use
552 # the cygwin version in this particular context.
553 exe = "/usr/bin/svn"
554 else:
555 exe = "svn"
556 patch_dir = os.path.dirname(patch_filename)
557 command = [exe, 'import', '-q', patch_dir, options.svn_repo, '--file',
558 description_filename]
559 if scm.SVN.AssertVersion("1.5")[0]:
560 command.append('--no-ignore')
561
505 try: 562 try:
506 # Description
507 temp_file.write(description)
508 temp_file.flush()
509
510 # Diff file
511 current_time = str(datetime.datetime.now()).replace(':', '.')
512 file_name = (Escape(options.user) + '.' + Escape(options.name) +
513 '.%s.diff' % current_time)
514 full_path = os.path.join(temp_dir, file_name)
515 with open(full_path, 'wb') as f:
516 f.write(options.diff)
517
518 # Committing it will trigger a try job.
519 if sys.platform == "cygwin":
520 # Small chromium-specific issue here:
521 # git-try uses /usr/bin/python on cygwin but svn.bat will be used
522 # instead of /usr/bin/svn by default. That causes bad things(tm) since
523 # Windows' svn.exe has no clue about cygwin paths. Hence force to use
524 # the cygwin version in this particular context.
525 exe = "/usr/bin/svn"
526 else:
527 exe = "svn"
528 command = [exe, 'import', '-q', temp_dir, options.svn_repo, '--file',
529 temp_file.name]
530 if scm.SVN.AssertVersion("1.5")[0]:
531 command.append('--no-ignore')
532
533 subprocess2.check_call(command) 563 subprocess2.check_call(command)
534 except subprocess2.CalledProcessError, e: 564 except subprocess2.CalledProcessError, e:
535 raise NoTryServerAccess(str(e)) 565 raise NoTryServerAccess(str(e))
536 finally: 566
537 temp_file.close() 567
538 shutil.rmtree(temp_dir, True) 568 def _GetPatchGitRepo(git_url):
569 """Get a path to a Git repo with patches with latest changes,
M-A Ruel 2014/03/25 01:42:56 Imperattive everywhere.
nodir 2014/03/26 05:26:52 Not sure I got it. Isn't "Get a patch..." imperati
570 associated with the given url.
571
572 Store patches in .git/git-try/patches-git directory, a git repo. If it
573 doesn't exist yet or its origin URL is different, then clean up and clone it.
574 If it existed before, then pull changes.
575
576 Does not support SVN repo.
577
578 Returns a path to the directory with patches.
579 """
580 git_dir = scm.GIT.GetGitDir(os.getcwd())
581 patch_dir = os.path.join(git_dir, GIT_PATCH_DIR_BASENAME)
582
583 logging.info('Looking for git repo for patches')
584 # Is there already a repo with the expected url or should we clone?
585 clone = True
586 if os.path.exists(patch_dir) and scm.GIT.IsInsideWorkTree(patch_dir):
587 existing_url = scm.GIT.Capture(
588 ['config', '--local', 'remote.origin.url'],
589 cwd=patch_dir)
590 clone = existing_url != git_url
591
592 if clone:
593 if os.path.exists(patch_dir):
594 logging.info('Cleaning up')
595 shutil.rmtree(patch_dir, True)
596 logging.info('Cloning patch repo')
597 scm.GIT.Capture(['clone', git_url, GIT_PATCH_DIR_BASENAME], cwd=git_dir)
598 email = scm.GIT.GetEmail(cwd=os.getcwd())
599 scm.GIT.Capture(['config', '--local', 'user.email', email], patch_dir)
600 else:
601 if scm.GIT.IsWorkTreeDirty(patch_dir):
602 logging.info('Work dir is dirty: hard reset!')
603 scm.GIT.Capture(['reset', '--hard'], cwd=patch_dir)
604 logging.info('Updating patch repo')
605 scm.GIT.Capture(['pull', 'origin', 'master'], cwd=patch_dir)
M-A Ruel 2014/03/25 01:42:56 Technically, you don't want to pull other's patche
nodir 2014/03/26 05:26:52 Probably this is safer because the push won't be f
606
607 return patch_dir
608
609
610 def _SendChangeGit(bot_spec, options):
611 """Send a change to the try server by committing a diff file to a GIT repo"""
612 if not options.git_repo:
613 raise NoTryServerAccess('Please use the --git_repo option to specify the '
614 'try server git repository to connect to.')
615
616 values = _ParseSendChangeOptions(bot_spec, options)
617 comment_subject = '%s.%s' % (options.user, options.name)
618 comment_body = ''.join("%s=%s\n" % (k, v) for k, v in values)
619 description = '%s\n\n%s' % (comment_subject, comment_body)
620 logging.info('Sending by GIT')
621 logging.info(description)
622 logging.info(options.git_repo)
623 logging.info(options.diff)
624 if options.dry_run:
625 return
626
627 patch_dir = _GetPatchGitRepo(options.git_repo)
628 assert scm.GIT.IsInsideWorkTree(patch_dir)
629 assert not scm.GIT.IsWorkTreeDirty(patch_dir)
630
631 with _PrepareDescriptionAndPatchFiles(description, options) as (
632 patch_filename, description_filename):
633 logging.info('Committing patch')
634 target_filename = os.path.abspath(
635 os.path.join(patch_dir, os.path.basename(patch_filename)))
636 shutil.copyfile(patch_filename, target_filename)
637 try:
638 scm.GIT.Capture(['add', target_filename], cwd=patch_dir)
639 scm.GIT.Capture(['commit', '-F', description_filename], cwd=patch_dir)
640 assert not scm.GIT.IsWorkTreeDirty(patch_dir)
641 logging.info('Pushing patch')
642 scm.GIT.Capture(['push', 'origin', 'HEAD'], cwd=patch_dir)
M-A Ruel 2014/03/25 01:42:56 Pushing on origin/HEAD? Usually you push to a bran
nodir 2014/03/26 05:26:52 Done.
643 except subprocess2.CalledProcessError, e:
644 scm.GIT.Capture(['reset', '--hard', 'origin/master'], cwd=patch_dir)
645 raise NoTryServerAccess(str(e))
646
539 647
540 648
541 def PrintSuccess(bot_spec, options): 649 def PrintSuccess(bot_spec, options):
542 if not options.dry_run: 650 if not options.dry_run:
543 text = 'Patch \'%s\' sent to try server' % options.name 651 text = 'Patch \'%s\' sent to try server' % options.name
544 if bot_spec: 652 if bot_spec:
545 text += ': %s' % ', '.join( 653 text += ': %s' % ', '.join(
546 '%s:%s' % (b[0], ','.join(b[1])) for b in bot_spec) 654 '%s:%s' % (b[0], ','.join(b[1])) for b in bot_spec)
547 print(text) 655 print(text)
548 656
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 "times to specify multiple builders. ex: " 752 "times to specify multiple builders. ex: "
645 "'-bwin_rel:ui_tests,webkit_unit_tests -bwin_layout'. See " 753 "'-bwin_rel:ui_tests,webkit_unit_tests -bwin_layout'. See "
646 "the try server waterfall for the builders name and the tests " 754 "the try server waterfall for the builders name and the tests "
647 "available. Can also be used to specify gtest_filter, e.g. " 755 "available. Can also be used to specify gtest_filter, e.g. "
648 "-bwin_rel:base_unittests:ValuesTest.*Value")) 756 "-bwin_rel:base_unittests:ValuesTest.*Value"))
649 group.add_option("-B", "--print_bots", action="store_true", 757 group.add_option("-B", "--print_bots", action="store_true",
650 help="Print bots we would use (e.g. from PRESUBMIT.py)" 758 help="Print bots we would use (e.g. from PRESUBMIT.py)"
651 " and exit. Do not send patch. Like --dry_run" 759 " and exit. Do not send patch. Like --dry_run"
652 " but less verbose.") 760 " but less verbose.")
653 group.add_option("-r", "--revision", 761 group.add_option("-r", "--revision",
654 help="Revision to use for the try job; default: the " 762 help="Revision to use for the try job. If 'auto' is "
763 "specified, it is resolved to the revision a patch is "
764 "generated against (Git only). Default: the "
655 "revision will be determined by the try server; see " 765 "revision will be determined by the try server; see "
656 "its waterfall for more info") 766 "its waterfall for more info")
657 group.add_option("-c", "--clobber", action="store_true", 767 group.add_option("-c", "--clobber", action="store_true",
658 help="Force a clobber before building; e.g. don't do an " 768 help="Force a clobber before building; e.g. don't do an "
659 "incremental build") 769 "incremental build")
660 # TODO(maruel): help="Select a specific configuration, usually 'debug' or " 770 # TODO(maruel): help="Select a specific configuration, usually 'debug' or "
661 # "'release'" 771 # "'release'"
662 group.add_option("--target", help=optparse.SUPPRESS_HELP) 772 group.add_option("--target", help=optparse.SUPPRESS_HELP)
663 773
664 group.add_option("--project", 774 group.add_option("--project",
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
730 group.add_option("--use_svn", 840 group.add_option("--use_svn",
731 action="store_const", 841 action="store_const",
732 const=_SendChangeSVN, 842 const=_SendChangeSVN,
733 dest="send_patch", 843 dest="send_patch",
734 help="Use SVN to talk to the try server") 844 help="Use SVN to talk to the try server")
735 group.add_option("-S", "--svn_repo", 845 group.add_option("-S", "--svn_repo",
736 metavar="SVN_URL", 846 metavar="SVN_URL",
737 help="SVN url to use to write the changes in; --use_svn is " 847 help="SVN url to use to write the changes in; --use_svn is "
738 "implied when using --svn_repo") 848 "implied when using --svn_repo")
739 parser.add_option_group(group) 849 parser.add_option_group(group)
850
851 group = optparse.OptionGroup(parser, "Access the try server with Git")
852 group.add_option("--use_git",
853 action="store_const",
854 const=_SendChangeGit,
855 dest="send_patch",
856 help="Use GIT to talk to the try server")
857 group.add_option("-G", "--git_repo",
858 metavar="GIT_URL",
859 help="GIT url to use to write the changes in; --use_git is "
860 "implied when using --git_repo")
861 parser.add_option_group(group)
740 return parser 862 return parser
741 863
742 864
743 def TryChange(argv, 865 def TryChange(argv,
744 change, 866 change,
745 swallow_exception, 867 swallow_exception,
746 prog=None, 868 prog=None,
747 extra_epilog=None): 869 extra_epilog=None):
748 """ 870 """
749 Args: 871 Args:
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
798 match = re.match(r'^(.*)/(\d+)/?$', options.rietveld_url) 920 match = re.match(r'^(.*)/(\d+)/?$', options.rietveld_url)
799 if match: 921 if match:
800 if options.issue or options.patchset: 922 if options.issue or options.patchset:
801 parser.error('Cannot use both --issue and use a review number url') 923 parser.error('Cannot use both --issue and use a review number url')
802 options.issue = int(match.group(2)) 924 options.issue = int(match.group(2))
803 options.rietveld_url = match.group(1) 925 options.rietveld_url = match.group(1)
804 926
805 try: 927 try:
806 changed_files = None 928 changed_files = None
807 # Always include os.getcwd() in the checkout settings. 929 # Always include os.getcwd() in the checkout settings.
808 checkouts = []
809 path = os.getcwd() 930 path = os.getcwd()
810 931
811 file_list = [] 932 file_list = []
812 if options.files: 933 if options.files:
813 file_list = options.files 934 file_list = options.files
814 elif change: 935 elif change:
815 file_list = [f.LocalPath() for f in change.AffectedFiles()] 936 file_list = [f.LocalPath() for f in change.AffectedFiles()]
816 937
817 if options.upstream_branch: 938 if options.upstream_branch:
818 path += '@' + options.upstream_branch 939 path += '@' + options.upstream_branch
819 # Clear file list so that the correct list will be retrieved from the 940 # Clear file list so that the correct list will be retrieved from the
820 # upstream branch. 941 # upstream branch.
821 file_list = [] 942 file_list = []
822 checkouts.append(GuessVCS(options, path, file_list)) 943
823 checkouts[0].AutomagicalSettings() 944 current_vcs = GuessVCS(options, path, file_list)
945 current_vcs.AutomagicalSettings()
946 options = current_vcs.options
947 vcs_is_git = type(current_vcs) is GIT
948
949 # So far, git_repo doesn't work with SVN
950 if options.git_repo and not vcs_is_git:
951 parser.error('--git_repo option is supported only for GIT repositories')
952
953 # If revision==auto, resolve it
954 if options.revision and options.revision.lower() == 'auto':
955 if not vcs_is_git:
956 parser.error('--revision=auto is supported only for GIT repositories')
957 options.revision = scm.GIT.Capture(
958 ['rev-parse', current_vcs.diff_against],
959 cwd=path)
960
961 checkouts = [current_vcs]
824 for item in options.sub_rep: 962 for item in options.sub_rep:
825 # Pass file_list=None because we don't know the sub repo's file list. 963 # Pass file_list=None because we don't know the sub repo's file list.
826 checkout = GuessVCS(options, 964 checkout = GuessVCS(options,
827 os.path.join(checkouts[0].checkout_root, item), 965 os.path.join(current_vcs.checkout_root, item),
828 None) 966 None)
829 if checkout.checkout_root in [c.checkout_root for c in checkouts]: 967 if checkout.checkout_root in [c.checkout_root for c in checkouts]:
830 parser.error('Specified the root %s two times.' % 968 parser.error('Specified the root %s two times.' %
831 checkout.checkout_root) 969 checkout.checkout_root)
832 checkouts.append(checkout) 970 checkouts.append(checkout)
833 971
834 can_http = options.port and options.host 972 can_http = options.port and options.host
835 can_svn = options.svn_repo 973 can_svn = options.svn_repo
974 can_git = options.git_repo
836 # If there was no transport selected yet, now we must have enough data to 975 # If there was no transport selected yet, now we must have enough data to
837 # select one. 976 # select one.
838 if not options.send_patch and not (can_http or can_svn): 977 if not options.send_patch and not (can_http or can_svn or can_git):
839 parser.error('Please specify an access method.') 978 parser.error('Please specify an access method.')
840 979
841 # Convert options.diff into the content of the diff. 980 # Convert options.diff into the content of the diff.
842 if options.url: 981 if options.url:
843 if options.files: 982 if options.files:
844 parser.error('You cannot specify files and --url at the same time.') 983 parser.error('You cannot specify files and --url at the same time.')
845 options.diff = urllib2.urlopen(options.url).read() 984 options.diff = urllib2.urlopen(options.url).read()
846 elif options.diff: 985 elif options.diff:
847 if options.files: 986 if options.files:
848 parser.error('You cannot specify files and --diff at the same time.') 987 parser.error('You cannot specify files and --diff at the same time.')
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
906 1045
907 if options.print_bots: 1046 if options.print_bots:
908 print 'Bots which would be used:' 1047 print 'Bots which would be used:'
909 for bot in bot_spec: 1048 for bot in bot_spec:
910 if bot[1]: 1049 if bot[1]:
911 print ' %s:%s' % (bot[0], ','.join(bot[1])) 1050 print ' %s:%s' % (bot[0], ','.join(bot[1]))
912 else: 1051 else:
913 print ' %s' % (bot[0]) 1052 print ' %s' % (bot[0])
914 return 0 1053 return 0
915 1054
916 # Send the patch. 1055 # Determine sending protocol
917 if options.send_patch: 1056 if options.send_patch:
918 # If forced. 1057 # If forced.
919 options.send_patch(bot_spec, options) 1058 senders = [options.send_patch]
920 PrintSuccess(bot_spec, options) 1059 else:
921 return 0 1060 # Try sending patch using avaialble protocols
922 try: 1061 all_senders = [
923 if can_http: 1062 (_SendChangeHTTP, can_http),
924 _SendChangeHTTP(bot_spec, options) 1063 (_SendChangeSVN, can_svn),
1064 (_SendChangeGit, can_git)
1065 ]
1066 senders = [sender for sender, can in all_senders if can]
1067
1068 # Send the patch.
1069 for sender in senders:
1070 try:
1071 sender(bot_spec, options)
925 PrintSuccess(bot_spec, options) 1072 PrintSuccess(bot_spec, options)
926 return 0 1073 return 0
927 except NoTryServerAccess: 1074 except NoTryServerAccess:
928 if not can_svn: 1075 is_last = sender == senders[-1]
929 raise 1076 if is_last:
930 _SendChangeSVN(bot_spec, options) 1077 raise
931 PrintSuccess(bot_spec, options) 1078 assert False, "Unreachable code"
932 return 0
933 except (InvalidScript, NoTryServerAccess), e: 1079 except (InvalidScript, NoTryServerAccess), e:
934 if swallow_exception: 1080 if swallow_exception:
935 return 1 1081 return 1
936 print >> sys.stderr, e 1082 print >> sys.stderr, e
937 return 1 1083 return 1
938 except (gclient_utils.Error, subprocess2.CalledProcessError), e: 1084 except (gclient_utils.Error, subprocess2.CalledProcessError), e:
939 print >> sys.stderr, e 1085 print >> sys.stderr, e
940 return 1 1086 return 1
941 return 0 1087 return 0
942 1088
943 1089
944 if __name__ == "__main__": 1090 if __name__ == "__main__":
945 fix_encoding.fix_encoding() 1091 fix_encoding.fix_encoding()
946 sys.exit(TryChange(None, None, False)) 1092 sys.exit(TryChange(None, None, False))
OLDNEW
« no previous file with comments | « tests/trychange_unittest.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698