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

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: using branch file and separate branches for patches Created 6 years, 8 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 = 'branch'
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 """Create temporary files with description and patch, yield execution,
513 and delete the files.
514
515 __enter__ called on the return value returns a tuple of patch_filename and
516 description_filename.
517
518 Args:
519 description: contents of description file.
520 options: patchset options object. Must have attributes: user,
521 name (of patch) and diff (contents of patch).
522 """
523 current_time = str(datetime.datetime.now()).replace(':', '.')
524 patch_basename = '%s.%s.%s.diff' % (Escape(options.user),
525 Escape(options.name), current_time)
526 with _TempFilename('description', description) as description_filename:
527 with _TempFilename(patch_basename, options.diff) as patch_filename:
528 yield patch_filename, description_filename
529
530
484 def _SendChangeSVN(bot_spec, options): 531 def _SendChangeSVN(bot_spec, options):
485 """Send a change to the try server by committing a diff file on a subversion 532 """Send a change to the try server by committing a diff file on a subversion
486 server.""" 533 server."""
487 if not options.svn_repo: 534 if not options.svn_repo:
488 raise NoTryServerAccess('Please use the --svn_repo option to specify the' 535 raise NoTryServerAccess('Please use the --svn_repo option to specify the'
489 ' try server svn repository to connect to.') 536 ' try server svn repository to connect to.')
490 537
491 values = _ParseSendChangeOptions(bot_spec, options) 538 values = _ParseSendChangeOptions(bot_spec, options)
492 description = ''.join("%s=%s\n" % (k, v) for k, v in values) 539 description = ''.join("%s=%s\n" % (k, v) for k, v in values)
493 logging.info('Sending by SVN') 540 logging.info('Sending by SVN')
494 logging.info(description) 541 logging.info(description)
495 logging.info(options.svn_repo) 542 logging.info(options.svn_repo)
496 logging.info(options.diff) 543 logging.info(options.diff)
497 if options.dry_run: 544 if options.dry_run:
498 return 545 return
499 546
500 # Create a temporary directory, put a uniquely named file in it with the diff 547 with _PrepareDescriptionAndPatchFiles(description, options) as (
501 # content and svn import that. 548 patch_filename, description_filename):
502 temp_dir = tempfile.mkdtemp() 549 if sys.platform == "cygwin":
503 temp_file = tempfile.NamedTemporaryFile() 550 # Small chromium-specific issue here:
504 try: 551 # git-try uses /usr/bin/python on cygwin but svn.bat will be used
552 # instead of /usr/bin/svn by default. That causes bad things(tm) since
553 # Windows' svn.exe has no clue about cygwin paths. Hence force to use
554 # the cygwin version in this particular context.
555 exe = "/usr/bin/svn"
556 else:
557 exe = "svn"
558 patch_dir = os.path.dirname(patch_filename)
559 command = [exe, 'import', '-q', patch_dir, options.svn_repo, '--file',
560 description_filename]
561 if scm.SVN.AssertVersion("1.5")[0]:
562 command.append('--no-ignore')
563
505 try: 564 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) 565 subprocess2.check_call(command)
534 except subprocess2.CalledProcessError, e: 566 except subprocess2.CalledProcessError, e:
535 raise NoTryServerAccess(str(e)) 567 raise NoTryServerAccess(str(e))
536 finally: 568
537 temp_file.close() 569
538 shutil.rmtree(temp_dir, True) 570 def _GetPatchGitRepo(git_url):
571 """Get a path to a Git repo with patches with latest changes,
agable 2014/03/26 20:27:04 Just a single line for the first line of a docstri
nodir 2014/03/26 20:57:02 Done.
572 associated with the given url.
573
574 Store patches in .git/git-try/patches-git directory, a git repo. If it
575 doesn't exist yet or its origin URL is different, then clean up and clone it.
576 If it existed before, then pull changes.
577
578 Does not support SVN repo.
579
580 Returns a path to the directory with patches.
581 """
582 git_dir = scm.GIT.GetGitDir(os.getcwd())
583 patch_dir = os.path.join(git_dir, GIT_PATCH_DIR_BASENAME)
584 def do_git(*args, **kwargs):
agable 2014/03/26 20:27:04 the name of this function doesn't clarify that it
nodir 2014/03/26 20:57:02 Removed the function
585 kwargs.setdefault('cwd', patch_dir)
586 return scm.GIT.Capture(list(args), **kwargs)
587
588 logging.info('Looking for git repo for patches')
589 # Is there already a repo with the expected url or should we clone?
590 clone = True
591 if os.path.exists(patch_dir) and scm.GIT.IsInsideWorkTree(patch_dir):
592 existing_url = scm.GIT.Capture(
593 ['config', '--local', 'remote.origin.url'],
594 cwd=patch_dir)
595 clone = existing_url != git_url
596
597 if clone:
598 if os.path.exists(patch_dir):
599 logging.info('Cleaning up')
600 shutil.rmtree(patch_dir, True)
601 logging.info('Cloning patch repo')
602 do_git('clone', git_url, GIT_PATCH_DIR_BASENAME, cwd=git_dir)
603 email = scm.GIT.GetEmail(cwd=os.getcwd())
604 do_git('config', '--local', 'user.email', email)
605 else:
606 if scm.GIT.IsWorkTreeDirty(patch_dir):
607 logging.info('Work dir is dirty: hard reset!')
608 do_git('reset', '--hard')
609 logging.info('Updating patch repo')
610 do_git('pull', 'origin', 'master')
611
612 return os.path.abspath(patch_dir)
613
614
615 def _SendChangeGit(bot_spec, options):
616 """Send a change to the try server by committing a diff file to a GIT repo"""
617 if not options.git_repo:
618 raise NoTryServerAccess('Please use the --git_repo option to specify the '
619 'try server git repository to connect to.')
620
621 values = _ParseSendChangeOptions(bot_spec, options)
622 comment_subject = '%s.%s' % (options.user, options.name)
623 comment_body = ''.join("%s=%s\n" % (k, v) for k, v in values)
624 description = '%s\n\n%s' % (comment_subject, comment_body)
625 logging.info('Sending by GIT')
626 logging.info(description)
627 logging.info(options.git_repo)
628 logging.info(options.diff)
629 if options.dry_run:
630 return
631
632 patch_dir = _GetPatchGitRepo(options.git_repo)
633 def do_git(*args):
agable 2014/03/26 20:27:04 If you're defining the same inner function multipl
nodir 2014/03/26 20:57:02 Renamed this one to patch_git. Still, trying to av
634 return scm.GIT.Capture(list(args), cwd=patch_dir)
635 def add_and_commit(filename, comment_filename):
636 do_git('add', filename)
637 do_git('commit', '-F', comment_filename)
638
639 assert scm.GIT.IsInsideWorkTree(patch_dir)
640 assert not scm.GIT.IsWorkTreeDirty(patch_dir)
641
642 with _PrepareDescriptionAndPatchFiles(description, options) as (
643 patch_filename, description_filename):
644 logging.info('Committing patch')
645 target_branch = ('refs/tryserver/' +
agable 2014/03/26 20:27:04 I'd say refs/patches/, since this system could pot
nodir 2014/03/26 20:57:02 Done.
646 os.path.basename(patch_filename).replace(' ','-'))
647 target_filename = os.path.join(patch_dir, 'patch.diff')
648 branch_file = os.path.join(patch_dir, GIT_BRANCH_FILE)
649 try:
agable 2014/03/26 20:27:04 This try is around a lot of different calls, only
nodir 2014/03/31 20:25:13 Done.
650 # Crete a new branch and put the patch there
651 do_git('checkout', '--orphan', target_branch)
652 do_git('reset')
653 do_git('clean', '-f')
654 shutil.copyfile(patch_filename, target_filename)
655 add_and_commit(target_filename, description_filename)
656 assert not scm.GIT.IsWorkTreeDirty(patch_dir)
657
658 # Update the branch file in the master
659 do_git('checkout', 'master')
660
661 def update_branch():
662 with open(branch_file, 'w') as f:
663 f.write(target_branch)
664 add_and_commit(branch_file, description_filename)
665 def push():
666 do_git('push', 'origin', 'master', target_branch)
667 def push_fixup():
668 do_git('fetch', 'origin')
669 do_git('reset', '--hard', 'origin/master')
670 update_branch()
671
672 update_branch()
673 logging.info('Pushing patch')
674 _retry(push, push_fixup)
675 except subprocess2.CalledProcessError, e:
676 do_git('checkout', 'master')
677 do_git('reset', '--hard', 'origin/master')
678 raise NoTryServerAccess(str(e))
679
680
681 def _retry(action, fixup=None, attempts=3):
agable 2014/03/26 20:27:04 There are already other retry mechanisms floating
nodir 2014/03/31 20:25:13 Done.
682 """Calls action until it passes without exceptions"""
683 for attempt in xrange(attempts):
684 try:
685 action()
686 except subprocess2.CalledProcessError:
687 is_last = attempt == attempts - 1
688 if is_last:
689 raise
690 if fixup:
691 fixup()
539 692
540 693
541 def PrintSuccess(bot_spec, options): 694 def PrintSuccess(bot_spec, options):
542 if not options.dry_run: 695 if not options.dry_run:
543 text = 'Patch \'%s\' sent to try server' % options.name 696 text = 'Patch \'%s\' sent to try server' % options.name
544 if bot_spec: 697 if bot_spec:
545 text += ': %s' % ', '.join( 698 text += ': %s' % ', '.join(
546 '%s:%s' % (b[0], ','.join(b[1])) for b in bot_spec) 699 '%s:%s' % (b[0], ','.join(b[1])) for b in bot_spec)
547 print(text) 700 print(text)
548 701
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 "times to specify multiple builders. ex: " 797 "times to specify multiple builders. ex: "
645 "'-bwin_rel:ui_tests,webkit_unit_tests -bwin_layout'. See " 798 "'-bwin_rel:ui_tests,webkit_unit_tests -bwin_layout'. See "
646 "the try server waterfall for the builders name and the tests " 799 "the try server waterfall for the builders name and the tests "
647 "available. Can also be used to specify gtest_filter, e.g. " 800 "available. Can also be used to specify gtest_filter, e.g. "
648 "-bwin_rel:base_unittests:ValuesTest.*Value")) 801 "-bwin_rel:base_unittests:ValuesTest.*Value"))
649 group.add_option("-B", "--print_bots", action="store_true", 802 group.add_option("-B", "--print_bots", action="store_true",
650 help="Print bots we would use (e.g. from PRESUBMIT.py)" 803 help="Print bots we would use (e.g. from PRESUBMIT.py)"
651 " and exit. Do not send patch. Like --dry_run" 804 " and exit. Do not send patch. Like --dry_run"
652 " but less verbose.") 805 " but less verbose.")
653 group.add_option("-r", "--revision", 806 group.add_option("-r", "--revision",
654 help="Revision to use for the try job; default: the " 807 help="Revision to use for the try job. If 'auto' is "
808 "specified, it is resolved to the revision a patch is "
809 "generated against (Git only). Default: the "
655 "revision will be determined by the try server; see " 810 "revision will be determined by the try server; see "
656 "its waterfall for more info") 811 "its waterfall for more info")
657 group.add_option("-c", "--clobber", action="store_true", 812 group.add_option("-c", "--clobber", action="store_true",
658 help="Force a clobber before building; e.g. don't do an " 813 help="Force a clobber before building; e.g. don't do an "
659 "incremental build") 814 "incremental build")
660 # TODO(maruel): help="Select a specific configuration, usually 'debug' or " 815 # TODO(maruel): help="Select a specific configuration, usually 'debug' or "
661 # "'release'" 816 # "'release'"
662 group.add_option("--target", help=optparse.SUPPRESS_HELP) 817 group.add_option("--target", help=optparse.SUPPRESS_HELP)
663 818
664 group.add_option("--project", 819 group.add_option("--project",
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
730 group.add_option("--use_svn", 885 group.add_option("--use_svn",
731 action="store_const", 886 action="store_const",
732 const=_SendChangeSVN, 887 const=_SendChangeSVN,
733 dest="send_patch", 888 dest="send_patch",
734 help="Use SVN to talk to the try server") 889 help="Use SVN to talk to the try server")
735 group.add_option("-S", "--svn_repo", 890 group.add_option("-S", "--svn_repo",
736 metavar="SVN_URL", 891 metavar="SVN_URL",
737 help="SVN url to use to write the changes in; --use_svn is " 892 help="SVN url to use to write the changes in; --use_svn is "
738 "implied when using --svn_repo") 893 "implied when using --svn_repo")
739 parser.add_option_group(group) 894 parser.add_option_group(group)
895
896 group = optparse.OptionGroup(parser, "Access the try server with Git")
897 group.add_option("--use_git",
898 action="store_const",
899 const=_SendChangeGit,
900 dest="send_patch",
901 help="Use GIT to talk to the try server")
902 group.add_option("-G", "--git_repo",
903 metavar="GIT_URL",
904 help="GIT url to use to write the changes in; --use_git is "
905 "implied when using --git_repo")
906 parser.add_option_group(group)
740 return parser 907 return parser
741 908
742 909
743 def TryChange(argv, 910 def TryChange(argv,
744 change, 911 change,
745 swallow_exception, 912 swallow_exception,
746 prog=None, 913 prog=None,
747 extra_epilog=None): 914 extra_epilog=None):
748 """ 915 """
749 Args: 916 Args:
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
798 match = re.match(r'^(.*)/(\d+)/?$', options.rietveld_url) 965 match = re.match(r'^(.*)/(\d+)/?$', options.rietveld_url)
799 if match: 966 if match:
800 if options.issue or options.patchset: 967 if options.issue or options.patchset:
801 parser.error('Cannot use both --issue and use a review number url') 968 parser.error('Cannot use both --issue and use a review number url')
802 options.issue = int(match.group(2)) 969 options.issue = int(match.group(2))
803 options.rietveld_url = match.group(1) 970 options.rietveld_url = match.group(1)
804 971
805 try: 972 try:
806 changed_files = None 973 changed_files = None
807 # Always include os.getcwd() in the checkout settings. 974 # Always include os.getcwd() in the checkout settings.
808 checkouts = []
809 path = os.getcwd() 975 path = os.getcwd()
810 976
811 file_list = [] 977 file_list = []
812 if options.files: 978 if options.files:
813 file_list = options.files 979 file_list = options.files
814 elif change: 980 elif change:
815 file_list = [f.LocalPath() for f in change.AffectedFiles()] 981 file_list = [f.LocalPath() for f in change.AffectedFiles()]
816 982
817 if options.upstream_branch: 983 if options.upstream_branch:
818 path += '@' + options.upstream_branch 984 path += '@' + options.upstream_branch
819 # Clear file list so that the correct list will be retrieved from the 985 # Clear file list so that the correct list will be retrieved from the
820 # upstream branch. 986 # upstream branch.
821 file_list = [] 987 file_list = []
822 checkouts.append(GuessVCS(options, path, file_list)) 988
823 checkouts[0].AutomagicalSettings() 989 current_vcs = GuessVCS(options, path, file_list)
990 current_vcs.AutomagicalSettings()
991 options = current_vcs.options
992 vcs_is_git = type(current_vcs) is GIT
993
994 # So far, git_repo doesn't work with SVN
995 if options.git_repo and not vcs_is_git:
996 parser.error('--git_repo option is supported only for GIT repositories')
997
998 # If revision==auto, resolve it
999 if options.revision and options.revision.lower() == 'auto':
1000 if not vcs_is_git:
1001 parser.error('--revision=auto is supported only for GIT repositories')
1002 options.revision = scm.GIT.Capture(
1003 ['rev-parse', current_vcs.diff_against],
1004 cwd=path)
1005
1006 checkouts = [current_vcs]
824 for item in options.sub_rep: 1007 for item in options.sub_rep:
825 # Pass file_list=None because we don't know the sub repo's file list. 1008 # Pass file_list=None because we don't know the sub repo's file list.
826 checkout = GuessVCS(options, 1009 checkout = GuessVCS(options,
827 os.path.join(checkouts[0].checkout_root, item), 1010 os.path.join(current_vcs.checkout_root, item),
828 None) 1011 None)
829 if checkout.checkout_root in [c.checkout_root for c in checkouts]: 1012 if checkout.checkout_root in [c.checkout_root for c in checkouts]:
830 parser.error('Specified the root %s two times.' % 1013 parser.error('Specified the root %s two times.' %
831 checkout.checkout_root) 1014 checkout.checkout_root)
832 checkouts.append(checkout) 1015 checkouts.append(checkout)
833 1016
834 can_http = options.port and options.host 1017 can_http = options.port and options.host
835 can_svn = options.svn_repo 1018 can_svn = options.svn_repo
1019 can_git = options.git_repo
836 # If there was no transport selected yet, now we must have enough data to 1020 # If there was no transport selected yet, now we must have enough data to
837 # select one. 1021 # select one.
838 if not options.send_patch and not (can_http or can_svn): 1022 if not options.send_patch and not (can_http or can_svn or can_git):
839 parser.error('Please specify an access method.') 1023 parser.error('Please specify an access method.')
840 1024
841 # Convert options.diff into the content of the diff. 1025 # Convert options.diff into the content of the diff.
842 if options.url: 1026 if options.url:
843 if options.files: 1027 if options.files:
844 parser.error('You cannot specify files and --url at the same time.') 1028 parser.error('You cannot specify files and --url at the same time.')
845 options.diff = urllib2.urlopen(options.url).read() 1029 options.diff = urllib2.urlopen(options.url).read()
846 elif options.diff: 1030 elif options.diff:
847 if options.files: 1031 if options.files:
848 parser.error('You cannot specify files and --diff at the same time.') 1032 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 1090
907 if options.print_bots: 1091 if options.print_bots:
908 print 'Bots which would be used:' 1092 print 'Bots which would be used:'
909 for bot in bot_spec: 1093 for bot in bot_spec:
910 if bot[1]: 1094 if bot[1]:
911 print ' %s:%s' % (bot[0], ','.join(bot[1])) 1095 print ' %s:%s' % (bot[0], ','.join(bot[1]))
912 else: 1096 else:
913 print ' %s' % (bot[0]) 1097 print ' %s' % (bot[0])
914 return 0 1098 return 0
915 1099
916 # Send the patch. 1100 # Determine sending protocol
917 if options.send_patch: 1101 if options.send_patch:
918 # If forced. 1102 # If forced.
919 options.send_patch(bot_spec, options) 1103 senders = [options.send_patch]
920 PrintSuccess(bot_spec, options) 1104 else:
921 return 0 1105 # Try sending patch using avaialble protocols
922 try: 1106 all_senders = [
923 if can_http: 1107 (_SendChangeHTTP, can_http),
924 _SendChangeHTTP(bot_spec, options) 1108 (_SendChangeSVN, can_svn),
1109 (_SendChangeGit, can_git)
1110 ]
1111 senders = [sender for sender, can in all_senders if can]
1112
1113 # Send the patch.
1114 for sender in senders:
1115 try:
1116 sender(bot_spec, options)
925 PrintSuccess(bot_spec, options) 1117 PrintSuccess(bot_spec, options)
926 return 0 1118 return 0
927 except NoTryServerAccess: 1119 except NoTryServerAccess:
928 if not can_svn: 1120 is_last = sender == senders[-1]
929 raise 1121 if is_last:
930 _SendChangeSVN(bot_spec, options) 1122 raise
931 PrintSuccess(bot_spec, options) 1123 assert False, "Unreachable code"
932 return 0
933 except (InvalidScript, NoTryServerAccess), e: 1124 except (InvalidScript, NoTryServerAccess), e:
934 if swallow_exception: 1125 if swallow_exception:
935 return 1 1126 return 1
936 print >> sys.stderr, e 1127 print >> sys.stderr, e
937 return 1 1128 return 1
938 except (gclient_utils.Error, subprocess2.CalledProcessError), e: 1129 except (gclient_utils.Error, subprocess2.CalledProcessError), e:
939 print >> sys.stderr, e 1130 print >> sys.stderr, e
940 return 1 1131 return 1
941 return 0 1132 return 0
942 1133
943 1134
944 if __name__ == "__main__": 1135 if __name__ == "__main__":
945 fix_encoding.fix_encoding() 1136 fix_encoding.fix_encoding()
946 sys.exit(TryChange(None, None, False)) 1137 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