blob: 46436cbc7e008dae02351bbfb35cfa5cf2fdff01 [file] [log] [blame]
# Copyright (c) 2014 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.
import base64
import json
import os
import re
import time
import urllib2
from common import utils
_THIS_DIR = os.path.abspath(os.path.dirname(__file__))
CONFIG = json.loads(open(os.path.join(_THIS_DIR,
'deps_config.json'), 'r').read())
OLD_GIT_URL_PATTERN = re.compile(r'https?://git.chromium.org/(.*)')
class _VarImpl(object):
def __init__(self, local_scope):
self._local_scope = local_scope
def Lookup(self, var_name):
if var_name in self._local_scope.get('vars', {}):
return self._local_scope['vars'][var_name]
raise Exception('Var is not defined: %s' % var_name)
def _ParseDEPS(content):
"""Parse the DEPS file of chromium."""
local_scope = {}
var = _VarImpl(local_scope)
global_scope = {
'Var': var.Lookup,
'deps': {},
'deps_os': {},
'include_rules': [],
'skip_child_includes': [],
'hooks': [],
}
exec(content, global_scope, local_scope)
local_scope.setdefault('deps', {})
local_scope.setdefault('deps_os', {})
return (local_scope['deps'], local_scope['deps_os'])
def _GetComponentName(path, host_dirs):
"""Return the component name of a path."""
components_renamed = {
'webkit': 'blink',
}
for host_dir in host_dirs:
if path.startswith(host_dir):
path = path[len(host_dir):]
name = path.split('/')[0].lower()
if name in components_renamed:
return components_renamed[name].lower()
else:
return name.lower()
# Unknown path, return the whole path as component name.
return '_'.join(path.split('/'))
def _GetContentOfDEPS(revision):
chromium_git_file_url_template = CONFIG['chromium_git_file_url']
# Try .DEPS.git first, because before migration from SVN to GIT, the .DEPS.git
# has the dependency in GIT repo while DEPS has dependency in SVN repo.
url = chromium_git_file_url_template % (revision, '.DEPS.git')
http_status_code, content = utils.GetHttpClient().Get(
url, retries=5, retry_if_not=404)
# If .DEPS.git is not found, use DEPS, assuming it is a commit after migration
# from SVN to GIT.
if http_status_code == 404:
url = chromium_git_file_url_template % (revision, 'DEPS')
http_status_code, content = utils.GetHttpClient().Get(url, retries=5)
if http_status_code == 200:
return base64.b64decode(content)
else:
return ''
def GetChromiumComponents(chromium_revision,
os_platform='unix',
deps_file_downloader=_GetContentOfDEPS):
"""Return a list of components used by Chrome of the given revision.
Args:
chromium_revision: Revision of the Chrome build: svn revision, or git hash.
os_platform: The target platform of the Chrome build, eg. win, mac, etc.
deps_file_downloader: A function that takes the chromium_revision as input,
and returns the content of the DEPS file. The returned
content is assumed to be trusted input and will be
evaluated as python code.
Returns:
A map from component path to parsed component name, repository URL,
repository type and revision.
Return None if an error occurs.
"""
if os_platform.lower() == 'linux':
os_platform = 'unix'
chromium_git_base_url = CONFIG['chromium_git_base_url']
if not utils.IsGitHash(chromium_revision):
# Convert svn revision or commit position to Git hash.
cr_rev_url_template = CONFIG['cr_rev_url']
url = cr_rev_url_template % chromium_revision
status_code, content = utils.GetHttpClient().Get(
url, timeout=120, retries=5, retry_if_not=404)
if status_code != 200 or not content:
if status_code == 404:
print 'Chromium commit position %s is not found.' % chromium_revision
return None
cr_rev_data = json.loads(content)
if 'git_sha' not in cr_rev_data:
return None
if 'repo' not in cr_rev_data or cr_rev_data['repo'] != 'chromium/src':
print ('%s seems like a commit position of "%s", but not "chromium/src".'
% (chromium_revision, cr_rev_data['repo']))
return None
chromium_revision = cr_rev_data.get('git_sha')
if not chromium_revision:
return None
# Download the content of DEPS file in chromium.
deps_content = deps_file_downloader(chromium_revision)
if not deps_content:
return None
all_deps = {}
# Parse the content of DEPS file.
deps, deps_os = _ParseDEPS(deps_content)
all_deps.update(deps)
if os_platform is not None:
all_deps.update(deps_os.get(os_platform, {}))
# Figure out components based on the dependencies.
components = {}
host_dirs = CONFIG['host_directories']
for component_path, component_repo_url in all_deps.iteritems():
if component_repo_url is None:
# For some platform like iso, some component is ignored.
continue
name = _GetComponentName(component_path, host_dirs)
repository, revision = component_repo_url.split('@')
match = OLD_GIT_URL_PATTERN.match(repository)
if match:
repository = 'https://chromium.googlesource.com/%s' % match.group(1)
is_git_hash = utils.IsGitHash(revision)
if is_git_hash:
repository_type = 'git'
else:
repository_type = 'svn'
if not component_path.endswith('/'):
component_path += '/'
components[component_path] = {
'path': component_path,
'name': name,
'repository': repository,
'repository_type': repository_type,
'revision': revision
}
# Add chromium as a component.
components['src/'] = {
'path': 'src/',
'name': 'chromium',
'repository': chromium_git_base_url,
'repository_type': 'git',
'revision': chromium_revision
}
return components
def GetChromiumComponentRange(old_revision,
new_revision,
os_platform='unix',
deps_file_downloader=_GetContentOfDEPS):
"""Return a list of components with their revision ranges.
Args:
old_revision: The old revision of a Chrome build.
new_revision: The new revision of a Chrome build.
os_platform: The target platform of the Chrome build, eg. win, mac, etc.
deps_file_downloader: A function that takes the chromium_revision as input,
and returns the content of the DEPS file. The returned
content is assumed to be trusted input and will be
evaluated as python code.
Returns:
A map from component path to its parsed regression and other information.
Return None if an error occurs.
"""
old_components = GetChromiumComponents(old_revision, os_platform,
deps_file_downloader)
if not old_components:
return None
new_components = GetChromiumComponents(new_revision, os_platform,
deps_file_downloader)
if not new_components:
return None
components = {}
for path in new_components:
new_component = new_components[path]
old_revision = None
if path in old_components:
old_component = old_components[path]
old_revision = old_component['revision']
components[path] = {
'path': path,
'rolled': new_component['revision'] != old_revision,
'name': new_component['name'],
'old_revision': old_revision,
'new_revision': new_component['revision'],
'repository': new_component['repository'],
'repository_type': new_component['repository_type']
}
return components