| #!/usr/bin/env python |
| # Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """ Create (if needed) and sync a nested checkout of Skia inside of Chrome. """ |
| |
| import optparse |
| import os |
| import re |
| import shlex |
| import sys |
| from urllib.request import urlopen |
| |
| import gclient_utils |
| import misc |
| import shell_utils |
| |
| |
| CHROME_GIT_URL = 'https://chromium.googlesource.com/chromium/src.git' |
| CHROME_LKGR_URL = 'http://chromium-status.appspot.com/git-lkgr' |
| FETCH = 'fetch.bat' if os.name == 'nt' else 'fetch' |
| GCLIENT = 'gclient.bat' if os.name == 'nt' else 'gclient' |
| GCLIENT_FILE = '.gclient' |
| PATH_TO_SKIA_IN_CHROME = os.path.join('src', 'third_party', 'skia', 'src') |
| DEFAULT_FETCH_TARGET = 'chromium' |
| |
| # Sync Chrome to LKGR. |
| CHROME_REV_LKGR = 'CHROME_REV_LKGR' |
| # Sync Chrome to origin/main. |
| CHROME_REV_MAIN = 'CHROME_REV_MAIN' |
| |
| # Skia repo URL. |
| SKIA_GIT_URL = 'https://skia.googlesource.com/skia.git' |
| # Code revision specified by DEPS. |
| SKIA_REV_DEPS = 'SKIA_REV_DEPS' |
| # Sync to origin/main. |
| SKIA_REV_MAIN = 'SKIA_REV_MAIN' |
| |
| |
| def GetRemoteMainHash(git_url): |
| return shell_utils.run(['git', 'ls-remote', git_url, '--verify', |
| 'refs/heads/main']).rstrip() |
| |
| |
| def GetDepsVar(deps_filepath, variable): |
| """Read the given DEPS file and return the value of the given variable. |
| |
| Args: |
| deps_filepath: string; path to a DEPS file. |
| variable: string; name of the variable whose value should be returned. |
| Returns: |
| string; value of the requested variable. |
| """ |
| deps_vars = {} |
| deps_vars['Var'] = lambda x: deps_vars['vars'][x] |
| execfile(deps_filepath, deps_vars) |
| return deps_vars['vars'][variable] |
| |
| |
| def Sync(skia_revision=SKIA_REV_DEPS, chrome_revision=CHROME_REV_LKGR, |
| fetch_target=DEFAULT_FETCH_TARGET, |
| gyp_defines=None, gyp_generators=None): |
| """ Create and sync a checkout of Skia inside a checkout of Chrome. Returns |
| a tuple containing the actually-obtained revision of Skia and the actually- |
| obtained revision of Chrome. |
| |
| skia_revision: revision of Skia to sync. Should be a commit hash or one of |
| (SKIA_REV_DEPS, SKIA_REV_MAIN). |
| chrome_revision: revision of Chrome to sync. Should be a commit hash or one |
| of (CHROME_REV_LKGR, CHROME_REV_MAIN). |
| fetch_target: string; Calls the fetch tool in depot_tools with the specified |
| argument. Default is DEFAULT_FETCH_TARGET. |
| gyp_defines: optional string; GYP_DEFINES to be passed to Gyp. |
| gyp_generators: optional string; which GYP_GENERATORS to use. |
| """ |
| # Figure out what revision of Skia we should use. |
| if skia_revision == SKIA_REV_MAIN: |
| output = GetRemoteMainHash(SKIA_GIT_URL) |
| if output: |
| skia_revision = shlex.split(output)[0] |
| if not skia_revision: |
| raise Exception('Could not determine current Skia revision!') |
| skia_revision = str(skia_revision) |
| |
| # Use Chrome LKGR, since gclient_utils will force a sync to origin/main. |
| if chrome_revision == CHROME_REV_LKGR: |
| chrome_revision = urlopen(CHROME_LKGR_URL).read() |
| elif chrome_revision == CHROME_REV_MAIN: |
| chrome_revision = shlex.split( |
| GetRemoteMainHash(CHROME_GIT_URL))[0] |
| |
| # Run "fetch chromium". The initial run is allowed to fail after it does some |
| # work. At the least, we expect the .gclient file to be present when it |
| # finishes. |
| if not os.path.isfile(GCLIENT_FILE): |
| try: |
| shell_utils.run([FETCH, fetch_target, '--nosvn=True']) |
| except shell_utils.CommandFailedException: |
| pass |
| if not os.path.isfile(GCLIENT_FILE): |
| raise Exception('Could not fetch %s!' % fetch_target) |
| |
| # Run "gclient sync" |
| revisions = [('src', chrome_revision)] |
| if skia_revision != SKIA_REV_DEPS: |
| revisions.append(('src/third_party/skia', skia_revision)) |
| |
| try: |
| # Hack: We have to set some GYP_DEFINES, or upstream scripts will complain. |
| os.environ['GYP_DEFINES'] = os.environ.get('GYP_DEFINES') or '' |
| gclient_utils.Sync( |
| revisions=revisions, |
| jobs=1, |
| no_hooks=True, |
| force=True) |
| except shell_utils.CommandFailedException as e: |
| # We frequently see sync failures because a lock file wasn't deleted. In |
| # that case, delete the lock file and try again. |
| pattern = r".*fatal: Unable to create '(\S+)': File exists\..*" |
| match = re.search(pattern, e.output) |
| if not match: |
| raise e |
| file_to_delete = match.groups()[0] |
| try: |
| print('Attempting to remove %s' % file_to_delete) |
| os.remove(file_to_delete) |
| except OSError: |
| # If the file no longer exists, just try again. |
| pass |
| gclient_utils.Sync( |
| revisions=revisions, |
| jobs=1, |
| no_hooks=True, |
| force=True) |
| |
| # Find the actually-obtained Chrome revision. |
| os.chdir('src') |
| actual_chrome_rev = shell_utils.run([gclient_utils.GIT, 'rev-parse', 'HEAD'], |
| log_in_real_time=False).rstrip().decode() |
| |
| |
| # Find the actually-obtained Skia revision. |
| with misc.ChDir(os.path.join('third_party', 'skia')): |
| actual_skia_rev = shell_utils.run([gclient_utils.GIT, 'rev-parse', 'HEAD'], |
| log_in_real_time=False).rstrip().decode() |
| |
| # Run gclient hooks |
| gclient_utils.RunHooks(gyp_defines=gyp_defines, gyp_generators=gyp_generators) |
| |
| # Fix the submodules so that they don't show up in "git status" |
| # This fails on Windows... |
| if os.name != 'nt': |
| submodule_cmd = ('\'git config -f ' |
| '$toplevel/.git/config submodule.$name.ignore all\'') |
| shell_utils.run( |
| ' '.join([gclient_utils.GIT, 'submodule', 'foreach', submodule_cmd]), |
| shell=True) |
| |
| # Verify that we got the requested revisions of Chrome and Skia. |
| if (skia_revision != actual_skia_rev[:len(skia_revision)] and |
| skia_revision != SKIA_REV_DEPS): |
| raise Exception('Requested Skia revision %s but got %s!' % ( |
| skia_revision, actual_skia_rev)) |
| if (chrome_revision and |
| chrome_revision != actual_chrome_rev[:len(chrome_revision)]): |
| raise Exception('Requested Chrome revision %s but got %s!' % ( |
| chrome_revision, actual_chrome_rev)) |
| |
| return (actual_skia_rev, actual_chrome_rev) |
| |
| |
| def Main(): |
| parser = optparse.OptionParser() |
| parser.add_option('--skia_revision', |
| help=('Desired revision of Skia. Defaults to the most ' |
| 'recent revision.')) |
| parser.add_option('--chrome_revision', |
| help=('Desired revision of Chrome. Defaults to the most ' |
| 'recent revision.')) |
| parser.add_option('--destination', |
| help=('Where to sync the code. Defaults to the current ' |
| 'directory.'), |
| default=os.curdir) |
| parser.add_option('--fetch_target', |
| help=('Calls the fetch tool in depot_tools with the ' |
| 'specified target.'), |
| default=DEFAULT_FETCH_TARGET) |
| (options, _) = parser.parse_args() |
| dest_dir = os.path.abspath(options.destination) |
| with misc.ChDir(dest_dir): |
| actual_skia_rev, actual_chrome_rev = Sync( |
| skia_revision=options.skia_revision or SKIA_REV_DEPS, |
| chrome_revision=options.chrome_revision or CHROME_REV_MAIN, |
| fetch_target=options.fetch_target) |
| print('Chrome synced to %s' % actual_chrome_rev) |
| print('Skia synced to %s' % actual_skia_rev) |
| |
| |
| if __name__ == '__main__': |
| sys.exit(Main()) |