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', 'android_n_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-clang',
     72                                        zip_name='chrome-win-clang.zip'),
     73                  'win_AMD64': UpdateInfo(omaha='win',
     74                                          gs_folder='desktop-*',
     75                                          gs_build='win64-clang',
     76                                          zip_name='chrome-win64-clang.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                  'android_n_armeabi-v7a': UpdateInfo(omaha='android',
     94                                                      gs_folder='android-*',
     95                                                      gs_build='arm',
     96                                                      zip_name='Monochrome.apk'),
     97 
     98 }
     99 
    100 
    101 def _ChannelVersionsMap(channel):
    102   rows = _OmahaReportVersionInfo(channel)
    103   omaha_versions_map = _OmahaVersionsMap(rows, channel)
    104   channel_versions_map = {}
    105   for platform in _PLATFORMS_TO_UPDATE:
    106     omaha_platform = _PLATFORM_MAP[platform].omaha
    107     if omaha_platform in omaha_versions_map:
    108       channel_versions_map[platform] = omaha_versions_map[omaha_platform]
    109   return channel_versions_map
    110 
    111 
    112 def _OmahaReportVersionInfo(channel):
    113   url ='https://omahaproxy.appspot.com/all?channel=%s' % channel
    114   lines = urllib2.urlopen(url).readlines()
    115   return [l.split(',') for l in lines]
    116 
    117 
    118 def _OmahaVersionsMap(rows, channel):
    119   platforms = _OMAHA_PLATFORMS.get(channel, [])
    120   if (len(rows) < 1 or
    121       not rows[0][0:3] == ['os', 'channel', 'current_version']):
    122     raise ValueError(
    123         'Omaha report is not in the expected form: %s.' % rows)
    124   versions_map = {}
    125   for row in rows[1:]:
    126     if row[1] != channel:
    127       raise ValueError(
    128           'Omaha report contains a line with the channel %s' % row[1])
    129     if row[0] in platforms:
    130       versions_map[row[0]] = row[2]
    131   logging.warn('versions map: %s' % versions_map)
    132   if not all(platform in versions_map for platform in platforms):
    133     raise ValueError(
    134         'Omaha report did not contain all desired platforms for channel %s' % channel)
    135   return versions_map
    136 
    137 
    138 def _QueuePlatformUpdate(platform, version, config, channel):
    139   """ platform: the name of the platform for the browser to
    140       be downloaded & updated from cloud storage. """
    141   platform_info = _PLATFORM_MAP[platform]
    142   filename = platform_info.zip_name
    143   # remote_path example: desktop-*/30.0.1595.0/precise32/chrome-precise32.zip
    144   remote_path = '%s/%s/%s/%s' % (
    145       platform_info.gs_folder, version, platform_info.gs_build, filename)
    146   if not cloud_storage.Exists(CHROME_GS_BUCKET, remote_path):
    147     cloud_storage_path = 'gs://%s/%s' % (CHROME_GS_BUCKET, remote_path)
    148     raise BuildNotFoundError(
    149         'Failed to find %s build for version %s at path %s.' % (
    150             platform, version, cloud_storage_path))
    151   reference_builds_folder = os.path.join(
    152       os.path.dirname(os.path.abspath(__file__)), 'chrome_telemetry_build',
    153       'reference_builds', channel)
    154   if not os.path.exists(reference_builds_folder):
    155     os.makedirs(reference_builds_folder)
    156   local_dest_path = os.path.join(reference_builds_folder, filename)
    157   cloud_storage.Get(CHROME_GS_BUCKET, remote_path, local_dest_path)
    158   config.AddCloudStorageDependencyUpdateJob(
    159       'chrome_%s' % channel, platform, local_dest_path, version=version,
    160       execute_job=False)
    161 
    162 
    163 def UpdateBuilds():
    164   config = base_config.BaseConfig(_CHROME_BINARIES_CONFIG, writable=True)
    165   for channel in _CHANNELS_TO_UPDATE:
    166     channel_versions_map = _ChannelVersionsMap(channel)
    167     for platform in channel_versions_map:
    168       print 'Downloading Chrome (%s channel) on %s' % (channel, platform)
    169       current_version = config.GetVersion('chrome_%s' % channel, platform)
    170       channel_version =  channel_versions_map.get(platform)
    171       print 'current: %s, channel: %s' % (current_version, channel_version)
    172       if current_version and current_version == channel_version:
    173         continue
    174       _QueuePlatformUpdate(platform, channel_version, config, channel)
    175     # TODO: move execute update jobs here, and add committing/uploading the cl.
    176 
    177   print 'Updating chrome builds with downloaded binaries'
    178   config.ExecuteUpdateJobs(force=True)
    179 
    180 
    181 def main():
    182   logging.getLogger().setLevel(logging.DEBUG)
    183   #TODO(aiolos): alert sheriffs via email when an error is seen.
    184   #This should be added when alerts are added when updating the build.
    185   UpdateBuilds()
    186   # TODO(aiolos): Add --commit flag. crbug.com/547229
    187 
    188 if __name__ == '__main__':
    189   main()
    190