1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch# Copyright 2014 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)"""Utility functions used by the bisect tool.
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)This includes functions related to checking out the depot and outputting
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)annotations for the Buildbot waterfall.
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)"""
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import errno
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import imp
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import os
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import shutil
153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import stat
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import subprocess
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import sys
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)DEFAULT_GCLIENT_CUSTOM_DEPS = {
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/data/page_cycler': 'https://chrome-internal.googlesource.com/'
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            'chrome/data/page_cycler/.git',
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/data/dom_perf': 'https://chrome-internal.googlesource.com/'
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                         'chrome/data/dom_perf/.git',
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/data/mach_ports': 'https://chrome-internal.googlesource.com/'
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           'chrome/data/mach_ports/.git',
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/tools/perf/data': 'https://chrome-internal.googlesource.com/'
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           'chrome/tools/perf/data/.git',
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/third_party/adobe/flash/binaries/ppapi/linux':
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'https://chrome-internal.googlesource.com/'
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'chrome/deps/adobe/flash/binaries/ppapi/linux/.git',
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/third_party/adobe/flash/binaries/ppapi/linux_x64':
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'https://chrome-internal.googlesource.com/'
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'chrome/deps/adobe/flash/binaries/ppapi/linux_x64/.git',
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/third_party/adobe/flash/binaries/ppapi/mac':
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'https://chrome-internal.googlesource.com/'
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'chrome/deps/adobe/flash/binaries/ppapi/mac/.git',
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/third_party/adobe/flash/binaries/ppapi/mac_64':
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'https://chrome-internal.googlesource.com/'
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'chrome/deps/adobe/flash/binaries/ppapi/mac_64/.git',
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/third_party/adobe/flash/binaries/ppapi/win':
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'https://chrome-internal.googlesource.com/'
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'chrome/deps/adobe/flash/binaries/ppapi/win/.git',
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/third_party/adobe/flash/binaries/ppapi/win_x64':
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'https://chrome-internal.googlesource.com/'
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'chrome/deps/adobe/flash/binaries/ppapi/win_x64/.git',
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/chrome/tools/test/reference_build/chrome_win': None,
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/chrome/tools/test/reference_build/chrome_mac': None,
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/chrome/tools/test/reference_build/chrome_linux': None,
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/third_party/WebKit/LayoutTests': None,
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'src/tools/valgrind': None,
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochGCLIENT_SPEC_DATA = [
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    {
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'name': 'src',
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'url': 'https://chromium.googlesource.com/chromium/src.git',
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'deps_file': '.DEPS.git',
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'managed': True,
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'custom_deps': {},
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'safesync_url': '',
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    },
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)]
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochGCLIENT_SPEC_ANDROID = "\ntarget_os = ['android']"
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)GCLIENT_CUSTOM_DEPS_V8 = {'src/v8_bleeding_edge': 'git://github.com/v8/v8.git'}
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)FILE_DEPS_GIT = '.DEPS.git'
66c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochFILE_DEPS = 'DEPS'
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)REPO_SYNC_COMMAND = ('git checkout -f $(git rev-list --max-count=1 '
696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                     '--before=%d remotes/m/master)')
706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)# Paths to CrOS-related files.
726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)# WARNING(qyearsley, 2014-08-15): These haven't been tested recently.
736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)CROS_SDK_PATH = os.path.join('..', 'cros', 'chromite', 'bin', 'cros_sdk')
746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)CROS_TEST_KEY_PATH = os.path.join(
756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    '..', 'cros', 'chromite', 'ssh_keys', 'testing_rsa')
766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)CROS_SCRIPT_KEY_PATH = os.path.join(
776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    '..', 'cros', 'src', 'scripts', 'mod_for_test_scripts', 'ssh_keys',
786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    'testing_rsa')
796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)REPO_PARAMS = [
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'https://chrome-internal.googlesource.com/chromeos/manifest-internal/',
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    '--repo-url',
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'https://git.chromium.org/external/repo.git'
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)]
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def OutputAnnotationStepStart(name):
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  """Outputs annotation to signal the start of a step to a try bot.
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Args:
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    name: The name of the step.
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  print
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  print '@@@SEED_STEP %s@@@' % name
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  print '@@@STEP_CURSOR %s@@@' % name
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  print '@@@STEP_STARTED@@@'
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  print
987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sys.stdout.flush()
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def OutputAnnotationStepClosed():
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  """Outputs annotation to signal the closing of a step to a try bot."""
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  print
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  print '@@@STEP_CLOSED@@@'
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  print
1067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sys.stdout.flush()
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)def OutputAnnotationStepLink(label, url):
1108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  """Outputs appropriate annotation to print a link.
1118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  Args:
1138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    label: The name to print.
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    url: The URL to print.
1158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  """
1168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  print
1178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  print '@@@STEP_LINK@%s@%s@@@' % (label, url)
1188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  print
1198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  sys.stdout.flush()
1208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)def LoadExtraSrc(path_to_file):
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Attempts to load an extra source file, and overrides global values.
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  If the extra source file is loaded successfully, then it will use the new
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  module to override some global values, such as gclient spec data.
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Args:
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    path_to_file: File path.
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Returns:
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    The loaded module object, or None if none was imported.
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  try:
135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    global GCLIENT_SPEC_DATA
136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    global GCLIENT_SPEC_ANDROID
137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    extra_src = imp.load_source('data', path_to_file)
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    GCLIENT_SPEC_DATA = extra_src.GetGClientSpec()
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    GCLIENT_SPEC_ANDROID = extra_src.GetGClientSpecExtraParams()
140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return extra_src
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  except ImportError:
142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return None
143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def IsTelemetryCommand(command):
1461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  """Attempts to discern whether or not a given command is running telemetry."""
1471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return ('tools/perf/run_' in command or 'tools\\perf\\run_' in command)
1481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def _CreateAndChangeToSourceDirectory(working_directory):
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Creates a directory 'bisect' as a subdirectory of |working_directory|.
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  If successful, the current working directory will be changed to the new
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  'bisect' directory.
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Args:
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    working_directory: The directory to create the new 'bisect' directory in.
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Returns:
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    True if the directory was successfully created (or already existed).
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cwd = os.getcwd()
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  os.chdir(working_directory)
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  try:
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    os.mkdir('bisect')
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  except OSError, e:
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if e.errno != errno.EEXIST:  # EEXIST indicates that it already exists.
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      os.chdir(cwd)
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return False
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  os.chdir('bisect')
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return True
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def _SubprocessCall(cmd, cwd=None):
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  """Runs a command in a subprocess.
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Args:
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    cmd: The command to run.
179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    cwd: Working directory to run from.
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Returns:
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    The return code of the call.
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if os.name == 'nt':
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # "HOME" isn't normally defined on windows, but is needed
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # for git to find the user's .netrc file.
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if not os.getenv('HOME'):
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      os.environ['HOME'] = os.environ['USERPROFILE']
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  shell = os.name == 'nt'
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return subprocess.call(cmd, shell=shell, cwd=cwd)
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochdef RunGClient(params, cwd=None):
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  """Runs gclient with the specified parameters.
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Args:
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    params: A list of parameters to pass to gclient.
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    cwd: Working directory to run from.
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Returns:
201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    The return code of the call.
202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  """
203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  cmd = ['gclient'] + params
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return _SubprocessCall(cmd, cwd=cwd)
205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)def SetupCrosRepo():
2086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  """Sets up CrOS repo for bisecting ChromeOS.
2096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  Returns:
2116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    True if successful, False otherwise.
2126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  """
2136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  cwd = os.getcwd()
2146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  try:
2156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    os.mkdir('cros')
2166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  except OSError as e:
2176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if e.errno != errno.EEXIST:  # EEXIST means the directory already exists.
2186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return False
2196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  os.chdir('cros')
2206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  cmd = ['init', '-u'] + REPO_PARAMS
2226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  passed = False
2246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if not _RunRepo(cmd):
2266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if not _RunRepo(['sync']):
2276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      passed = True
2286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  os.chdir(cwd)
2296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return passed
2316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def _RunRepo(params):
2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Runs CrOS repo command with specified parameters.
235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
236868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Args:
237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    params: A list of parameters to pass to gclient.
238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Returns:
2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    The return code of the call (zero indicates success).
241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  """
242868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  cmd = ['repo'] + params
2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return _SubprocessCall(cmd)
244868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)def RunRepoSyncAtTimestamp(timestamp):
247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  """Syncs all git depots to the timestamp specified using repo forall.
248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Args:
250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    params: Unix timestamp to sync to.
251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Returns:
253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    The return code of the call.
254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  """
255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  cmd = ['forall', '-c', REPO_SYNC_COMMAND % timestamp]
2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return _RunRepo(cmd)
257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
259eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochdef RunGClientAndCreateConfig(opts, custom_deps=None, cwd=None):
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """Runs gclient and creates a config containing both src and src-internal.
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Args:
263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    opts: The options parsed from the command line through parse_args().
264eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    custom_deps: A dictionary of additional dependencies to add to .gclient.
265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    cwd: Working directory to run from.
266868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Returns:
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    The return code of the call.
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """
270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  spec = GCLIENT_SPEC_DATA
271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if custom_deps:
273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for k, v in custom_deps.iteritems():
274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      spec[0]['custom_deps'][k] = v
275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  # Cannot have newlines in string on windows
277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  spec = 'solutions =' + str(spec)
278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  spec = ''.join([l for l in spec.splitlines()])
279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
280a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if 'android' in opts.target_platform:
281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    spec += GCLIENT_SPEC_ANDROID
282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return_code = RunGClient(
2841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ['config', '--spec=%s' % spec], cwd=cwd)
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return return_code
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def OnAccessError(func, path, _):
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Error handler for shutil.rmtree.
2913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Source: http://goo.gl/DEYNCT
2933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  If the error is due to an access error (read only file), it attempts to add
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  write permissions, then retries.
2963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  If the error is for another reason it re-raises the error.
2983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Args:
3003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    func: The function that raised the error.
3013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    path: The path name passed to func.
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    _: Exception information from sys.exc_info(). Not used.
3033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  """
3043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if not os.access(path, os.W_OK):
3053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    os.chmod(path, stat.S_IWUSR)
3063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    func(path)
3073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  else:
3083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    raise
3093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)def RemoveThirdPartyDirectory(dir_name):
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  """Removes third_party directory from the source.
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  At some point, some of the third_parties were causing issues to changes in
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  the way they are synced. We remove such folder in order to avoid sync errors
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  while bisecting.
3173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Returns:
319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    True on success, otherwise False.
3203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  """
321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  path_to_dir = os.path.join(os.getcwd(), 'third_party', dir_name)
3223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  try:
3233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if os.path.exists(path_to_dir):
3243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      shutil.rmtree(path_to_dir, onerror=OnAccessError)
3253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  except OSError, e:
3263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    print 'Error #%d while running shutil.rmtree(%s): %s' % (
3273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        e.errno, path_to_dir, str(e))
3283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if e.errno != errno.ENOENT:
3293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return False
3303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return True
3313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def _CleanupPreviousGitRuns():
3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Cleans up any leftover index.lock files after running git."""
3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  # If a previous run of git crashed, or bot was reset, etc., then we might
3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  # end up with leftover index.lock files.
3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for path, _, files in os.walk(os.getcwd()):
3381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    for cur_file in files:
3391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      if cur_file.endswith('index.lock'):
3401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        path_to_file = os.path.join(path, cur_file)
3411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        os.remove(path_to_file)
3421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
344a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)def RunGClientAndSync(cwd=None):
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """Runs gclient and does a normal sync.
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Args:
348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    cwd: Working directory to run from.
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Returns:
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    The return code of the call.
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """
353a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  params = ['sync', '--verbose', '--nohooks', '--reset', '--force']
354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return RunGClient(params, cwd=cwd)
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)def SetupGitDepot(opts, custom_deps):
3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Sets up the depot for the bisection.
3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  The depot will be located in a subdirectory called 'bisect'.
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Args:
363868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    opts: The options parsed from the command line through parse_args().
3643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    custom_deps: A dictionary of additional dependencies to add to .gclient.
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Returns:
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    True if gclient successfully created the config file and did a sync, False
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    otherwise.
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  name = 'Setting up Bisection Depot'
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if opts.output_buildbot_annotations:
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OutputAnnotationStepStart(name)
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  passed = False
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if not RunGClientAndCreateConfig(opts, custom_deps):
378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    passed_deps_check = True
379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if os.path.isfile(os.path.join('src', FILE_DEPS_GIT)):
380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cwd = os.getcwd()
381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      os.chdir('src')
3823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if passed_deps_check:
383cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        passed_deps_check = RemoveThirdPartyDirectory('libjingle')
384cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if passed_deps_check:
385cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        passed_deps_check = RemoveThirdPartyDirectory('skia')
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      os.chdir(cwd)
387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
388558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if passed_deps_check:
3891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      _CleanupPreviousGitRuns()
3901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
391d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      RunGClient(['revert'])
392a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      if not RunGClientAndSync():
393558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        passed = True
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
395868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if opts.output_buildbot_annotations:
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    print
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OutputAnnotationStepClosed()
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return passed
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)def CheckIfBisectDepotExists(opts):
403424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  """Checks if the bisect directory already exists.
404424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
405424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  Args:
406424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    opts: The options parsed from the command line through parse_args().
407424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
408424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  Returns:
409424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    Returns True if it exists.
410424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  """
411424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  path_to_dir = os.path.join(opts.working_directory, 'bisect', 'src')
412424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return os.path.exists(path_to_dir)
413424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
414424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
4155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def CheckRunGit(command, cwd=None):
4165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Run a git subcommand, returning its output and return code. Asserts if
4175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  the return code of the call is non-zero.
4185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Args:
4205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    command: A list containing the args to git.
4215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Returns:
4235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    A tuple of the output and return code.
4245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """
4255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  (output, return_code) = RunGit(command, cwd=cwd)
4265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  assert not return_code, 'An error occurred while running'\
4285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                          ' "git %s"' % ' '.join(command)
4295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return output
4305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def RunGit(command, cwd=None):
4335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Run a git subcommand, returning its output and return code.
4345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Args:
4365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    command: A list containing the args to git.
4375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    cwd: A directory to change to while running the git command (optional).
4385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Returns:
4405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    A tuple of the output and return code.
4415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """
4425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  command = ['git'] + command
4435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return RunProcessAndRetrieveOutput(command, cwd=cwd)
4445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)def CreateBisectDirectoryAndSetupDepot(opts, custom_deps):
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """Sets up a subdirectory 'bisect' and then retrieves a copy of the depot
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  there using gclient.
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Args:
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    opts: The options parsed from the command line through parse_args().
4523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    custom_deps: A dictionary of additional dependencies to add to .gclient.
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """
4545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if not _CreateAndChangeToSourceDirectory(opts.working_directory):
4558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    raise RuntimeError('Could not create bisect directory.')
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if not SetupGitDepot(opts, custom_deps):
4588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    raise RuntimeError('Failed to grab source.')
4595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def RunProcess(command):
4625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Runs an arbitrary command.
4635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  If output from the call is needed, use RunProcessAndRetrieveOutput instead.
4655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Args:
4675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    command: A list containing the command and args to execute.
4685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Returns:
4705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    The return code of the call.
4715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """
4725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  # On Windows, use shell=True to get PATH interpretation.
4735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  shell = IsWindowsHost()
4745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return subprocess.call(command, shell=shell)
4755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def RunProcessAndRetrieveOutput(command, cwd=None):
4785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Runs an arbitrary command, returning its output and return code.
4795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Since output is collected via communicate(), there will be no output until
4815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  the call terminates. If you need output while the program runs (ie. so
4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  that the buildbot doesn't terminate the script), consider RunProcess().
4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Args:
4855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    command: A list containing the command and args to execute.
4865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    cwd: A directory to change to while running the command. The command can be
4875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        relative to this directory. If this is None, the command will be run in
4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        the current directory.
4895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Returns:
4915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    A tuple of the output and return code.
4925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """
4935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if cwd:
4945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    original_cwd = os.getcwd()
4955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    os.chdir(cwd)
4965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  # On Windows, use shell=True to get PATH interpretation.
4985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  shell = IsWindowsHost()
4995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  proc = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE)
5005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  (output, _) = proc.communicate()
5015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if cwd:
5035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    os.chdir(original_cwd)
5045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return (output, proc.returncode)
5065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def IsStringInt(string_to_check):
5095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Checks whether or not the given string can be converted to a integer.
5105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Args:
5125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    string_to_check: Input string to check if it can be converted to an int.
5135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Returns:
5155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    True if the string can be converted to an int.
5165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """
5175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  try:
5185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int(string_to_check)
5195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return True
5205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  except ValueError:
5215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return False
5225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def IsStringFloat(string_to_check):
5255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Checks whether or not the given string can be converted to a floating
5265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  point number.
5275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Args:
5295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    string_to_check: Input string to check if it can be converted to a float.
5305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Returns:
5325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    True if the string can be converted to a float.
5335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """
5345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  try:
5355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    float(string_to_check)
5365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return True
5375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  except ValueError:
5385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return False
5395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def IsWindowsHost():
5425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Checks whether or not the script is running on Windows.
5435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Returns:
5455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    True if running on Windows.
5465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """
5475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return sys.platform == 'cygwin' or sys.platform.startswith('win')
5485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def Is64BitWindows():
5515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Returns whether or not Windows is a 64-bit version.
5525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Returns:
5545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    True if Windows is 64-bit, False if 32-bit.
5555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """
5565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  platform = os.environ['PROCESSOR_ARCHITECTURE']
5575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  try:
5585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    platform = os.environ['PROCESSOR_ARCHITEW6432']
5595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  except KeyError:
5605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # Must not be running in WoW64, so PROCESSOR_ARCHITECTURE is correct
5615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    pass
5625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return platform in ['AMD64', 'I64']
5645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def IsLinuxHost():
5675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Checks whether or not the script is running on Linux.
5685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Returns:
5705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    True if running on Linux.
5715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """
5725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return sys.platform.startswith('linux')
5735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def IsMacHost():
5765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Checks whether or not the script is running on Mac.
5775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Returns:
5795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    True if running on Mac.
5805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """
5815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return sys.platform.startswith('darwin')
582