def Sync(revisions=None, force=False, delete_unversioned_trees=False,
         verbose=False, jobs=None, no_hooks=False, extra_args=None):
  """ Update the local checkout using gclient.

  Args:
      revisions: optional list of (branch, revision) tuples indicating which
          projects to sync to which revisions.
      force: whether to run with --force.
      delete_unversioned_trees: whether to run with --delete-unversioned-trees.
      verbose: whether to run with --verbose.
      jobs: optional argument for the --jobs flag.
      no_hooks: whether to run with --nohooks.
      extra_args: optional list; any additional arguments.
  """
  for branch, _ in (revisions or []):
    # Do whatever it takes to get up-to-date with origin/master.
    if os.path.exists(branch):
      with misc.ChDir(branch):
        # First, fix the git identity if needed.
        maybe_fix_identity()

        # If there are local changes, "git checkout" will fail.
        shell_utils.run([GIT, 'reset', '--hard', 'HEAD'])
        # In case HEAD is detached...
        shell_utils.run([GIT, 'checkout', 'master'])
        # Always fetch, in case we're unmanaged.
        shell_utils.run([GIT, 'fetch'])
        # This updates us to origin/master even if master has diverged.
        shell_utils.run([GIT, 'reset', '--hard', 'origin/master'])

  cmd = ['sync', '--no-nag-max']
  if verbose:
    cmd.append('--verbose')
  if force:
    cmd.append('--force')
  if delete_unversioned_trees:
    cmd.append('--delete_unversioned_trees')
  if jobs:
    cmd.append('-j%d' % jobs)
  if no_hooks:
    cmd.append('--nohooks')
  for branch, revision in (revisions or []):
    if revision:
      cmd.extend(['--revision', '%s@%s' % (branch, revision)])
  if extra_args:
    cmd.extend(extra_args)
  output = _RunCmd(cmd)

  # "gclient sync" just downloads all of the commits. In order to actually sync
  # to the desired commit, we have to "git reset" to that commit.
  for branch, revision in (revisions or []):
    with misc.ChDir(branch):
      if revision:
        shell_utils.run([GIT, 'reset', '--hard', revision])
      else:
        shell_utils.run([GIT, 'reset', '--hard', 'origin/master'])
  return output
def Main():
    parser = 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_MASTER,
            chrome_revision=options.chrome_revision or CHROME_REV_MASTER,
            fetch_target=options.fetch_target)
        print 'Chrome synced to %s' % actual_chrome_rev
        print 'Skia synced to %s' % actual_skia_rev
    def _Run(self):
        chrome_path = os.path.join(os.pardir, 'src')
        with misc.ChDir(chrome_path):
            shell_utils.run(
                ['git', 'config', '--local', 'user.name', DEPS_ROLL_NAME])
            shell_utils.run(
                ['git', 'config', '--local', 'user.email', DEPS_ROLL_AUTHOR])

            auto_roll = os.path.join(misc.BUILDBOT_PATH, 'third_party',
                                     'chromium_buildbot_tot', 'scripts',
                                     'tools', 'blink_roller', 'auto_roll.py')

            # python auto_roll.py <project> <author> <path to chromium/src>
            cmd = ['python', auto_roll, 'skia', DEPS_ROLL_AUTHOR, chrome_path]

            exception = None
            try:
                output = shell_utils.run(cmd)
            except shell_utils.CommandFailedException as e:
                output = e.output
                # Suppress failure for "refusing to roll backwards."
                if not re.search(REGEXP_ROLL_TOO_OLD, output):
                    exception = e

        bucket_url = gs_utils.GSUtils.with_gs_prefix(
            skia_vars.GetGlobalVariable('googlestorage_bucket'))

        match = re.search(REGEXP_ISSUE_CREATED, output)
        if match:
            issue = match.group('issue')
            print 'Found issue #', issue
            with open(FILENAME_CURRENT_ATTEMPT, 'w') as f:
                f.write(HTML_CONTENT % (ISSUE_URL_TEMPLATE % {'issue': issue}))
            slave_utils.GSUtilCopyFile(filename=FILENAME_CURRENT_ATTEMPT,
                                       gs_base=bucket_url,
                                       subdir=None,
                                       gs_acl='public-read')

        roll_status = None
        for regexp, status_msg in ROLL_STATUSES:
            match = re.search(regexp, output)
            if match:
                roll_status = status_msg % match.groupdict()
                break

        if roll_status:
            with open(FILENAME_ROLL_STATUS, 'w') as f:
                f.write(roll_status)
            slave_utils.GSUtilCopyFile(filename=FILENAME_ROLL_STATUS,
                                       gs_base=bucket_url,
                                       subdir=None,
                                       gs_acl='public-read')

        #pylint: disable=E0702
        if exception:
            raise exception
