gclient sync: Add support to apply gerrit refs.
Mimics bot_update's functionality to apply gerrit refs in gclient
via --gerrit-ref flags.
When the patch fails to apply, gclient sync will return exit code 2.
The idea is to move this logic from bot_update to gclient sync to
deal when patches for projects like ANGLE are tried on Chromium bots.
This way the patch is applied before recursively parsing and syncing
ANGLE’s DEPS.chromium file, which doesn't currently happen.
Bug: 643346
Change-Id: I7e2018b3c393a5ac9852b8c3611f906977eeeb18
Reviewed-on: https://chromium-review.googlesource.com/961605
Reviewed-by: Aaron Gable <agable@chromium.org>
Commit-Queue: Edward Lesmes <ehmaldonado@chromium.org>
diff --git a/gclient.py b/gclient.py
index 8bd839d..c4bf011 100755
--- a/gclient.py
+++ b/gclient.py
@@ -936,7 +936,8 @@
# Arguments number differs from overridden method
# pylint: disable=arguments-differ
- def run(self, revision_overrides, command, args, work_queue, options):
+ def run(self, revision_overrides, command, args, work_queue, options,
+ patch_refs):
"""Runs |command| then parse the DEPS file."""
logging.info('Dependency(%s).run()' % self.name)
assert self._file_list == []
@@ -963,6 +964,13 @@
out_cb=work_queue.out_cb)
self._got_revision = self._used_scm.RunCommand(command, options, args,
file_list)
+
+ patch_repo = parsed_url.split('@')[0]
+ patch_ref = patch_refs.pop(patch_repo, patch_refs.pop(self.name, None))
+ if command == 'update' and patch_ref is not None:
+ self._used_scm.apply_patch_ref(patch_repo, patch_ref, options,
+ file_list)
+
if file_list:
file_list = [os.path.join(self.name, f.strip()) for f in file_list]
@@ -1596,6 +1604,20 @@
index += 1
return revision_overrides
+ def _EnforcePatchRefs(self):
+ """Checks for patch refs."""
+ patch_refs = {}
+ if not self._options.patch_refs:
+ return patch_refs
+ for given_patch_ref in self._options.patch_refs:
+ patch_repo, _, patch_ref = given_patch_ref.partition('@')
+ if not patch_repo or not patch_ref:
+ raise gclient_utils.Error(
+ 'Wrong revision format: %s should be of the form '
+ 'patch_repo@patch_ref.' % given_patch_ref)
+ patch_refs[patch_repo] = patch_ref
+ return patch_refs
+
def RunOnDeps(self, command, args, ignore_requirements=False, progress=True):
"""Runs a command on each dependency in a client and its dependencies.
@@ -1607,12 +1629,16 @@
raise gclient_utils.Error('No solution specified')
revision_overrides = {}
+ patch_refs = {}
# It's unnecessary to check for revision overrides for 'recurse'.
# Save a few seconds by not calling _EnforceRevisions() in that case.
if command not in ('diff', 'recurse', 'runhooks', 'status', 'revert',
'validate'):
self._CheckConfig()
revision_overrides = self._EnforceRevisions()
+
+ if command == 'update':
+ patch_refs = self._EnforcePatchRefs()
# Disable progress for non-tty stdout.
should_show_progress = (
setup_color.IS_TTY and not self._options.verbose and progress)
@@ -1628,10 +1654,19 @@
for s in self.dependencies:
if s.should_process:
work_queue.enqueue(s)
- work_queue.flush(revision_overrides, command, args, options=self._options)
+ work_queue.flush(revision_overrides, command, args, options=self._options,
+ patch_refs=patch_refs)
+
if revision_overrides:
print('Please fix your script, having invalid --revision flags will soon '
- 'considered an error.', file=sys.stderr)
+ 'be considered an error.', file=sys.stderr)
+
+ if patch_refs:
+ raise gclient_utils.Error(
+ 'The following --patch-ref flags were not used. Please fix it:\n%s' %
+ ('\n'.join(
+ patch_repo + '@' + patch_ref
+ for patch_repo, patch_ref in patch_refs.iteritems())))
if self._cipd_root:
self._cipd_root.run(command)
@@ -1749,7 +1784,7 @@
for s in self.dependencies:
if s.should_process:
work_queue.enqueue(s)
- work_queue.flush({}, None, [], options=self._options)
+ work_queue.flush({}, None, [], options=self._options, patch_refs=None)
def ShouldPrintRevision(path, rev):
if not self._options.path and not self._options.url:
@@ -1920,14 +1955,15 @@
self._package_version = version
#override
- def run(self, revision_overrides, command, args, work_queue, options):
+ def run(self, revision_overrides, command, args, work_queue, options,
+ patch_refs):
"""Runs |command| then parse the DEPS file."""
logging.info('CipdDependency(%s).run()' % self.name)
if not self.should_process:
return
self._CreatePackageIfNecessary()
super(CipdDependency, self).run(revision_overrides, command, args,
- work_queue, options)
+ work_queue, options, patch_refs)
def _CreatePackageIfNecessary(self):
# We lazily create the CIPD package to make sure that only packages
@@ -2637,6 +2673,15 @@
'takes precedence. -r can be used multiple times when '
'.gclient has multiple solutions configured, and will '
'work even if the src@ part is skipped.')
+ parser.add_option('--patch-ref', action='append',
+ dest='patch_refs', metavar='GERRIT_REF', default=[],
+ help='Patches the given reference with the format dep@ref. '
+ 'For dep, you can specify URLs as well as paths, with '
+ 'URLs taking preference. The reference will be '
+ 'applied to the necessary path, will be rebased on '
+ 'top what the dep was synced to, and then will do a '
+ 'soft reset. Use --no-rebase-patch-ref and '
+ '--reset-patch-ref to disable this behavior.')
parser.add_option('--with_branch_heads', action='store_true',
help='Clone git "branch_heads" refspecs in addition to '
'the default refspecs. This adds about 1/2GB to a '
@@ -2708,6 +2753,12 @@
parser.add_option('--disable-syntax-validation', action='store_false',
dest='validate_syntax',
help='Disable validation of .gclient and DEPS syntax.')
+ parser.add_option('--no-rebase-patch-ref', action='store_false',
+ dest='rebase_patch_ref', default=True,
+ help='Bypass rebase of the patch ref after checkout.')
+ parser.add_option('--no-reset-patch-ref', action='store_false',
+ dest='reset_patch_ref', default=True,
+ help='Bypass calling reset after patching the ref.')
(options, args) = parser.parse_args(args)
client = GClient.LoadCurrentConfig(options)