| # Copyright 2016 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. |
| |
| from recipe_engine import config_types |
| from recipe_engine import recipe_api |
| |
| COMMIT_MESSAGE = """Update submodule references. |
| |
| This is an artificial commit to make dependencies specified in the DEPS file |
| visible to Codesearch. |
| This commit does not exist in the underlying repository.""" |
| |
| |
| def Humanish(url): |
| if url.endswith('.git'): # pragma: nocover |
| url = url[:-4] |
| slash = url.rfind('/') |
| if slash != -1: |
| url = url[slash + 1:] |
| return url |
| |
| |
| class SyncSubmodulesApi(recipe_api.RecipeApi): |
| def __call__(self, source, source_repo_checkout_name, |
| dest, source_ref='refs/heads/master', |
| dest_ref='refs/heads/master', extra_submodules=None, |
| deps_path_prefix=None, |
| disable_path_prefix=False): |
| """ |
| Args: |
| source: URL of the git repository to mirror. |
| source_repo_checkout_name: Name of the directory that the source repo |
| should be checked out into. |
| dest: URL of the git repository to push to. |
| source_ref: git ref in the source repository to checkout. |
| dest_ref: git ref in the destination repository to push to. |
| extra_submodules: a list of "path=URL" strings. These are added as extra |
| submodules. |
| deps_path_prefix: path prefix used to filter out DEPS. DEPS with the |
| prefix are included. |
| disable_path_prefix: disable filtering out DEPS by path prefix. |
| """ |
| |
| if extra_submodules is None: # pragma: nocover |
| extra_submodules = [] |
| |
| if source_repo_checkout_name is None: |
| solution_name = Humanish(source) |
| else: |
| solution_name = source_repo_checkout_name |
| |
| if deps_path_prefix is None: |
| deps_path_prefix = '%s/' % solution_name |
| |
| sanitized_buildername = ''.join( |
| c if c.isalnum() else '_' |
| for c in self.m.buildbucket.builder_name |
| ) |
| checkout_dir = self.m.path['cache'].join(sanitized_buildername) |
| self.m.file.ensure_directory('makedirs checkout', checkout_dir) |
| self.m.path['checkout'] = checkout_dir |
| |
| # Populate the git cache, get the path to the mirror. |
| git_cache = self.m.infra_paths.default_git_cache_dir |
| |
| with self.m.context(cwd=checkout_dir): |
| # Retrieve/refresh the source solution. |
| self.m.gclient.use_mirror = True |
| src_cfg = self.m.gclient.make_config(CACHE_DIR=git_cache) |
| # Target every OS. This enables us to check out most of the conditional |
| # dependencies in the DEPS file so they can be shown in Code Search. |
| # TODO(crbug.com/860379): Remove this once we can tell gclient to evaluate |
| # all dependencies regardless of conditions. |
| src_cfg.target_os = [ |
| 'android', 'chromeos', 'fuchsia', 'ios', 'unix', 'mac', 'win'] |
| soln = src_cfg.solutions.add() |
| soln.name = solution_name |
| soln.url = source |
| self.m.gclient.c = src_cfg |
| self.m.bot_update.ensure_checkout() |
| |
| revinfo_params = ['revinfo', '--output-json', self.m.json.output(), |
| '--ignore-dep-type=cipd'] |
| revinfo_step = self.m.gclient('get revinfo', revinfo_params) |
| |
| # Checkout the gitlink overlay repository. |
| overlay_repo_dir = self.m.path['start_dir'].join('overlay') |
| self.m.git.checkout( |
| dest, ref='master', dir_path=overlay_repo_dir, submodules=False) |
| |
| # Create submodule references. |
| deps2submodules_cmd = [ |
| 'python', |
| self.resource('deps2submodules.py'), |
| '--path-prefix', deps_path_prefix, |
| self.m.json.input(revinfo_step.json.output), |
| ] |
| if disable_path_prefix: |
| deps2submodules_cmd.append('--disable-path-prefix') |
| for extra_submodule in extra_submodules: |
| deps2submodules_cmd.extend(['--extra-submodule', extra_submodule]) |
| with self.m.context(cwd=overlay_repo_dir): |
| self.m.step('deps2submodules', deps2submodules_cmd) |
| |
| # Check whether deps2submodules changed anything. |
| try: |
| self.m.git('diff-index', '--quiet', '--cached', 'HEAD') |
| except self.m.step.StepFailure as f: |
| # An exit code of 1 means there were differences. |
| if f.retcode == 1: |
| # Commit and push to the destination ref. |
| self.m.git('commit', '-m', COMMIT_MESSAGE) |
| # TODO(hinoka): Delete after luci migration |
| if self.m.runtime.is_experimental: |
| self.m.git('push', 'origin', '--dry-run', 'HEAD:%s' % dest_ref) |
| else: |
| self.m.git('push', 'origin', 'HEAD:%s' % dest_ref) |
| else: |
| raise |