Exemple #4
0
  def _Run(self):
    try:
      os.makedirs(ANDROID_CHECKOUT_PATH)
    except OSError:
      pass
    with misc.ChDir(ANDROID_CHECKOUT_PATH):
      if not os.path.exists(REPO):
        # Download repo.
        shell_utils.run(['curl', REPO_URL, '>', REPO])
        shell_utils.run(['chmod', 'a+x', REPO])

      with GitAuthenticate():
        shell_utils.run([REPO, 'init', '-u', ANDROID_REPO_URL, '-g',
                         'all,-notdefault,-darwin', '-b', 'master-skia'])
        shell_utils.run([REPO, 'sync', '-j32'])
Exemple #5
0
def GetCheckedOutHash():
    """ Determine what commit we actually got. If there are local modifications,
  raise an exception. """
    checkout_root, config_dict = _GetLocalConfig()

    # Get the checked-out commit hash for the first gclient solution.
    with misc.ChDir(os.path.join(checkout_root, config_dict[0]['name'])):
        # First, print out the remote from which we synced, just for debugging.
        cmd = [GIT, 'remote', '-v']
        try:
            shell_utils.run(cmd)
        except shell_utils.CommandFailedException as e:
            print e

        # "git rev-parse HEAD" returns the commit hash for HEAD.
        return shell_utils.run([GIT, 'rev-parse', 'HEAD'],
                               log_in_real_time=False).rstrip('\n')
Exemple #6
0
  def _Run(self):
    with misc.ChDir(PATH_TO_SKIA):
      shell_utils.run([GIT, 'config', '--local', 'user.name',
                       SKIA_COMMITTER_NAME])
      shell_utils.run([GIT, 'config', '--local', 'user.email',
                       SKIA_COMMITTER_EMAIL])
      if CHROMIUM_SKIA in shell_utils.run([GIT, 'remote', '-v']):
        shell_utils.run([GIT, 'remote', 'set-url', 'origin', SKIA_GIT_URL,
                         CHROMIUM_SKIA])

      version_file = 'SKP_VERSION'
      skp_version = self._args.get('skp_version')
      with git_utils.GitBranch(branch_name='update_skp_version',
                               commit_msg=COMMIT_MSG % skp_version,
                               commit_queue=not self._is_try):

        # First, upload a version of the CL with just the SKP version changed.
        with open(version_file, 'w') as f:
          f.write(skp_version)
def force_update():
    with misc.ChDir(os.path.join(misc.BUILDBOT_PATH, os.pardir)):
        # Run "gclient" before doing anything else to ensure that we get the
        # necessary stuff installed.
        gclient_utils.GClient()

        # Be sure that we sync to the most recent commit.
        buildbot_revision = None
        try:
            output = git_utils.GetRemoteMasterHash(BUILDBOT_GIT_URL)
            if output:
                buildbot_revision = shlex.split(output)[0]
        except shell_utils.CommandFailedException:
            pass
        if not buildbot_revision:
            buildbot_revision = 'origin/master'

        gclient_utils.Sync(revisions=[('buildbot', buildbot_revision)],
                           verbose=True,
                           force=True)
        got_revision = gclient_utils.GetCheckedOutHash()
        print GOT_REVISION_PATTERN % got_revision

        return gclient_utils.GetCheckedOutHash()
