16b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com#!/usr/bin/python
26b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
36b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com# Copyright (c) 2013 The Chromium Authors. All rights reserved.
46b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com# Use of this source code is governed by a BSD-style license that can be
56b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com# found in the LICENSE file.
66b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
76b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
86b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com"""
96b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.comsubmit_try: Submit a try request.
106b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
116b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.comThis is a thin wrapper around the try request utilities in depot_tools which
126b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.comadds some validation and supports both git and svn.
136b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com"""
146b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
156b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
166b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.comimport httplib
176b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.comimport json
186b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.comimport os
19f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.comimport re
20d4ba6e778122df9b52dc68a2f41210d33fd43471borenet@google.comimport shutil
216b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.comimport subprocess
22a74302d628f48c7c1c3e14742b0bf293ccd633f7borenet@google.comimport svn
236b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.comimport sys
24d4ba6e778122df9b52dc68a2f41210d33fd43471borenet@google.comimport tempfile
25fe7533eebe777cc66c7f8fa7a03f00572755c5b4borenet@google.com
262e81e51d1e932d34d602183130359514203efbbfborenetimport retrieve_from_googlesource
276b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
286b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
296b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com# Alias which can be used to run a try on every builder.
306b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.comALL_BUILDERS = 'all'
31f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com# Alias which can be used to run a try on all compile builders.
32f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.comCOMPILE_BUILDERS = 'compile'
33f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com# Alias which can be used to run a try on all builders that are run in the CQ.
34f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.comCQ_BUILDERS = 'cq'
35f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com# Alias which can be used to specify a regex to choose builders.
36f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.comREGEX = 'regex'
37f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com
389f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.orgALL_ALIASES = [ALL_BUILDERS, COMPILE_BUILDERS, REGEX, CQ_BUILDERS]
396b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
402e81e51d1e932d34d602183130359514203efbbfborenetLARGE_NUMBER_OF_BOTS = 5
412e81e51d1e932d34d602183130359514203efbbfborenet
421a5e83a0ac27aa2c9d7dd8deadc8e88a4af0fbf6borenet@google.comGIT = 'git.bat' if os.name == 'nt' else 'git'
431a5e83a0ac27aa2c9d7dd8deadc8e88a4af0fbf6borenet@google.com
449f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org# URL of the slaves.cfg file in the Skia buildbot sources.
452e81e51d1e932d34d602183130359514203efbbfborenetSKIA_REPO = 'https://skia.googlesource.com/buildbot'
462e81e51d1e932d34d602183130359514203efbbfborenetSLAVES_CFG_PATH = 'master/slaves.cfg'
476b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
486b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com# All try builders have this suffix.
4999da601032e4a5808ea33adc1cc721f79b73e4caborenet@google.comTRYBOT_SUFFIX = '-Trybot'
506b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
516b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com# String for matching the svn url of the try server inside codereview.settings.
526b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.comTRYSERVER_SVN_URL = 'TRYSERVER_SVN_URL: '
536b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
546b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com# Strings used for matching svn config properties.
55a74302d628f48c7c1c3e14742b0bf293ccd633f7borenet@google.comURL_STR = 'URL'
56a74302d628f48c7c1c3e14742b0bf293ccd633f7borenet@google.comREPO_ROOT_STR = 'Repository Root'
576b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
586b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
596b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.comdef FindDepotTools():
606b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  """ Find depot_tools on the local machine and return its location. """
616b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  which_cmd = 'where' if os.name == 'nt' else 'which'
626b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  cmd = [which_cmd, 'gcl']
636b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
646b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  if proc.wait() != 0:
656b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com    raise Exception('Couldn\'t find depot_tools in PATH!')
666c55b513bfbb9d04d0339715637c356cd4858663borenet@google.com  gcl = proc.communicate()[0].split('\n')[0].rstrip()
676b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  depot_tools_dir = os.path.dirname(gcl)
686b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  return depot_tools_dir
696b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
706b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
712e81e51d1e932d34d602183130359514203efbbfborenetdef GetCheckoutRoot():
722e81e51d1e932d34d602183130359514203efbbfborenet  """ Determine where the local checkout is rooted."""
732e81e51d1e932d34d602183130359514203efbbfborenet  cmd = ['git', 'rev-parse', '--show-toplevel']
742e81e51d1e932d34d602183130359514203efbbfborenet  proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
752e81e51d1e932d34d602183130359514203efbbfborenet                          stderr=subprocess.STDOUT)
762e81e51d1e932d34d602183130359514203efbbfborenet  if proc.wait() != 0:
772e81e51d1e932d34d602183130359514203efbbfborenet    raise Exception('Couldn\'t find checkout root!')
782e81e51d1e932d34d602183130359514203efbbfborenet  return os.path.basename(proc.communicate()[0])
796b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
806b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
816b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.comdef GetTryRepo():
826f0f5b4aad40fbdcbadcbbc32a38bd4c7d8998bcborenet@google.com  """Determine the TRYSERVER_SVN_URL from the codereview.settings file."""
836f0f5b4aad40fbdcbadcbbc32a38bd4c7d8998bcborenet@google.com  codereview_settings_file = os.path.join(os.path.dirname(__file__), os.pardir,
846f0f5b4aad40fbdcbadcbbc32a38bd4c7d8998bcborenet@google.com                                          'codereview.settings')
856f0f5b4aad40fbdcbadcbbc32a38bd4c7d8998bcborenet@google.com  with open(codereview_settings_file) as f:
866f0f5b4aad40fbdcbadcbbc32a38bd4c7d8998bcborenet@google.com    for line in f:
876f0f5b4aad40fbdcbadcbbc32a38bd4c7d8998bcborenet@google.com      if line.startswith(TRYSERVER_SVN_URL):
886f0f5b4aad40fbdcbadcbbc32a38bd4c7d8998bcborenet@google.com        return line[len(TRYSERVER_SVN_URL):].rstrip()
896b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  raise Exception('Couldn\'t determine the TRYSERVER_SVN_URL. Make sure it is '
906f0f5b4aad40fbdcbadcbbc32a38bd4c7d8998bcborenet@google.com                  'defined in the %s file.' % codereview_settings_file)
916b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
926b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
939f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.orgdef RetrieveTrybotList():
949f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  """Retrieve the list of known trybots from the checked-in buildbot
959f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  configuration."""
969f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  # Retrieve the slaves.cfg file from the repository.
972e81e51d1e932d34d602183130359514203efbbfborenet  slaves_cfg_text = retrieve_from_googlesource.get(SKIA_REPO, SLAVES_CFG_PATH)
986b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
999f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  # Execute the slaves.cfg file to obtain the list of slaves.
1009f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  vars = {}
1019f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  exec(slaves_cfg_text, vars)
1029f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  slaves_cfg = vars['slaves']
1036b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
1049f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  # Pull the list of known builders from the slaves list.
1059f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  trybots = set()
1069f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  for slave in slaves_cfg:
1079f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org    for builder in slave['builder']:
1089f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org      if not builder.endswith(TRYBOT_SUFFIX):
1099f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org        trybots.add(builder)
1106b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
1119f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  return list(trybots), vars['cq_trybots']
1129f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org
1139f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org
1149f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.orgdef ValidateArgs(argv, trybots, cq_trybots, is_svn=True):
1156b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  """ Parse and validate command-line arguments. If the arguments are valid,
1166b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  returns a tuple of (<changelist name>, <list of trybots>).
1176b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
1189f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  trybots: list of strings; A list of the known try builders.
1199f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  cq_trybots: list of strings; Trybots who get run by the commit queue.
1209f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  is_svn: bool; whether or not we're in an svn checkout.
1216b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  """
122a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com
123a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com  class CollectedArgs(object):
124a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    def __init__(self, bots, changelist, revision):
125a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      self._bots = bots
126a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      self._changelist = changelist
127a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      self._revision = revision
128a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com
129a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    @property
130a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    def bots(self):
131a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      for bot in self._bots:
132a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com        yield bot
133a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com
134a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    @property
135a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    def changelist(self):
136a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      return self._changelist
137a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com
138a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    @property
139a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    def revision(self):
140a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      return self._revision
141a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com
142a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com  usage = (
143a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com"""submit_try: Submit a try request.
144a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.comsubmit_try %s--bot <buildername> [<buildername> ...]
145a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com
146f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com-b, --bot           Builder(s) or Alias on which to run the try. Required.
147f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com                    Allowed aliases: %s
148a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com-h, --help          Show this message.
149a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com-r <revision#>      Revision from which to run the try.
150f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com-l, --list_bots     List the available try builders and aliases and exit.
151f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com""" % ('<changelist> ' if is_svn else '', ALL_ALIASES))
152a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com
153a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com  def Error(msg=None):
154a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    if msg:
155a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      print msg
156a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    print usage
157a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    sys.exit(1)
158a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com
159a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com  using_bots = None
160a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com  changelist = None
161a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com  revision = None
162a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com
163a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com  while argv:
164a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    arg = argv.pop(0)
165a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    if arg == '-h' or arg == '--help':
166a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      Error()
167a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    elif arg == '-l' or arg == '--list_bots':
1689f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org      format_args = ['\n  '.join(sorted(trybots))] + \
1699f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org                    ALL_ALIASES + \
1709f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org                    ['\n    '.join(sorted(cq_trybots))]
171f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com      print (
172f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com"""
173f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.comsubmit_try: Available builders:\n  %s
174f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com
175f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.comCan also use the following aliases to run on groups of builders-
176f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com  %s: Will run against all trybots.
177f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com  %s: Will run against all compile trybots.
178f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com  %s: You will be prompted to enter a regex to select builders with.
1799f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  %s: Will run against the same trybots as the commit queue:\n    %s
180f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com
181f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com""" % tuple(format_args))
182a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      sys.exit(0)
18302009c781da3e586546fed7cbb533e7bd683522bborenet@google.com    elif arg == '-b' or arg == '--bot':
184a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      if using_bots:
185a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com        Error('--bot specified multiple times.')
186a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      if len(argv) < 1:
187a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com        Error('You must specify a builder with "--bot".')
188a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      using_bots = []
189a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      while argv and not argv[0].startswith('-'):
19050d6862fdbc4dfe449b6be698fd9d0b42809533aepoger@google.com        for bot in argv.pop(0).split(','):
191f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com          if bot in ALL_ALIASES:
19250d6862fdbc4dfe449b6be698fd9d0b42809533aepoger@google.com            if using_bots:
193f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com              Error('Cannot specify "%s" with additional builder names or '
194f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com                    'aliases.' % bot)
195f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com            elif bot == COMPILE_BUILDERS:
1966fb77569596ad3e9419e9450db959949cc37576aborenet@google.com              using_bots = [t for t in trybots if t.startswith('Build')]
197f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com            elif bot == CQ_BUILDERS:
1989f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org              using_bots = cq_trybots
199f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com            elif bot == REGEX:
200f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com              while True:
201f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com                regex = raw_input("Enter your trybot regex: ")
202f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com                p = re.compile(regex)
203f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com                using_bots = [t for t in trybots if p.match(t)]
204f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com                print '\n\nTrybots that match your regex:\n%s\n\n' % '\n'.join(
205f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com                    using_bots)
206f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com                if raw_input('Re-enter regex? [y,n]: ') == 'n':
207f5c4fc8523423755abecc45db3e6333ee0fe0241rmistry@google.com                  break
20850d6862fdbc4dfe449b6be698fd9d0b42809533aepoger@google.com            break
20950d6862fdbc4dfe449b6be698fd9d0b42809533aepoger@google.com          else:
21050d6862fdbc4dfe449b6be698fd9d0b42809533aepoger@google.com            if not bot in trybots:
21150d6862fdbc4dfe449b6be698fd9d0b42809533aepoger@google.com              Error('Unrecognized builder: %s' % bot)
21250d6862fdbc4dfe449b6be698fd9d0b42809533aepoger@google.com            using_bots.append(bot)
213a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    elif arg == '-r':
214a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      if len(argv) < 1:
215a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com        Error('You must specify a revision with "-r".')
216a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      revision = argv.pop(0)
217a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    else:
218a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      if changelist or not is_svn:
219a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com        Error('Unknown argument: %s' % arg)
220a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com      changelist = arg
221a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com  if is_svn and not changelist:
222a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    Error('You must specify a changelist name.')
223a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com  if not using_bots:
224a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com    Error('You must specify one or more builders using --bot.')
2252e81e51d1e932d34d602183130359514203efbbfborenet  if len(using_bots) > LARGE_NUMBER_OF_BOTS:
2262e81e51d1e932d34d602183130359514203efbbfborenet    are_you_sure = raw_input('Running a try on a large number of bots is very '
2272e81e51d1e932d34d602183130359514203efbbfborenet                             'expensive. You may be able to get enough '
2282e81e51d1e932d34d602183130359514203efbbfborenet                             'information by running on a smaller set of bots. '
2292e81e51d1e932d34d602183130359514203efbbfborenet                             'Are you sure you want to do this? [y,n]: ')
2302e81e51d1e932d34d602183130359514203efbbfborenet    if are_you_sure != 'y':
2312e81e51d1e932d34d602183130359514203efbbfborenet      Error()
232a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com  return CollectedArgs(bots=using_bots, changelist=changelist,
233a5d621f2ce3cfc0a0892ee4cd1c11d00cc13a8caborenet@google.com                       revision=revision)
2346b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
2356b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
2362e81e51d1e932d34d602183130359514203efbbfborenetdef SubmitTryRequest(trybots, revision=None):
2372e81e51d1e932d34d602183130359514203efbbfborenet  """ Submits a try request on the given list of trybots.
2386b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
2392e81e51d1e932d34d602183130359514203efbbfborenet  Args:
2402e81e51d1e932d34d602183130359514203efbbfborenet      trybots: list of strings; the names of the try builders to run.
2412e81e51d1e932d34d602183130359514203efbbfborenet      revision: optional string; the revision from which to run the try.
2426b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  """
2432e81e51d1e932d34d602183130359514203efbbfborenet  botlist = ','.join(['%s%s' % (bot, TRYBOT_SUFFIX) for bot in trybots])
2442e81e51d1e932d34d602183130359514203efbbfborenet  # Find depot_tools. This is needed to import git_cl and trychange.
2452e81e51d1e932d34d602183130359514203efbbfborenet  sys.path.append(FindDepotTools())
2462e81e51d1e932d34d602183130359514203efbbfborenet  import git_cl
2472e81e51d1e932d34d602183130359514203efbbfborenet  import trychange
2482e81e51d1e932d34d602183130359514203efbbfborenet
2492e81e51d1e932d34d602183130359514203efbbfborenet  cmd = [GIT, 'diff', git_cl.Changelist().GetUpstreamBranch(),
2502e81e51d1e932d34d602183130359514203efbbfborenet         '--no-ext-diff']
2512e81e51d1e932d34d602183130359514203efbbfborenet  proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
2522e81e51d1e932d34d602183130359514203efbbfborenet  git_data = proc.communicate()
2532e81e51d1e932d34d602183130359514203efbbfborenet  if git_data[0] is None:
2542e81e51d1e932d34d602183130359514203efbbfborenet    raise Exception('Failed to capture git diff!')
2552e81e51d1e932d34d602183130359514203efbbfborenet
2562e81e51d1e932d34d602183130359514203efbbfborenet  temp_dir = tempfile.mkdtemp()
2572e81e51d1e932d34d602183130359514203efbbfborenet  try:
2582e81e51d1e932d34d602183130359514203efbbfborenet    diff_file = os.path.join(temp_dir, 'patch.diff')
2592e81e51d1e932d34d602183130359514203efbbfborenet    with open(diff_file, 'wb') as f:
2602e81e51d1e932d34d602183130359514203efbbfborenet      f.write(git_data[0])
2612e81e51d1e932d34d602183130359514203efbbfborenet      f.close()
2622e81e51d1e932d34d602183130359514203efbbfborenet
2632e81e51d1e932d34d602183130359514203efbbfborenet    try_args = ['--use_svn',
2642e81e51d1e932d34d602183130359514203efbbfborenet                '--svn_repo', GetTryRepo(),
2652e81e51d1e932d34d602183130359514203efbbfborenet                '--root', GetCheckoutRoot(),
2662e81e51d1e932d34d602183130359514203efbbfborenet                '--bot', botlist,
2672e81e51d1e932d34d602183130359514203efbbfborenet                '--diff', diff_file,
2682e81e51d1e932d34d602183130359514203efbbfborenet                ]
2692e81e51d1e932d34d602183130359514203efbbfborenet    if revision:
2702e81e51d1e932d34d602183130359514203efbbfborenet      try_args.extend(['-r', revision])
2712e81e51d1e932d34d602183130359514203efbbfborenet
2722e81e51d1e932d34d602183130359514203efbbfborenet    # Submit the try request.
2732e81e51d1e932d34d602183130359514203efbbfborenet    trychange.TryChange(try_args, None, False)
2742e81e51d1e932d34d602183130359514203efbbfborenet  finally:
2752e81e51d1e932d34d602183130359514203efbbfborenet    shutil.rmtree(temp_dir)
2766b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
2776b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
2786b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.comdef main():
2796b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  # Retrieve the list of active try builders from the build master.
2809f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  trybots, cq_trybots = RetrieveTrybotList()
2816b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
2826b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  # Determine if we're in an SVN checkout.
2836b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  is_svn = os.path.isdir('.svn')
2846b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
2856b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  # Parse and validate the command-line arguments.
2869f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org  args = ValidateArgs(sys.argv[1:], trybots=trybots, cq_trybots=cq_trybots,
2879f8e282901752e95e3b43059a19f08ea0a1a073ecommit-bot@chromium.org                      is_svn=is_svn)
2886b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
2896b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com  # Submit the try request.
2902e81e51d1e932d34d602183130359514203efbbfborenet  SubmitTryRequest(args.bots, args.revision)
2916b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
2926b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.com
2936b5388e71b0fb93b900e2705348cf9a6bfd3df9dborenet@google.comif __name__ == '__main__':
29450d6862fdbc4dfe449b6be698fd9d0b42809533aepoger@google.com  sys.exit(main())
295