blob: d248a5d5ca3f227cacd6844beb680742bac35bc0 [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) 2012 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.
""" Check out the Skia sources. """
from build_step import BuildStep, BuildStepFailure
from common import chromium_utils
from py.utils.git_utils import GIT
from utils import file_utils
from utils import gclient_utils
from py.utils import misc
from py.utils import shell_utils
import ast
import config_private
import os
import re
import sys
LOCAL_GIT_MIRROR_URL = 'http://192.168.1.120/git-mirror/skia'
SKIA_GIT_URL_TO_REPLACE = config_private.SKIA_GIT_URL[:-len('.git')]
def _MaybeUseSkiaLabMirror(revision=None):
"""If the SkiaLab mirror is reachable, set the gitconfig to use that instead
of the remote repo.
Args:
revision: optional string; commit hash to which we're syncing. This is a
safety net; in the case that the mirror does not yet have this commit,
we will use the remote repo instead.
"""
# Attempt to reach the SkiaLab git mirror.
mirror_is_accessible = False
print 'Attempting to reach the SkiaLab git mirror...'
try:
shell_utils.run([GIT, 'ls-remote',
LOCAL_GIT_MIRROR_URL + '.git',
revision or 'HEAD', '--exit-code'], timeout=10)
mirror_is_accessible = True
except (shell_utils.CommandFailedException, shell_utils.TimeoutException):
pass
# Find the global git config entries and loop over them, removing the ones
# which aren't needed and adding a URL override for the git mirror if it is
# accessible and not already present.
try:
configs = shell_utils.run([GIT, 'config', '--global',
'--list']).splitlines()
except shell_utils.CommandFailedException:
configs = []
already_overriding_url = False
for config in configs:
override_url = None
match = re.match('url.(.+).insteadof=', config)
if match:
override_url = match.groups()[0]
if override_url:
if override_url == LOCAL_GIT_MIRROR_URL and mirror_is_accessible:
print 'Already have URL override for SkiaLab git mirror.'
already_overriding_url = True
else:
print 'Removing unneeded URL override for %s' % override_url
try:
shell_utils.run([GIT, 'config', '--global',
'--remove-section', config.split('.insteadof')[0]])
except shell_utils.CommandFailedException as e:
if 'No such section!' in e.output:
print '"insteadof" section already removed; continuing...'
else:
raise
if mirror_is_accessible and not already_overriding_url:
print ('SkiaLab git mirror appears to be accessible. Changing gitconfig to '
'use the mirror.')
shell_utils.run([GIT, 'config', '--global',
'url.%s.insteadOf' % LOCAL_GIT_MIRROR_URL,
SKIA_GIT_URL_TO_REPLACE])
# Some debugging info that might help us figure things out...
try:
shell_utils.run([GIT, 'config', '--global', '--list'])
except shell_utils.CommandFailedException:
pass
class Update(BuildStep):
def __init__(self, timeout=10000, no_output_timeout=6000, attempts=5,
**kwargs):
super(Update, self).__init__(timeout=timeout,
no_output_timeout=no_output_timeout,
attempts=attempts,
**kwargs)
def _Run(self):
# Run "gclient" before doing anything else to ensure that we get the
# necessary stuff installed.
gclient_utils.GClient()
_MaybeUseSkiaLabMirror(self._revision)
# We receive gclient_solutions as a list of dictionaries flattened into a
# double-quoted string. This invocation of literal_eval converts that string
# into a list of strings.
solutions = ast.literal_eval(self._args['gclient_solutions'][1:-1])
# TODO(borenet): Move the gclient solutions parsing logic into a function.
# Parse each solution dictionary from a string and add it to a list, while
# building a string to pass as a spec to gclient, to indicate which
# branches should be downloaded.
solution_dicts = []
gclient_spec = 'solutions = ['
for solution in solutions:
gclient_spec += solution
solution_dicts += ast.literal_eval(solution)
gclient_spec += ']'
# Set the DEPS target_os if necessary.
if self._deps_target_os:
gclient_spec += '\ntarget_os = ["%s"]' % self._deps_target_os
# Run "gclient config" with the spec we just built.
gclient_utils.Config(spec=gclient_spec)
revisions = []
for solution in solution_dicts:
if solution['name'] == gclient_utils.SKIA_TRUNK:
revisions.append((solution['name'], self._revision))
else:
url_split = solution['url'].split('@')
if len(url_split) > 1:
revision = url_split[1]
revisions.append((solution['name'], revision))
try:
if self._is_try:
# Clean our checkout to make sure we don't have a patch left over.
if (os.path.isdir('skia') and
os.path.isdir(os.path.join('skia', '.git'))):
with misc.ChDir('skia'):
gclient_utils.Revert()
# Run "gclient sync"
gclient_utils.Sync(
revisions=revisions,
verbose=True,
force=True,
delete_unversioned_trees=True)
got_revision = gclient_utils.GetCheckedOutHash()
except Exception:
# If the sync fails, clear the checkout and try again.
print 'Initial sync failed.'
# Attempt to remove the skia directory first.
if os.path.isdir('skia'):
print 'Removing "skia"'
chromium_utils.RemoveDirectory('skia')
# Now, remove *everything* in the build directory.
build_dir = os.path.abspath(os.curdir)
with misc.ChDir(os.pardir):
print 'Attempting to clear %s' % build_dir
file_utils.clear_directory(build_dir)
# Try to sync again.
print 'Attempting to sync again.'
gclient_utils.Config(spec=gclient_spec)
gclient_utils.Sync(
revisions=revisions,
verbose=True,
force=True,
delete_unversioned_trees=True,
jobs=1)
got_revision = gclient_utils.GetCheckedOutHash()
# If the revision we actually got differs from what was requested, raise an
# exception.
if self._revision and got_revision != self._revision:
raise BuildStepFailure('Actually-synced revision "%s" is different from '
'the requested revision "%s".' % (
repr(got_revision), repr(self._revision)))
# Print the obtained revision number so that the master can parse it.
print 'Skia updated to %s' % got_revision
if '__main__' == __name__:
sys.exit(BuildStep.RunBuildStep(Update))