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

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