blob: 2387e278d3aafd92b7dfe4b2ca45de0e1ef2480d [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2017 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.
"""Tool to help developers rebase branches across the Blink rename."""
import argparse
import json
import os
import subprocess
import shutil
import sys
import tempfile
class _DepotToolsNotFoundException(Exception):
pass
def _whereis(name):
"""Find and return the first entry in $PATH containing a file named |name|.
Returns the path if found; otherwise returns nothing.
"""
for path in os.environ['PATH'].split(os.pathsep):
if os.path.exists(os.path.join(path, name)):
return path
def _find_depot_tools():
"""Attempts to configure and return a wrapper for invoking depot tools.
Returns:
A helper object for invoking depot tools.
Raises:
_DepotToolsNotFoundException: An error occurred trying to find depot tools.
"""
class DepotToolsWrapper(object):
def __init__(self, path):
self.__download_from_google_storage = os.path.join(
path, 'download_from_google_storage.py')
self.__gsutil = os.path.join(path, 'gsutil.py')
def call_download_from_google_storage(self, *args):
"""Runs download_from_google_storage with the given args."""
subprocess.check_call(['python', self.__download_from_google_storage] +
list(args))
def call_gsutil(self, *args):
"""Runs gsutil with the given args."""
subprocess.check_call(['python', self.__gsutil] + list(args))
# Attempt to find download_from_google_storage.py from depot_tools
path = _whereis('download_from_google_storage.py')
if not path:
raise _DepotToolsNotFoundException(
'download_from_google_storage.py not found. Make sure depot_tools is '
'in $PATH.')
# Make sure gsutil.py is in the same location
path2 = _whereis('download_from_google_storage.py')
if not path2:
raise _DepotToolsNotFoundException(
'gsutil.py not found. Make sure depot_tools is in $PATH.')
if path != path2:
raise _DepotToolsNotFoundException(
'download_from_google_storage.py found in %s but gsutil.py found in %s.'
% (path, path2))
return DepotToolsWrapper(path)
class Bootstrapper(object):
"""Helper class for bootstrapping startup of the rebase helper.
Performs update checks and stages any required binaries."""
def __init__(self, depot_tools, components_manifest_name):
"""Bootstrapper constructor.
Args:
depot_tools: a wrapper for invoking depot_tools.
components_manifest_name: The name of the components manifest.
"""
self.__depot_tools = depot_tools
self.__components_manifest_name = components_manifest_name
self.__tmpdir = None
def __enter__(self):
self.__tmpdir = tempfile.mkdtemp()
return self
def __exit__(self, exc_type, exc_value, traceback):
shutil.rmtree(self.__tmpdir, ignore_errors=True)
def update(self):
"""Performs an update check for various components."""
components = self._get_latest_components()
for name, sha1_hash in components.iteritems():
args = [
'--no_auth', '--no_resume', '-b', 'chromium-blink-rename',
'--extract', sha1_hash
]
if '-' in name:
name, platform = name.split('-', 1)
args.append('-p')
args.append(platform)
args.append('-o')
args.append(os.path.join('staging', '%s.tar.gz' % name))
self.__depot_tools.call_download_from_google_storage(*args)
def _get_latest_components(self):
"""Fetches info about the latest components from google storage.
The return value should be a dict of component names to SHA1 hashes."""
components_path = os.path.join(self.__tmpdir, 'COMPONENTS')
self.__depot_tools.call_gsutil(
'cp', 'gs://chromium-blink-rename/%s' % self.__components_manifest_name,
components_path)
with open(components_path) as f:
return json.loads(f.read())
def main():
# Intentionally suppress help. These are internal testing flags.
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('--components-manifest-name', default='COMPONENTS')
parser.add_argument('--pylib-path')
args, remaining_argv = parser.parse_known_args()
script_dir = os.path.dirname(os.path.realpath(__file__))
os.chdir(script_dir)
try:
depot_tools = _find_depot_tools()
except _DepotToolsNotFoundException as e:
print e.message
return 1
print 'Checking for updates...'
with Bootstrapper(depot_tools, args.components_manifest_name) as bootstrapper:
bootstrapper.update()
# Import stage 2 and launch it.
tool_pylib = args.pylib_path
if not tool_pylib:
tool_pylib = os.path.abspath(os.path.join(script_dir, 'staging/pylib'))
sys.path.insert(0, tool_pylib)
from blink_rename_merge_helper import driver
# Note: for compatibility with older versions of run.py, set sys.argv to the
# unconsumed args.
sys.argv = sys.argv[:1] + remaining_argv
driver.run()
if __name__ == '__main__':
sys.exit(main())