12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#!/usr/bin/env python
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Copyright (c) 2013 The Chromium Authors. All rights reserved.
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# found in the LICENSE file.
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)"""Runs all the buildbot steps for ChromeDriver except for update/compile."""
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import bisect
9424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)import csv
10424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)import datetime
111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import glob
12d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import json
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import optparse
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import os
15d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import platform as platform_module
16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import re
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import shutil
18424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)import StringIO
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import sys
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import tempfile
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import time
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import urllib2
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)_THIS_DIR = os.path.abspath(os.path.dirname(__file__))
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)GS_CHROMEDRIVER_BUCKET = 'gs://chromedriver'
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)GS_CHROMEDRIVER_DATA_BUCKET = 'gs://chromedriver-data'
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GS_CHROMEDRIVER_RELEASE_URL = 'http://chromedriver.storage.googleapis.com'
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)GS_CONTINUOUS_URL = GS_CHROMEDRIVER_DATA_BUCKET + '/continuous'
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)GS_PREBUILTS_URL = GS_CHROMEDRIVER_DATA_BUCKET + '/prebuilts'
301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)GS_SERVER_LOGS_URL = GS_CHROMEDRIVER_DATA_BUCKET + '/server_logs'
310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)SERVER_LOGS_LINK = (
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    'http://chromedriver-data.storage.googleapis.com/server_logs')
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_LOG_FORMAT = '%s_log.json'
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciGS_GIT_LOG_URL = (
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    'https://chromium.googlesource.com/chromium/src/+/%s?format=json')
36116680a4aac90f2aa7413d9095a592090648e557Ben MurdochGS_SEARCH_PATTERN = (
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    r'Cr-Commit-Position: refs/heads/master@{#(\d+)}')
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciCR_REV_URL = 'https://cr-rev.appspot.com/_ah/api/crrev/v1/redirect/%s'
39d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)SCRIPT_DIR = os.path.join(_THIS_DIR, os.pardir, os.pardir, os.pardir, os.pardir,
41d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                          os.pardir, os.pardir, os.pardir, 'scripts')
42d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)SITE_CONFIG_DIR = os.path.join(_THIS_DIR, os.pardir, os.pardir, os.pardir,
43d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                               os.pardir, os.pardir, os.pardir, os.pardir,
44d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                               'site_config')
45d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)sys.path.append(SCRIPT_DIR)
46d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)sys.path.append(SITE_CONFIG_DIR)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import archive
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import chrome_paths
50d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)from slave import gsutil_download
51d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)from slave import slave_utils
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import util
53d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
54d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def _ArchivePrebuilts(revision):
56d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """Uploads the prebuilts to google storage."""
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  util.MarkBuildStepStart('archive prebuilts')
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  zip_path = util.Zip(os.path.join(chrome_paths.GetBuildDir(['chromedriver']),
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                   'chromedriver'))
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if slave_utils.GSUtilCopy(
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      zip_path,
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      '%s/%s' % (GS_PREBUILTS_URL, 'r%s.zip' % revision)):
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    util.MarkBuildStepError()
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def _ArchiveServerLogs():
671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  """Uploads chromedriver server logs to google storage."""
681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  util.MarkBuildStepStart('archive chromedriver server logs')
691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for server_log in glob.glob(os.path.join(tempfile.gettempdir(),
701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                           'chromedriver_*')):
710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    base_name = os.path.basename(server_log)
720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    util.AddLink(base_name, '%s/%s' % (SERVER_LOGS_LINK, base_name))
731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    slave_utils.GSUtilCopy(
740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        server_log,
750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        '%s/%s' % (GS_SERVER_LOGS_URL, base_name),
760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        mimetype='text/plain')
771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def _DownloadPrebuilts():
80d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """Downloads the most recent prebuilts from google storage."""
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  util.MarkBuildStepStart('Download latest chromedriver')
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  zip_path = os.path.join(util.MakeTempDir(), 'build.zip')
84c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if gsutil_download.DownloadLatestFile(GS_PREBUILTS_URL,
85c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                        GS_PREBUILTS_URL + '/r',
86c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                        zip_path):
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    util.MarkBuildStepError()
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  util.Unzip(zip_path, chrome_paths.GetBuildDir(['host_forwarder']))
90d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
91d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def _GetTestResultsLog(platform):
93d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """Gets the test results log for the given platform.
94d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Args:
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    platform: The platform that the test results log is for.
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
98d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Returns:
99d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    A dictionary where the keys are SVN revisions and the values are booleans
100d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    indicating whether the tests passed.
101d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """
102d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  temp_log = tempfile.mkstemp()[1]
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  log_name = TEST_LOG_FORMAT % platform
104d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  result = slave_utils.GSUtilDownloadFile(
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      '%s/%s' % (GS_CHROMEDRIVER_DATA_BUCKET, log_name), temp_log)
106d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if result:
107d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return {}
108d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  with open(temp_log, 'rb') as log_file:
109d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    json_dict = json.load(log_file)
110d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  # Workaround for json encoding dictionary keys as strings.
111d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return dict([(int(v[0]), v[1]) for v in json_dict.items()])
112d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
113d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
114d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)def _PutTestResultsLog(platform, test_results_log):
115d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """Pushes the given test results log to google storage."""
116d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  temp_dir = util.MakeTempDir()
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  log_name = TEST_LOG_FORMAT % platform
118d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  log_path = os.path.join(temp_dir, log_name)
119d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  with open(log_path, 'wb') as log_file:
120d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    json.dump(test_results_log, log_file)
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if slave_utils.GSUtilCopyFile(log_path, GS_CHROMEDRIVER_DATA_BUCKET):
122d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    raise Exception('Failed to upload test results log to google storage')
123d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
124d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def _UpdateTestResultsLog(platform, revision, passed):
126d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """Updates the test results log for the given platform.
127d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
128d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Args:
129d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    platform: The platform name.
130d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    revision: The SVN revision number.
131d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    passed: Boolean indicating whether the tests passed at this revision.
132d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """
133d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  assert isinstance(revision, int), 'The revision must be an integer'
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  log = _GetTestResultsLog(platform)
135d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if len(log) > 500:
136d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    del log[min(log.keys())]
137d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  assert revision not in log, 'Results already exist for revision %s' % revision
138d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  log[revision] = bool(passed)
139d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  _PutTestResultsLog(platform, log)
140d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
141d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def _GetVersion():
143d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """Get the current chromedriver version."""
144d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  with open(os.path.join(_THIS_DIR, 'VERSION'), 'r') as f:
145d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return f.read().strip()
146d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
147d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def _GetSupportedChromeVersions():
149d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """Get the minimum and maximum supported Chrome versions.
150d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
151d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Returns:
152d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    A tuple of the form (min_version, max_version).
153d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  # Minimum supported Chrome version is embedded as:
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  # const int kMinimumSupportedChromeVersion[] = {27, 0, 1453, 0};
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  with open(os.path.join(_THIS_DIR, 'chrome', 'version.cc'), 'r') as f:
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    lines = f.readlines()
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    chrome_min_version_line = [
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        x for x in lines if 'kMinimumSupportedChromeVersion' in x]
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  chrome_min_version = chrome_min_version_line[0].split('{')[1].split(',')[0]
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  with open(os.path.join(chrome_paths.GetSrc(), 'chrome', 'VERSION'), 'r') as f:
162d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    chrome_max_version = f.readlines()[0].split('=')[1].strip()
163d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return (chrome_min_version, chrome_max_version)
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
166d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)def _RevisionState(test_results_log, revision):
167d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """Check the state of tests at a given SVN revision.
168d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
169d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Considers tests as having passed at a revision if they passed at revisons both
170d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  before and after.
171d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
172d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Args:
1734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    test_results_log: A test results log dictionary from _GetTestResultsLog().
174d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    revision: The revision to check at.
175d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
176d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Returns:
177d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    'passed', 'failed', or 'unknown'
178d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """
179d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  assert isinstance(revision, int), 'The revision must be an integer'
180d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  keys = sorted(test_results_log.keys())
181d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  # Return passed if the exact revision passed on Android.
182d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if revision in test_results_log:
183d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return 'passed' if test_results_log[revision] else 'failed'
184d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  # Tests were not run on this exact revision on Android.
185d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  index = bisect.bisect_right(keys, revision)
186d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  # Tests have not yet run on Android at or above this revision.
187d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if index == len(test_results_log):
188d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return 'unknown'
189d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  # No log exists for any prior revision, assume it failed.
190d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if index == 0:
191d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return 'failed'
192d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  # Return passed if the revisions on both sides passed.
193d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if test_results_log[keys[index]] and test_results_log[keys[index - 1]]:
194d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return 'passed'
195d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return 'failed'
196d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
197d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def _ArchiveGoodBuild(platform, revision):
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  """Archive chromedriver binary if the build is green."""
200d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  assert platform != 'android'
2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  util.MarkBuildStepStart('archive build')
2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  server_name = 'chromedriver'
2044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if util.IsWindows():
2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    server_name += '.exe'
2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  zip_path = util.Zip(os.path.join(chrome_paths.GetBuildDir([server_name]),
2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                   server_name))
2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  build_name = 'chromedriver_%s_%s.%s.zip' % (
210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      platform, _GetVersion(), revision)
211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  build_url = '%s/%s' % (GS_CONTINUOUS_URL, build_name)
2124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if slave_utils.GSUtilCopy(zip_path, build_url):
2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    util.MarkBuildStepError()
214d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  (latest_fd, latest_file) = tempfile.mkstemp()
216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  os.write(latest_fd, build_name)
217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  os.close(latest_fd)
218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  latest_url = '%s/latest_%s' % (GS_CONTINUOUS_URL, platform)
219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if slave_utils.GSUtilCopy(latest_file, latest_url, mimetype='text/plain'):
220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    util.MarkBuildStepError()
221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  os.remove(latest_file)
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
223d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def _WasReleased(version, platform):
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  """Check if the specified version is released for the given platform."""
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result, _ = slave_utils.GSUtilListBucket(
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      '%s/%s/chromedriver_%s.zip' % (GS_CHROMEDRIVER_BUCKET, version, platform),
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      [])
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return result == 0
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
232d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)def _MaybeRelease(platform):
2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  """Releases a release candidate if conditions are right."""
234d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  assert platform != 'android'
2354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  version = _GetVersion()
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  # Check if the current version has already been released.
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if _WasReleased(version, platform):
240d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return
241d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  # Fetch Android test results.
2434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  android_test_results = _GetTestResultsLog('android')
2444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  # Fetch release candidates.
2464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  result, output = slave_utils.GSUtilListBucket(
2474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      '%s/chromedriver_%s_%s*' % (
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          GS_CONTINUOUS_URL, platform, version),
2494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      [])
2504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  assert result == 0 and output, 'No release candidates found'
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  candidate_pattern = re.compile(
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      r'.*/chromedriver_%s_%s\.(\d+)\.zip$' % (platform, version))
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  candidates = []
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for line in output.strip().split('\n'):
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result = candidate_pattern.match(line)
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not result:
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      print 'Ignored line "%s"' % line
2580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      continue
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    candidates.append(int(result.group(1)))
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Release the latest candidate build that passed Android, if any.
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # In this way, if a hot fix is needed, we can delete the release from
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # the chromedriver bucket instead of bumping up the release version number.
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  candidates.sort(reverse=True)
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for revision in candidates:
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    android_result = _RevisionState(android_test_results, revision)
2674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if android_result == 'failed':
2684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      print 'Android tests did not pass at revision', revision
2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    elif android_result == 'passed':
2704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      print 'Android tests passed at revision', revision
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      candidate = 'chromedriver_%s_%s.%s.zip' % (platform, version, revision)
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      _Release('%s/%s' % (GS_CONTINUOUS_URL, candidate), version, platform)
2734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      break
2744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    else:
2754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      print 'Android tests have not run at a revision as recent as', revision
276d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def _Release(build, version, platform):
2794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  """Releases the given candidate build."""
2804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  release_name = 'chromedriver_%s.zip' % platform
2814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  util.MarkBuildStepStart('releasing %s' % release_name)
2825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  temp_dir = util.MakeTempDir()
2835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  slave_utils.GSUtilCopy(build, temp_dir)
2845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  zip_path = os.path.join(temp_dir, os.path.basename(build))
2855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if util.IsLinux():
2875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    util.Unzip(zip_path, temp_dir)
2885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    server_path = os.path.join(temp_dir, 'chromedriver')
2895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    util.RunCommand(['strip', server_path])
2905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    zip_path = util.Zip(server_path)
2915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  slave_utils.GSUtilCopy(
2935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      zip_path, '%s/%s/%s' % (GS_CHROMEDRIVER_BUCKET, version, release_name))
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  _MaybeUploadReleaseNotes(version)
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  _MaybeUpdateLatestRelease(version)
297424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def _GetWebPageContent(url):
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  """Return the content of the web page specified by the given url."""
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return urllib2.urlopen(url).read()
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def _MaybeUploadReleaseNotes(version):
305d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """Upload release notes if conditions are right."""
3064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  # Check if the current version has already been released.
3074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  notes_name = 'notes.txt'
3084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  notes_url = '%s/%s/%s' % (GS_CHROMEDRIVER_BUCKET, version, notes_name)
309424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  prev_version = '.'.join([version.split('.')[0],
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           str(int(version.split('.')[1]) - 1)])
3114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  prev_notes_url = '%s/%s/%s' % (
3124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      GS_CHROMEDRIVER_BUCKET, prev_version, notes_name)
3134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  result, _ = slave_utils.GSUtilListBucket(notes_url, [])
3154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if result == 0:
3164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return
317424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
318424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  fixed_issues = []
319424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  query = ('https://code.google.com/p/chromedriver/issues/csv?'
320424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)           'q=status%3AToBeReleased&colspec=ID%20Summary')
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  issues = StringIO.StringIO(_GetWebPageContent(query).split('\n', 1)[1])
322424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  for issue in csv.reader(issues):
323424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if not issue:
324424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      continue
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    issue_id = issue[0]
326424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    desc = issue[1]
327424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    labels = issue[2]
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fixed_issues += ['Resolved issue %s: %s [%s]' % (issue_id, desc, labels)]
329424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
330d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  old_notes = ''
331d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  temp_notes_fname = tempfile.mkstemp()[1]
3324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if not slave_utils.GSUtilDownloadFile(prev_notes_url, temp_notes_fname):
333d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    with open(temp_notes_fname, 'rb') as f:
334d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      old_notes = f.read()
3354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  new_notes = '----------ChromeDriver v%s (%s)----------\n%s\n%s\n\n%s' % (
337424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      version, datetime.date.today().isoformat(),
3384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'Supports Chrome v%s-%s' % _GetSupportedChromeVersions(),
339424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      '\n'.join(fixed_issues),
340424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      old_notes)
3414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  with open(temp_notes_fname, 'w') as f:
342424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    f.write(new_notes)
343424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
3444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if slave_utils.GSUtilCopy(temp_notes_fname, notes_url, mimetype='text/plain'):
345d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    util.MarkBuildStepError()
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def _MaybeUpdateLatestRelease(version):
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  """Update the file LATEST_RELEASE with the latest release version number."""
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  latest_release_fname = 'LATEST_RELEASE'
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  latest_release_url = '%s/%s' % (GS_CHROMEDRIVER_BUCKET, latest_release_fname)
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Check if LATEST_RELEASE is up-to-date.
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  latest_released_version = _GetWebPageContent(
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      '%s/%s' % (GS_CHROMEDRIVER_RELEASE_URL, latest_release_fname))
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if version == latest_released_version:
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Check if chromedriver was released on all supported platforms.
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  supported_platforms = ['linux32', 'linux64', 'mac32', 'win32']
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for platform in supported_platforms:
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not _WasReleased(version, platform):
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  util.MarkBuildStepStart('updating LATEST_RELEASE to %s' % version)
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  temp_latest_release_fname = tempfile.mkstemp()[1]
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  with open(temp_latest_release_fname, 'w') as f:
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    f.write(version)
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if slave_utils.GSUtilCopy(temp_latest_release_fname, latest_release_url,
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            mimetype='text/plain'):
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    util.MarkBuildStepError()
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def _CleanTmpDir():
376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  tmp_dir = tempfile.gettempdir()
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  print 'cleaning temp directory:', tmp_dir
378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for file_name in os.listdir(tmp_dir):
3790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    file_path = os.path.join(tmp_dir, file_name)
3800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if os.path.isdir(file_path):
3810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      print 'deleting sub-directory', file_path
3820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      shutil.rmtree(file_path, True)
3830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if file_name.startswith('chromedriver_'):
3840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      print 'deleting file', file_path
3850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      os.remove(file_path)
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef _GetCommitPositionFromGitHash(snapshot_hashcode):
3891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  json_url = GS_GIT_LOG_URL % snapshot_hashcode
390116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  try:
391116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    response = urllib2.urlopen(json_url)
392116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  except urllib2.HTTPError as error:
393116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    util.PrintAndFlush('HTTP Error %d' % error.getcode())
3941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return None
395116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  except urllib2.URLError as error:
396116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    util.PrintAndFlush('URL Error %s' % error.message)
397116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return None
398116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  data = json.loads(response.read()[4:])
399116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if 'message' in data:
400116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    message = data['message'].split('\n')
401116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    message = [line for line in message if line.strip()]
402116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    search_pattern = re.compile(GS_SEARCH_PATTERN)
403116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    result = search_pattern.search(message[len(message)-1])
404116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if result:
405116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return result.group(1)
406116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  util.PrintAndFlush('Failed to get svn revision number for %s' %
407116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     snapshot_hashcode)
408116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return None
409116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
410116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
4111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef _GetGitHashFromCommitPosition(commit_position):
4121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  json_url = CR_REV_URL % commit_position
4131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  try:
4141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    response = urllib2.urlopen(json_url)
4151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  except urllib2.HTTPError as error:
4161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    util.PrintAndFlush('HTTP Error %d' % error.getcode())
4171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return None
4181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  except urllib2.URLError as error:
4191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    util.PrintAndFlush('URL Error %s' % error.message)
4201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return None
4211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  data = json.loads(response.read())
4221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if 'git_sha' in data:
4231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return data['git_sha']
4241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  util.PrintAndFlush('Failed to get git hash for %s' % commit_position)
4251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return None
4261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def _WaitForLatestSnapshot(revision):
42990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  util.MarkBuildStepStart('wait_for_snapshot')
430116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def _IsRevisionNumber(revision):
431116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if isinstance(revision, int):
432116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return True
433116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    else:
434116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return revision.isdigit()
43590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  while True:
436f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    snapshot_revision = archive.GetLatestSnapshotVersion()
437116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if not _IsRevisionNumber(snapshot_revision):
4381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      snapshot_revision = _GetCommitPositionFromGitHash(snapshot_revision)
439116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if revision is not None and snapshot_revision is not None:
440116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if int(snapshot_revision) >= int(revision):
441116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        break
442116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      util.PrintAndFlush('Waiting for snapshot >= %s, found %s' %
443116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         (revision, snapshot_revision))
44490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    time.sleep(60)
44590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  util.PrintAndFlush('Got snapshot revision %s' % snapshot_revision)
44690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
44790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def _AddToolsToPath(platform_name):
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  """Add some tools like Ant and Java to PATH for testing steps to use."""
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  paths = []
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  error_message = ''
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if platform_name == 'win32':
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    paths = [
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Path to Ant and Java, required for the java acceptance tests.
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'C:\\Program Files (x86)\\Java\\ant\\bin',
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'C:\\Program Files (x86)\\Java\\jre\\bin',
4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ]
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    error_message = ('Java test steps will fail as expected and '
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     'they can be ignored.\n'
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     'Ant, Java or others might not be installed on bot.\n'
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     'Please refer to page "WATERFALL" on site '
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     'go/chromedriver.')
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if paths:
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    util.MarkBuildStepStart('Add tools to PATH')
4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    path_missing = False
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for path in paths:
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if not os.path.isdir(path) or not os.listdir(path):
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        print 'Directory "%s" is not found or empty.' % path
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        path_missing = True
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if path_missing:
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      print error_message
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      util.MarkBuildStepError()
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    os.environ['PATH'] += os.pathsep + os.pathsep.join(paths)
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def main():
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  parser = optparse.OptionParser()
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  parser.add_option(
4803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      '', '--android-packages',
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      help=('Comma separated list of application package names, '
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            'if running tests on Android.'))
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  parser.add_option(
4841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      '-r', '--revision', help='Chromium revision')
4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  parser.add_option(
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      '', '--update-log', action='store_true',
48768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      help='Update the test results log (only applicable to Android)')
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options, _ = parser.parse_args()
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
490d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  bitness = '32'
491d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if util.IsLinux() and platform_module.architecture()[0] == '64bit':
492d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    bitness = '64'
493d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  platform = '%s%s' % (util.GetPlatformName(), bitness)
494d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if options.android_packages:
495d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    platform = 'android'
496d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
4974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  _CleanTmpDir()
498c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if not options.revision:
5001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    commit_position = None
5011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  elif options.revision.isdigit():
5021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    commit_position = options.revision
5031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  else:
5041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    commit_position = _GetCommitPositionFromGitHash(options.revision)
5051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
506d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if platform == 'android':
50768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if not options.revision and options.update_log:
50868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      parser.error('Must supply a --revision with --update-log')
5094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    _DownloadPrebuilts()
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else:
51190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if not options.revision:
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      parser.error('Must supply a --revision')
513d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if platform == 'linux64':
5141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      _ArchivePrebuilts(commit_position)
5151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    _WaitForLatestSnapshot(commit_position)
51690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  _AddToolsToPath(platform)
5185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cmd = [
52090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      sys.executable,
521ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      os.path.join(_THIS_DIR, 'test', 'run_all_tests.py'),
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ]
523d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if platform == 'android':
5243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    cmd.append('--android-packages=' + options.android_packages)
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  passed = (util.RunCommand(cmd) == 0)
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  _ArchiveServerLogs()
5291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
530d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if platform == 'android':
53168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if options.update_log:
53268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      util.MarkBuildStepStart('update test result log')
5331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      _UpdateTestResultsLog(platform, commit_position, passed)
534d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  elif passed:
5351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    _ArchiveGoodBuild(platform, commit_position)
536d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    _MaybeRelease(platform)
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if not passed:
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Make sure the build is red if there is some uncaught exception during
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # running run_all_tests.py.
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    util.MarkBuildStepStart('run_all_tests.py')
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    util.MarkBuildStepError()
5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Add a "cleanup" step so that errors from runtest.py or bb_device_steps.py
5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # (which invoke this script) are kept in thier own build step.
5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  util.MarkBuildStepStart('cleanup')
5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)if __name__ == '__main__':
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  main()
551