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

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: branch -> ref 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 import contextlib
11 import datetime 12 import datetime
12 import errno 13 import errno
13 import getpass 14 import getpass
14 import itertools 15 import itertools
15 import json 16 import json
16 import logging 17 import logging
17 import optparse 18 import optparse
18 import os 19 import os
19 import posixpath 20 import posixpath
20 import re 21 import re
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 premade diff file on the local drive: 64 premade diff file on the local drive:
64 %(prog)s --email user@example.com 65 %(prog)s --email user@example.com
65 --svn_repo svn://svn.chromium.org/chrome-try/try --diff foo.diff 66 --svn_repo svn://svn.chromium.org/chrome-try/try --diff foo.diff
66 67
67 Running only on a 'mac' slave with revision 123 and clobber first; specify 68 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: 69 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 70 %(prog)s --bot mac --revision 123 --clobber -f src/a.cc -f src/a.h
70 -f include/b.h 71 -f include/b.h
71 """ 72 """
72 73
74 GIT_PATCH_DIR_BASENAME = os.path.join('git-try', 'patches-git')
75 GIT_BRANCH_FILE = 'ref'
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 225 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 409
404 bot_spec.extend(_ApplyTestFilter(options.testfilter, new_style)) 410 bot_spec.extend(_ApplyTestFilter(options.testfilter, new_style))
405 411
406 except ImportError: 412 except ImportError:
407 pass 413 pass
408 414
409 return bot_spec 415 return bot_spec
410 416
411 417
412 def _ParseSendChangeOptions(bot_spec, options): 418 def _ParseSendChangeOptions(bot_spec, options):
413 """Parse common options passed to _SendChangeHTTP and _SendChangeSVN.""" 419 """Parse common options passed to _SendChangeHTTP, _SendChangeSVN and
420 _SendChangeGit.
421 """
414 values = [ 422 values = [
415 ('user', options.user), 423 ('user', options.user),
416 ('name', options.name), 424 ('name', options.name),
417 ] 425 ]
418 if options.email: 426 if options.email:
419 values.append(('email', options.email)) 427 values.append(('email', options.email))
420 if options.revision: 428 if options.revision:
421 values.append(('revision', options.revision)) 429 values.append(('revision', options.revision))
422 if options.clobber: 430 if options.clobber:
423 values.append(('clobber', 'true')) 431 values.append(('clobber', 'true'))
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 str(e.args))) 482 str(e.args)))
475 if not connection: 483 if not connection:
476 raise NoTryServerAccess('%s is unaccessible.' % url) 484 raise NoTryServerAccess('%s is unaccessible.' % url)
477 logging.info('Reading response...') 485 logging.info('Reading response...')
478 response = connection.read() 486 response = connection.read()
479 logging.info('Done') 487 logging.info('Done')
480 if response != 'OK': 488 if response != 'OK':
481 raise NoTryServerAccess('%s is unaccessible. Got:\n%s' % (url, response)) 489 raise NoTryServerAccess('%s is unaccessible. Got:\n%s' % (url, response))
482 490
483 491
492 @contextlib.contextmanager
493 def _TempFilename(name, contents=None):
494 """Create a temporary directory, append the specified name and yield.
495
496 In contrast to NamedTemporaryFile, does not keep the file open.
497 Deletes the file on __exit__.
498 """
499 temp_dir = tempfile.mkdtemp(prefix=name)
500 try:
501 path = os.path.join(temp_dir, name)
502 if contents:
503 with open(path, 'w') as f:
504 f.write(contents)
505 yield path
506 finally:
507 shutil.rmtree(temp_dir, True)
508
509
510 @contextlib.contextmanager
511 def _PrepareDescriptionAndPatchFiles(description, options):
512 """Creates temporary files with description and patch.
513
514 __enter__ called on the return value returns a tuple of patch_filename and
515 description_filename.
516
517 Args:
518 description: contents of description file.
519 options: patchset options object. Must have attributes: user,
520 name (of patch) and diff (contents of patch).
521 """
522 current_time = str(datetime.datetime.now()).replace(':', '.')
523 patch_basename = '%s.%s.%s.diff' % (Escape(options.user),
524 Escape(options.name), current_time)
525 with _TempFilename('description', description) as description_filename:
526 with _TempFilename(patch_basename, options.diff) as patch_filename:
527 yield patch_filename, description_filename
528
529
484 def _SendChangeSVN(bot_spec, options): 530 def _SendChangeSVN(bot_spec, options):
485 """Send a change to the try server by committing a diff file on a subversion 531 """Send a change to the try server by committing a diff file on a subversion
486 server.""" 532 server."""
487 if not options.svn_repo: 533 if not options.svn_repo:
488 raise NoTryServerAccess('Please use the --svn_repo option to specify the' 534 raise NoTryServerAccess('Please use the --svn_repo option to specify the'
489 ' try server svn repository to connect to.') 535 ' try server svn repository to connect to.')
490 536
491 values = _ParseSendChangeOptions(bot_spec, options) 537 values = _ParseSendChangeOptions(bot_spec, options)
492 description = ''.join("%s=%s\n" % (k, v) for k, v in values) 538 description = ''.join("%s=%s\n" % (k, v) for k, v in values)
493 logging.info('Sending by SVN') 539 logging.info('Sending by SVN')
494 logging.info(description) 540 logging.info(description)
495 logging.info(options.svn_repo) 541 logging.info(options.svn_repo)
496 logging.info(options.diff) 542 logging.info(options.diff)
497 if options.dry_run: 543 if options.dry_run:
498 return 544 return
499 545
500 # Create a temporary directory, put a uniquely named file in it with the diff 546 with _PrepareDescriptionAndPatchFiles(description, options) as (
501 # content and svn import that. 547 patch_filename, description_filename):
502 temp_dir = tempfile.mkdtemp() 548 if sys.platform == "cygwin":
503 temp_file = tempfile.NamedTemporaryFile() 549 # Small chromium-specific issue here:
504 try: 550 # git-try uses /usr/bin/python on cygwin but svn.bat will be used
551 # instead of /usr/bin/svn by default. That causes bad things(tm) since
552 # Windows' svn.exe has no clue about cygwin paths. Hence force to use
553 # the cygwin version in this particular context.
554 exe = "/usr/bin/svn"
555 else:
556 exe = "svn"
557 patch_dir = os.path.dirname(patch_filename)
558 command = [exe, 'import', '-q', patch_dir, options.svn_repo, '--file',
559 description_filename]
560 if scm.SVN.AssertVersion("1.5")[0]:
561 command.append('--no-ignore')
562
505 try: 563 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) 564 subprocess2.check_call(command)
534 except subprocess2.CalledProcessError, e: 565 except subprocess2.CalledProcessError, e:
535 raise NoTryServerAccess(str(e)) 566 raise NoTryServerAccess(str(e))
536 finally: 567
537 temp_file.close() 568
538 shutil.rmtree(temp_dir, True) 569 def _GetPatchGitRepo(git_url):
570 """Gets a path to a Git repo with patches.
571
572 Stores patches in .git/git-try/patches-git directory, a git repo. If it
573 doesn't exist yet or its origin URL is different, cleans up and clones it.
574 If it existed before, then pulls 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], cwd=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)
606
607 return os.path.abspath(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 def patch_git(*args):
629 return scm.GIT.Capture(list(args), cwd=patch_dir)
630 def add_and_commit(filename, comment_filename):
631 patch_git('add', filename)
632 patch_git('commit', '-F', comment_filename)
633
634 assert scm.GIT.IsInsideWorkTree(patch_dir)
635 assert not scm.GIT.IsWorkTreeDirty(patch_dir)
636
637 with _PrepareDescriptionAndPatchFiles(description, options) as (
638 patch_filename, description_filename):
639 logging.info('Committing patch')
640 target_branch = ('refs/patches/' +
641 os.path.basename(patch_filename).replace(' ','-'))
642 target_filename = os.path.join(patch_dir, 'patch.diff')
643 branch_file = os.path.join(patch_dir, GIT_BRANCH_FILE)
644 try:
645 # Crete a new branch and put the patch there
646 patch_git('checkout', '--orphan', target_branch)
647 patch_git('reset')
648 patch_git('clean', '-f')
649 shutil.copyfile(patch_filename, target_filename)
650 add_and_commit(target_filename, description_filename)
651 assert not scm.GIT.IsWorkTreeDirty(patch_dir)
652
653 # Update the branch file in the master
654 patch_git('checkout', 'master')
655
656 def update_branch():
657 with open(branch_file, 'w') as f:
658 f.write(target_branch)
659 add_and_commit(branch_file, description_filename)
660 def push():
661 patch_git('push', 'origin', 'master', target_branch)
662 def push_fixup():
663 patch_git('fetch', 'origin')
664 patch_git('reset', '--hard', 'origin/master')
665 update_branch()
666 def push_failed():
667 raise NoTryServerAccess(str(e))
668
669 update_branch()
670 logging.info('Pushing patch')
671 _retry(push, push_fixup, push_failed)
672 except subprocess2.CalledProcessError, e:
673 # Restore state.
674 patch_git('checkout', 'master')
675 patch_git('reset', '--hard', 'origin/master')
676 raise
677
678
679 def _retry(action, fixup, fail, attempts=3):
680 """Calls action until it passes without exceptions"""
681 for attempt in xrange(attempts):
682 try:
683 action()
684 except subprocess2.CalledProcessError:
685 is_last = attempt == attempts - 1
686 if is_last:
687 fail()
688 else:
689 fixup()
539 690
540 691
541 def PrintSuccess(bot_spec, options): 692 def PrintSuccess(bot_spec, options):
542 if not options.dry_run: 693 if not options.dry_run:
543 text = 'Patch \'%s\' sent to try server' % options.name 694 text = 'Patch \'%s\' sent to try server' % options.name
544 if bot_spec: 695 if bot_spec:
545 text += ': %s' % ', '.join( 696 text += ': %s' % ', '.join(
546 '%s:%s' % (b[0], ','.join(b[1])) for b in bot_spec) 697 '%s:%s' % (b[0], ','.join(b[1])) for b in bot_spec)
547 print(text) 698 print(text)
548 699
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 "times to specify multiple builders. ex: " 795 "times to specify multiple builders. ex: "
645 "'-bwin_rel:ui_tests,webkit_unit_tests -bwin_layout'. See " 796 "'-bwin_rel:ui_tests,webkit_unit_tests -bwin_layout'. See "
646 "the try server waterfall for the builders name and the tests " 797 "the try server waterfall for the builders name and the tests "
647 "available. Can also be used to specify gtest_filter, e.g. " 798 "available. Can also be used to specify gtest_filter, e.g. "
648 "-bwin_rel:base_unittests:ValuesTest.*Value")) 799 "-bwin_rel:base_unittests:ValuesTest.*Value"))
649 group.add_option("-B", "--print_bots", action="store_true", 800 group.add_option("-B", "--print_bots", action="store_true",
650 help="Print bots we would use (e.g. from PRESUBMIT.py)" 801 help="Print bots we would use (e.g. from PRESUBMIT.py)"
651 " and exit. Do not send patch. Like --dry_run" 802 " and exit. Do not send patch. Like --dry_run"
652 " but less verbose.") 803 " but less verbose.")
653 group.add_option("-r", "--revision", 804 group.add_option("-r", "--revision",
654 help="Revision to use for the try job; default: the " 805 help="Revision to use for the try job. If 'auto' is "
806 "specified, it is resolved to the revision a patch is "
807 "generated against (Git only). Default: the "
655 "revision will be determined by the try server; see " 808 "revision will be determined by the try server; see "
656 "its waterfall for more info") 809 "its waterfall for more info")
657 group.add_option("-c", "--clobber", action="store_true", 810 group.add_option("-c", "--clobber", action="store_true",
658 help="Force a clobber before building; e.g. don't do an " 811 help="Force a clobber before building; e.g. don't do an "
659 "incremental build") 812 "incremental build")
660 # TODO(maruel): help="Select a specific configuration, usually 'debug' or " 813 # TODO(maruel): help="Select a specific configuration, usually 'debug' or "
661 # "'release'" 814 # "'release'"
662 group.add_option("--target", help=optparse.SUPPRESS_HELP) 815 group.add_option("--target", help=optparse.SUPPRESS_HELP)
663 816
664 group.add_option("--project", 817 group.add_option("--project",
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
730 group.add_option("--use_svn", 883 group.add_option("--use_svn",
731 action="store_const", 884 action="store_const",
732 const=_SendChangeSVN, 885 const=_SendChangeSVN,
733 dest="send_patch", 886 dest="send_patch",
734 help="Use SVN to talk to the try server") 887 help="Use SVN to talk to the try server")
735 group.add_option("-S", "--svn_repo", 888 group.add_option("-S", "--svn_repo",
736 metavar="SVN_URL", 889 metavar="SVN_URL",
737 help="SVN url to use to write the changes in; --use_svn is " 890 help="SVN url to use to write the changes in; --use_svn is "
738 "implied when using --svn_repo") 891 "implied when using --svn_repo")
739 parser.add_option_group(group) 892 parser.add_option_group(group)
893
894 group = optparse.OptionGroup(parser, "Access the try server with Git")
895 group.add_option("--use_git",
ghost stip (do not use) 2014/03/28 23:24:08 it doesn't look like this option is used, please d
nodir 2014/03/31 20:25:14 It is used the same way as use_svn. If set, the op
896 action="store_const",
897 const=_SendChangeGit,
898 dest="send_patch",
899 help="Use GIT to talk to the try server")
900 group.add_option("-G", "--git_repo",
901 metavar="GIT_URL",
902 help="GIT url to use to write the changes in; --use_git is "
903 "implied when using --git_repo")
904 parser.add_option_group(group)
740 return parser 905 return parser
741 906
742 907
743 def TryChange(argv, 908 def TryChange(argv,
744 change, 909 change,
745 swallow_exception, 910 swallow_exception,
746 prog=None, 911 prog=None,
747 extra_epilog=None): 912 extra_epilog=None):
748 """ 913 """
749 Args: 914 Args:
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
798 match = re.match(r'^(.*)/(\d+)/?$', options.rietveld_url) 963 match = re.match(r'^(.*)/(\d+)/?$', options.rietveld_url)
799 if match: 964 if match:
800 if options.issue or options.patchset: 965 if options.issue or options.patchset:
801 parser.error('Cannot use both --issue and use a review number url') 966 parser.error('Cannot use both --issue and use a review number url')
802 options.issue = int(match.group(2)) 967 options.issue = int(match.group(2))
803 options.rietveld_url = match.group(1) 968 options.rietveld_url = match.group(1)
804 969
805 try: 970 try:
806 changed_files = None 971 changed_files = None
807 # Always include os.getcwd() in the checkout settings. 972 # Always include os.getcwd() in the checkout settings.
808 checkouts = []
809 path = os.getcwd() 973 path = os.getcwd()
810 974
811 file_list = [] 975 file_list = []
812 if options.files: 976 if options.files:
813 file_list = options.files 977 file_list = options.files
814 elif change: 978 elif change:
815 file_list = [f.LocalPath() for f in change.AffectedFiles()] 979 file_list = [f.LocalPath() for f in change.AffectedFiles()]
816 980
817 if options.upstream_branch: 981 if options.upstream_branch:
818 path += '@' + options.upstream_branch 982 path += '@' + options.upstream_branch
819 # Clear file list so that the correct list will be retrieved from the 983 # Clear file list so that the correct list will be retrieved from the
820 # upstream branch. 984 # upstream branch.
821 file_list = [] 985 file_list = []
822 checkouts.append(GuessVCS(options, path, file_list)) 986
823 checkouts[0].AutomagicalSettings() 987 current_vcs = GuessVCS(options, path, file_list)
988 current_vcs.AutomagicalSettings()
989 options = current_vcs.options
990 vcs_is_git = type(current_vcs) is GIT
991
992 # So far, git_repo doesn't work with SVN
993 if options.git_repo and not vcs_is_git:
994 parser.error('--git_repo option is supported only for GIT repositories')
995
996 # If revision==auto, resolve it
997 if options.revision and options.revision.lower() == 'auto':
998 if not vcs_is_git:
999 parser.error('--revision=auto is supported only for GIT repositories')
1000 options.revision = scm.GIT.Capture(
1001 ['rev-parse', current_vcs.diff_against],
1002 cwd=path)
1003
1004 checkouts = [current_vcs]
824 for item in options.sub_rep: 1005 for item in options.sub_rep:
825 # Pass file_list=None because we don't know the sub repo's file list. 1006 # Pass file_list=None because we don't know the sub repo's file list.
826 checkout = GuessVCS(options, 1007 checkout = GuessVCS(options,
827 os.path.join(checkouts[0].checkout_root, item), 1008 os.path.join(current_vcs.checkout_root, item),
828 None) 1009 None)
829 if checkout.checkout_root in [c.checkout_root for c in checkouts]: 1010 if checkout.checkout_root in [c.checkout_root for c in checkouts]:
830 parser.error('Specified the root %s two times.' % 1011 parser.error('Specified the root %s two times.' %
831 checkout.checkout_root) 1012 checkout.checkout_root)
832 checkouts.append(checkout) 1013 checkouts.append(checkout)
833 1014
834 can_http = options.port and options.host 1015 can_http = options.port and options.host
835 can_svn = options.svn_repo 1016 can_svn = options.svn_repo
1017 can_git = options.git_repo
836 # If there was no transport selected yet, now we must have enough data to 1018 # If there was no transport selected yet, now we must have enough data to
837 # select one. 1019 # select one.
838 if not options.send_patch and not (can_http or can_svn): 1020 if not options.send_patch and not (can_http or can_svn or can_git):
839 parser.error('Please specify an access method.') 1021 parser.error('Please specify an access method.')
840 1022
841 # Convert options.diff into the content of the diff. 1023 # Convert options.diff into the content of the diff.
842 if options.url: 1024 if options.url:
843 if options.files: 1025 if options.files:
844 parser.error('You cannot specify files and --url at the same time.') 1026 parser.error('You cannot specify files and --url at the same time.')
845 options.diff = urllib2.urlopen(options.url).read() 1027 options.diff = urllib2.urlopen(options.url).read()
846 elif options.diff: 1028 elif options.diff:
847 if options.files: 1029 if options.files:
848 parser.error('You cannot specify files and --diff at the same time.') 1030 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 1088
907 if options.print_bots: 1089 if options.print_bots:
908 print 'Bots which would be used:' 1090 print 'Bots which would be used:'
909 for bot in bot_spec: 1091 for bot in bot_spec:
910 if bot[1]: 1092 if bot[1]:
911 print ' %s:%s' % (bot[0], ','.join(bot[1])) 1093 print ' %s:%s' % (bot[0], ','.join(bot[1]))
912 else: 1094 else:
913 print ' %s' % (bot[0]) 1095 print ' %s' % (bot[0])
914 return 0 1096 return 0
915 1097
916 # Send the patch. 1098 # Determine sending protocol
917 if options.send_patch: 1099 if options.send_patch:
918 # If forced. 1100 # If forced.
919 options.send_patch(bot_spec, options) 1101 senders = [options.send_patch]
920 PrintSuccess(bot_spec, options) 1102 else:
921 return 0 1103 # Try sending patch using avaialble protocols
922 try: 1104 all_senders = [
923 if can_http: 1105 (_SendChangeHTTP, can_http),
924 _SendChangeHTTP(bot_spec, options) 1106 (_SendChangeSVN, can_svn),
1107 (_SendChangeGit, can_git)
1108 ]
1109 senders = [sender for sender, can in all_senders if can]
1110
1111 # Send the patch.
1112 for sender in senders:
1113 try:
1114 sender(bot_spec, options)
925 PrintSuccess(bot_spec, options) 1115 PrintSuccess(bot_spec, options)
926 return 0 1116 return 0
927 except NoTryServerAccess: 1117 except NoTryServerAccess:
928 if not can_svn: 1118 is_last = sender == senders[-1]
929 raise 1119 if is_last:
930 _SendChangeSVN(bot_spec, options) 1120 raise
931 PrintSuccess(bot_spec, options) 1121 assert False, "Unreachable code"
932 return 0
933 except (InvalidScript, NoTryServerAccess), e: 1122 except (InvalidScript, NoTryServerAccess), e:
934 if swallow_exception: 1123 if swallow_exception:
935 return 1 1124 return 1
936 print >> sys.stderr, e 1125 print >> sys.stderr, e
937 return 1 1126 return 1
938 except (gclient_utils.Error, subprocess2.CalledProcessError), e: 1127 except (gclient_utils.Error, subprocess2.CalledProcessError), e:
939 print >> sys.stderr, e 1128 print >> sys.stderr, e
940 return 1 1129 return 1
941 return 0 1130 return 0
942 1131
943 1132
944 if __name__ == "__main__": 1133 if __name__ == "__main__":
945 fix_encoding.fix_encoding() 1134 fix_encoding.fix_encoding()
946 sys.exit(TryChange(None, None, False)) 1135 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