Home | History | Annotate | Download | only in bin
      1 #!/usr/bin/env python
      2 #
      3 # Copyright 2013 The Chromium Authors. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 """Updates the Chrome reference builds.
      8 
      9 Usage:
     10   $ /path/to/update_reference_build.py
     11   $ git commit -a
     12   $ git cl upload
     13 """
     14 
     15 import collections
     16 import logging
     17 import os
     18 import shutil
     19 import subprocess
     20 import sys
     21 import urllib2
     22 import zipfile
     23 
     24 sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'py_utils'))
     25 
     26 from py_utils import cloud_storage
     27 from dependency_manager import base_config
     28 
     29 
     30 def BuildNotFoundError(error_string):
     31   raise ValueError(error_string)
     32 
     33 
     34 _CHROME_BINARIES_CONFIG = os.path.join(
     35     os.path.dirname(os.path.abspath(__file__)), '..', '..', 'common',
     36     'py_utils', 'py_utils', 'chrome_binaries.json')
     37 
     38 CHROME_GS_BUCKET = 'chrome-unsigned'
     39 
     40 
     41 # Remove a platform name from this list to disable updating it.
     42 # Add one to enable updating it. (Must also update _PLATFORM_MAP.)
     43 _PLATFORMS_TO_UPDATE = ['mac_x86_64', 'win_x86', 'win_AMD64', 'linux_x86_64',
     44                         'android_k_armeabi-v7a', 'android_l_arm64-v8a',
     45                         'android_l_armeabi-v7a']
     46 
     47 # Remove a channal name from this list to disable updating it.
     48 # Add one to enable updating it.
     49 _CHANNELS_TO_UPDATE = ['stable'] # 'canary', 'dev'
     50 
     51 
     52 # Omaha is Chrome's autoupdate server. It reports the current versions used
     53 # by each platform on each channel.
     54 _OMAHA_PLATFORMS = { 'stable':  ['mac', 'linux', 'win', 'android'],
     55                     'dev':  ['linux'], 'canary': ['mac', 'win']}
     56 
     57 
     58 # All of the information we need to update each platform.
     59 #   omaha: name omaha uses for the plaftorms.
     60 #   zip_name: name of the zip file to be retrieved from cloud storage.
     61 #   gs_build: name of the Chrome build platform used in cloud storage.
     62 #   destination: Name of the folder to download the reference build to.
     63 UpdateInfo = collections.namedtuple('UpdateInfo',
     64     'omaha, gs_folder, gs_build, zip_name')
     65 _PLATFORM_MAP = { 'mac_x86_64': UpdateInfo(omaha='mac',
     66                                            gs_folder='desktop-*',
     67                                            gs_build='mac64',
     68                                            zip_name='chrome-mac.zip'),
     69                   'win_x86': UpdateInfo(omaha='win',
     70                                         gs_folder='desktop-*',
     71                                         gs_build='win',
     72                                         zip_name='chrome-win.zip'),
     73                   'win_AMD64': UpdateInfo(omaha='win',
     74                                           gs_folder='desktop-*',
     75                                           gs_build='win64',
     76                                           zip_name='chrome-win64.zip'),
     77                   'linux_x86_64': UpdateInfo(omaha='linux',
     78                                              gs_folder='desktop-*',
     79                                              gs_build='linux64',
     80                                              zip_name='chrome-linux64.zip'),
     81                   'android_k_armeabi-v7a': UpdateInfo(omaha='android',
     82                                                       gs_folder='android-*',
     83                                                       gs_build='arm',
     84                                                       zip_name='Chrome.apk'),
     85                   'android_l_arm64-v8a': UpdateInfo(omaha='android',
     86                                                     gs_folder='android-*',
     87                                                     gs_build='arm_64',
     88                                                     zip_name='ChromeModern.apk'),
     89                   'android_l_armeabi-v7a': UpdateInfo(omaha='android',
     90                                                       gs_folder='android-*',
     91                                                       gs_build='arm',
     92                                                       zip_name='Chrome.apk'),
     93 }
     94 
     95 
     96 def _ChannelVersionsMap(channel):
     97   rows = _OmahaReportVersionInfo(channel)
     98   omaha_versions_map = _OmahaVersionsMap(rows, channel)
     99   channel_versions_map = {}
    100   for platform in _PLATFORMS_TO_UPDATE:
    101     omaha_platform = _PLATFORM_MAP[platform].omaha
    102     if omaha_platform in omaha_versions_map:
    103       channel_versions_map[platform] = omaha_versions_map[omaha_platform]
    104   return channel_versions_map
    105 
    106 
    107 def _OmahaReportVersionInfo(channel):
    108   url ='https://omahaproxy.appspot.com/all?channel=%s' % channel
    109   lines = urllib2.urlopen(url).readlines()
    110   return [l.split(',') for l in lines]
    111 
    112 
    113 def _OmahaVersionsMap(rows, channel):
    114   platforms = _OMAHA_PLATFORMS.get(channel, [])
    115   if (len(rows) < 1 or
    116       not rows[0][0:3] == ['os', 'channel', 'current_version']):
    117     raise ValueError(
    118         'Omaha report is not in the expected form: %s.' % rows)
    119   versions_map = {}
    120   for row in rows[1:]:
    121     if row[1] != channel:
    122       raise ValueError(
    123           'Omaha report contains a line with the channel %s' % row[1])
    124     if row[0] in platforms:
    125       versions_map[row[0]] = row[2]
    126   logging.warn('versions map: %s' % versions_map)
    127   if not all(platform in versions_map for platform in platforms):
    128     raise ValueError(
    129         'Omaha report did not contain all desired platforms for channel %s' % channel)
    130   return versions_map
    131 
    132 
    133 def _QueuePlatformUpdate(platform, version, config, channel):
    134   """ platform: the name of the platform for the browser to
    135       be downloaded & updated from cloud storage. """
    136   platform_info = _PLATFORM_MAP[platform]
    137   filename = platform_info.zip_name
    138   # remote_path example: desktop-*/30.0.1595.0/precise32/chrome-precise32.zip
    139   remote_path = '%s/%s/%s/%s' % (
    140       platform_info.gs_folder, version, platform_info.gs_build, filename)
    141   if not cloud_storage.Exists(CHROME_GS_BUCKET, remote_path):
    142     raise BuildNotFoundError(
    143         'Failed to find %s build for version %s at path %s.' % (platform, version, remote_path))
    144   reference_builds_folder = os.path.join(
    145       os.path.dirname(os.path.abspath(__file__)), 'chrome_telemetry_build',
    146       'reference_builds', channel)
    147   if not os.path.exists(reference_builds_folder):
    148     os.makedirs(reference_builds_folder)
    149   local_dest_path = os.path.join(reference_builds_folder, filename)
    150   cloud_storage.Get(CHROME_GS_BUCKET, remote_path, local_dest_path)
    151   config.AddCloudStorageDependencyUpdateJob(
    152       'chrome_%s' % channel, platform, local_dest_path, version=version,
    153       execute_job=False)
    154 
    155 
    156 def UpdateBuilds():
    157   config = base_config.BaseConfig(_CHROME_BINARIES_CONFIG, writable=True)
    158   for channel in _CHANNELS_TO_UPDATE:
    159     channel_versions_map = _ChannelVersionsMap(channel)
    160     for platform in channel_versions_map:
    161       print 'Downloading Chrome (%s channel) on %s' % (channel, platform)
    162       current_version = config.GetVersion('chrome_%s' % channel, platform)
    163       channel_version =  channel_versions_map.get(platform)
    164       print 'current: %s, channel: %s' % (current_version, channel_version)
    165       if current_version and current_version == channel_version:
    166         continue
    167       _QueuePlatformUpdate(platform, channel_version, config, channel)
    168     # TODO: move execute update jobs here, and add committing/uploading the cl.
    169 
    170   print 'Updating chrome builds with downloaded binaries'
    171   config.ExecuteUpdateJobs(force=True)
    172 
    173 
    174 def main():
    175   logging.getLogger().setLevel(logging.DEBUG)
    176   #TODO(aiolos): alert sheriffs via email when an error is seen.
    177   #This should be added when alerts are added when updating the build.
    178   UpdateBuilds()
    179   # TODO(aiolos): Add --commit flag. crbug.com/547229
    180 
    181 if __name__ == '__main__':
    182   main()
    183