Home | History | Annotate | Download | only in webrtc
      1 #!/usr/bin/env python
      2 # Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
      3 #
      4 # Use of this source code is governed by a BSD-style license
      5 # that can be found in the LICENSE file in the root of the source
      6 # tree. An additional intellectual property rights grant can be found
      7 # in the file PATENTS.  All contributing project authors may
      8 # be found in the AUTHORS file in the root of the source tree.
      9 
     10 """Script to download a Chromium checkout into the workspace.
     11 
     12 The script downloads a full Chromium Git clone and its DEPS.
     13 
     14 The following environment variable can be used to alter the behavior:
     15 * CHROMIUM_NO_HISTORY - If set to 1, a Git checkout with no history will be
     16   downloaded. This is consumes less bandwidth and disk space but is known to be
     17   slower in general if you have a high-speed connection.
     18 
     19 After a successful sync has completed, a .last_sync_chromium file is written to
     20 the chromium directory. While it exists, no more gclient sync operations will be
     21 performed until the --target-revision changes or the SCRIPT_VERSION constant is
     22 incremented. The file can be removed manually to force a new sync.
     23 """
     24 
     25 import argparse
     26 import os
     27 import shutil
     28 import subprocess
     29 import sys
     30 import textwrap
     31 
     32 # Bump this whenever the algorithm changes and you need bots/devs to re-sync,
     33 # ignoring the .last_sync_chromium file
     34 SCRIPT_VERSION = 7
     35 
     36 ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
     37 CHROMIUM_NO_HISTORY = 'CHROMIUM_NO_HISTORY'
     38 
     39 # Duplicated from depot_tools/gclient.py since we cannot depend on that:
     40 DEPS_OS_CHOICES = {
     41   "win32": "win",
     42   "win": "win",
     43   "cygwin": "win",
     44   "darwin": "mac",
     45   "mac": "mac",
     46   "unix": "unix",
     47   "linux": "unix",
     48   "linux2": "unix",
     49   "linux3": "unix",
     50   "android": "android",
     51 }
     52 
     53 def _parse_gclient_dict():
     54   gclient_dict = {}
     55   try:
     56     main_gclient = os.path.join(os.path.dirname(ROOT_DIR), '.gclient')
     57     with open(main_gclient, 'rb') as deps_content:
     58       exec(deps_content, gclient_dict)
     59   except Exception as e:
     60     print >> sys.stderr, 'error while parsing .gclient:', e
     61   return gclient_dict
     62 
     63 
     64 def get_cache_dir():
     65   return _parse_gclient_dict().get('cache_dir')
     66 
     67 
     68 def get_target_os_list():
     69   # Always add the currently running OS since the --deps option will override
     70   # that if specified:
     71   target_os_list = [DEPS_OS_CHOICES.get(sys.platform, 'unix')]
     72   # Add any target_os entries from .gclient.
     73   target_os_list += _parse_gclient_dict().get('target_os', [])
     74   return ','.join(target_os_list)
     75 
     76 
     77 def main():
     78   CR_DIR = os.path.join(ROOT_DIR, 'chromium')
     79 
     80   p = argparse.ArgumentParser()
     81   p.add_argument('--target-revision', required=True,
     82                  help='The target chromium git revision [REQUIRED]')
     83   p.add_argument('--chromium-dir', default=CR_DIR,
     84                  help=('The path to the chromium directory to sync '
     85                        '(default: %(default)r)'))
     86   opts = p.parse_args()
     87   opts.chromium_dir = os.path.abspath(opts.chromium_dir)
     88 
     89   target_os_list = get_target_os_list()
     90 
     91   # Do a quick check to see if we were successful last time to make runhooks
     92   # sooper fast.
     93   flag_file = os.path.join(opts.chromium_dir, '.last_sync_chromium')
     94   flag_file_content = '\n'.join([
     95     str(SCRIPT_VERSION),
     96     opts.target_revision,
     97     repr(target_os_list),
     98   ])
     99   if (os.path.exists(os.path.join(opts.chromium_dir, 'src')) and
    100       os.path.exists(flag_file)):
    101     with open(flag_file, 'r') as f:
    102       if f.read() == flag_file_content:
    103         print 'Chromium already up to date: ', opts.target_revision
    104         return 0
    105     os.unlink(flag_file)
    106 
    107   env = os.environ.copy()
    108 
    109   # Workaround to avoid sync failure due move in
    110   # https://codereview.chromium.org/1155743013
    111   # TODO(kjellander): Remove this after the summer of 2015.
    112   freetype_src = os.path.join(CR_DIR, 'src', 'third_party', 'freetype-android',
    113                               'src')
    114   if os.path.isdir(freetype_src):
    115     shutil.rmtree(freetype_src)
    116 
    117   # Avoid downloading NaCl toolchain as part of the Chromium hooks.
    118   env.setdefault('GYP_DEFINES', '')
    119   env['GYP_DEFINES'] += ' disable_nacl=1'
    120   env['GYP_CHROMIUM_NO_ACTION'] = '1'
    121   gclient_cmd = 'gclient.bat' if sys.platform.startswith('win') else 'gclient'
    122   args = [
    123       gclient_cmd, 'sync', '--force', '--revision', 'src@'+opts.target_revision
    124   ]
    125 
    126   if os.environ.get('CHROME_HEADLESS') == '1':
    127     # Running on a buildbot.
    128     args.append('-vvv')
    129 
    130     if sys.platform.startswith('win'):
    131       cache_path = os.path.join(os.path.splitdrive(ROOT_DIR)[0] + os.path.sep,
    132                                 'b', 'git-cache')
    133     else:
    134       cache_path = '/b/git-cache'
    135   else:
    136     # Verbose, but not as verbose as on the buildbots.
    137     args.append('-v')
    138 
    139     # Support developers setting the cache_dir in .gclient.
    140     cache_path = get_cache_dir()
    141 
    142   # Allow for users with poor internet connections to download a Git clone
    143   # without history (saves several gigs but is generally slower and doesn't work
    144   # with the Git cache).
    145   if os.environ.get(CHROMIUM_NO_HISTORY) == '1':
    146     if cache_path:
    147       print >> sys.stderr, (
    148           'You cannot use "no-history" mode for syncing Chrome (i.e. set the '
    149           '%s environment variable to 1) when you have cache_dir configured in '
    150           'your .gclient.' % CHROMIUM_NO_HISTORY)
    151       return 1
    152     args.append('--no-history')
    153     gclient_entries_file = os.path.join(opts.chromium_dir, '.gclient_entries')
    154   else:
    155     # Write a temporary .gclient file that has the cache_dir variable added.
    156     gclientfile = os.path.join(opts.chromium_dir, '.gclient')
    157     with open(gclientfile, 'rb') as spec:
    158       spec = spec.read().splitlines()
    159       spec[-1] = 'cache_dir = %r' % (cache_path,)
    160     with open(gclientfile + '.tmp', 'wb') as f:
    161       f.write('\n'.join(spec))
    162 
    163     args += [
    164       '--gclientfile', '.gclient.tmp',
    165       '--delete_unversioned_trees', '--reset', '--upstream'
    166     ]
    167     gclient_entries_file = os.path.join(opts.chromium_dir,
    168                                         '.gclient.tmp_entries')
    169 
    170   # To avoid gclient sync problems when DEPS entries have been removed we must
    171   # wipe the gclient's entries file that contains cached URLs for all DEPS.
    172   if os.path.exists(gclient_entries_file):
    173     os.unlink(gclient_entries_file)
    174 
    175   if target_os_list:
    176     args += ['--deps=' + target_os_list]
    177 
    178   print textwrap.dedent("""\
    179   +---------------------------------------------------------------------+
    180   | NOTICE: This sync of Chromium will take a long time as several      |
    181   |         gigabytes of data are downloaded. If this is your initial   |
    182   |         sync and it's interrupted, try running 'gclient sync' again.|
    183   |         If that fails, wipe everything clean and start over again.  |
    184   +---------------------------------------------------------------------+""")
    185   print 'Running "%s" in %s' % (' '.join(args), opts.chromium_dir)
    186   ret = subprocess.call(args, cwd=opts.chromium_dir, env=env)
    187   if ret == 0:
    188     with open(flag_file, 'wb') as f:
    189       f.write(flag_file_content)
    190 
    191   return ret
    192 
    193 
    194 if __name__ == '__main__':
    195   sys.exit(main())
    196