def Sync(skia_revision=SKIA_REV_MASTER,
         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_MASTER).
  chrome_revision: revision of Chrome to sync. Should be a commit hash or one
      of (CHROME_REV_LKGR, CHROME_REV_MASTER).
  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_MASTER:
        output = git_utils.GetRemoteMasterHash(
            skia_vars.GetGlobalVariable('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/master.
    if chrome_revision == CHROME_REV_LKGR:
        chrome_revision = urllib2.urlopen(CHROME_LKGR_URL).read()
    elif chrome_revision == CHROME_REV_MASTER:
        chrome_revision = shlex.split(
            git_utils.GetRemoteMasterHash(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([GIT, 'rev-parse', 'HEAD'],
                                        log_in_real_time=False).rstrip()

    # Find the actually-obtained Skia revision.
    with misc.ChDir(os.path.join('third_party', 'skia')):
        actual_skia_rev = shell_utils.run([GIT, 'rev-parse', 'HEAD'],
                                          log_in_real_time=False).rstrip()

    # 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([GIT, 'submodule', 'foreach', submodule_cmd]),
                        shell=True)

    # Verify that we got the requested revisions of Chrome and Skia.
    if skia_revision != actual_skia_rev and skia_revision != SKIA_REV_DEPS:
        raise Exception('Requested Skia revision %s but got %s!' %
                        (repr(skia_revision), repr(actual_skia_rev)))
    if chrome_revision and chrome_revision != actual_chrome_rev:
        raise Exception('Requested Chrome revision %s but got %s!' %
                        (repr(chrome_revision), repr(actual_chrome_rev)))

    return (actual_skia_rev, actual_chrome_rev)
Exemple #9
0
 def _Run(self):
   with misc.ChDir(misc.BUILDBOT_PATH):
     shell_utils.run(['python', 'run_unittests'])
Exemple #10
0
    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
    def _Run(self):
        with misc.ChDir(EXTERNAL_SKIA):
            # Check to see whether there is an upstream yet.
            if not UPSTREAM_REMOTE_NAME in shell_utils.run(
                [GIT, 'remote', 'show']):
                try:
                    shell_utils.run([
                        GIT, 'remote', 'add', UPSTREAM_REMOTE_NAME,
                        SKIA_REPO_URL
                    ])
                except shell_utils.CommandFailedException as e:
                    if 'remote %s already exists' % UPSTREAM_REMOTE_NAME in e.output:
                        # Accept this error. The upstream remote name should have been in
                        # the output of git remote show, which would have made us skip this
                        # redundant command anyway.
                        print(
                            '%s was already added. Why did it not show in git remote'
                            ' show?' % UPSTREAM_REMOTE_NAME)
                    else:
                        raise e

            # Update the upstream remote.
            shell_utils.run([GIT, 'fetch', UPSTREAM_REMOTE_NAME])

            # Create a stack of commits to submit, one at a time, until we reach a
            # commit that has already been merged.
            commit_stack = []
            head = git_utils.ShortHash('HEAD')

            print 'HEAD is at %s' % head

            if self._got_revision:
                # Merge the revision that started this build.
                commit = git_utils.ShortHash(self._got_revision)
            else:
                raise Exception('This build has no _got_revision to merge!')

            print(
                'Starting with %s, look for commits that have not been merged to '
                'HEAD' % commit)
            while not git_utils.AIsAncestorOfB(commit, head):
                print 'Adding %s to list of commits to merge.' % commit
                commit_stack.append(commit)
                if git_utils.IsMerge(commit):
                    # Skia's commit history is not linear. There is no obvious way to
                    # merge each branch in, one commit at a time. So just start with the
                    # merge commit.
                    print '%s is a merge. Skipping merge of its parents.' % commit
                    break
                commit = git_utils.ShortHash(commit + '~1')
            else:
                print '%s has already been merged.' % commit

            if len(commit_stack) == 0:
                raise BuildStepWarning(
                    'Nothing to merge; did someone already merge %s?'
                    ' Exiting.' % commit)

            print 'Merging %s commit(s):\n%s' % (len(commit_stack), '\n'.join(
                reversed(commit_stack)))

            # Now we have a list of commits to merge.
            while len(commit_stack) > 0:
                commit_to_merge = commit_stack.pop()

                print 'Attempting to merge ' + commit_to_merge

                # Start the merge.
                try:
                    shell_utils.run(
                        [GIT, 'merge', commit_to_merge, '--no-commit'])
                except shell_utils.CommandFailedException:
                    # Merge conflict. There may be a more elegant solution, but for now,
                    # undo the merge, and allow (/make) a human to do it.
                    git_utils.MergeAbort()
                    raise Exception(
                        'Failed to merge %s. Fall back to manual human '
                        'merge.' % commit_to_merge)

                # Grab the upstream version of SkUserConfig, which will be used to
                # generate Android's version.
                shell_utils.run([
                    GIT, 'checkout', commit_to_merge, '--',
                    UPSTREAM_USER_CONFIG
                ])

                # We don't want to commit the upstream version, so remove it from the
                # index.
                shell_utils.run([GIT, 'reset', 'HEAD', UPSTREAM_USER_CONFIG])

                # Now generate Android.mk and SkUserConfig.h
                gyp_failed = False
                try:
                    gyp_to_android.main()
                except AssertionError as e:
                    print e
                    # Failed to generate the makefiles. Make a human fix the problem.
                    git_utils.MergeAbort()
                    raise Exception(
                        'Failed to generate makefiles for %s. Fall back to '
                        'manual human merge.' % commit_to_merge)
                except SystemExit as e:
                    gyp_failed = True

                if not gyp_failed:
                    git_utils.Add('Android.mk')
                    git_utils.Add(ANDROID_USER_CONFIG)
                    git_utils.Add(os.path.join('tests', 'Android.mk'))
                    git_utils.Add(os.path.join('tools', 'Android.mk'))
                    git_utils.Add(os.path.join('bench', 'Android.mk'))
                    git_utils.Add(os.path.join('gm', 'Android.mk'))
                    git_utils.Add(os.path.join('dm', 'Android.mk'))

                # Remove upstream user config, which is no longer needed.
                os.remove(UPSTREAM_USER_CONFIG)

                # Create a new branch.
                shell_utils.run([REPO, 'start', LOCAL_BRANCH_NAME, '.'])

                try:
                    orig_msg = shell_utils.run(
                        [GIT, 'show', commit_to_merge, '--format="%s"',
                         '-s']).rstrip()
                    message = 'Merge %s into master-skia\n\n' + SKIA_REV_URL
                    if gyp_failed:
                        message += '\n\nFIXME: Failed to generate makefiles!'
                    shell_utils.run([
                        GIT, 'commit', '-m',
                        message % (orig_msg, commit_to_merge)
                    ])
                except shell_utils.CommandFailedException:
                    # It is possible that someone else already did the merge (for example,
                    # if they are testing a build slave). Clean up and exit.
                    RepoAbandon(LOCAL_BRANCH_NAME)
                    raise BuildStepWarning(
                        'Nothing to merge; did someone already merge '
                        '%s?' % commit_to_merge)

                # For some reason, sometimes the bot's authentication from sync_android
                # does not carry over to this step. Authenticate again.
                with GitAuthenticate():
                    # Now push to master-skia branch
                    try:
                        shell_utils.run(
                            [GIT, 'push', MASTER_SKIA_URL, MASTER_SKIA_REFS])
                    except shell_utils.CommandFailedException:
                        # It's possible someone submitted in between our sync and push or
                        # push failed for some other reason. Abandon and let the next
                        # attempt try again.
                        RepoAbandon(LOCAL_BRANCH_NAME)
                        raise BuildStepFailure('git push failed!')

                    # Our branch is no longer needed. Remove it.
                    shell_utils.run([REPO, 'sync', '-j32', '.'])
                    shell_utils.run([REPO, 'prune', '.'])

                # If gyp failed, this probably means there was an error in the gyp
                # files. We still want to push the commit. This way, when it gets
                # fixed with a future commit, we don't remain hung up on this one.
                if gyp_failed:
                    raise BuildStepFailure(
                        'Merged %s, but failed to generate makefiles.'
                        ' Is there a mistake in the gyp files?' %
                        commit_to_merge)