gclient: add cwd support for hooks

This makes it possible to run hooks properly
in flattened DEPS.

Bug: 570091
Change-Id: If8175a57ebe8f607bd4ac83d4a26dcc4cc18165c
Reviewed-on: https://chromium-review.googlesource.com/535476
Reviewed-by: Andrii Shyshkalov <tandrii@chromium.org>
Commit-Queue: Paweł Hajdan Jr. <phajdan.jr@chromium.org>
changes/76/535476/2
Paweł Hajdan, Jr 8 years ago committed by Commit Bot
parent c10a4d88a4
commit c93643954d

@ -191,22 +191,24 @@ def ToGNString(value, allow_dicts = True):
class Hook(object): class Hook(object):
"""Descriptor of command ran before/after sync or on demand.""" """Descriptor of command ran before/after sync or on demand."""
def __init__(self, action, pattern=None, name=None): def __init__(self, action, pattern=None, name=None, cwd=None):
"""Constructor. """Constructor.
Arguments: Arguments:
action (list of basestring): argv of the command to run action (list of basestring): argv of the command to run
pattern (basestring regex): noop with git; deprecated pattern (basestring regex): noop with git; deprecated
name (basestring): optional name; no effect on operation name (basestring): optional name; no effect on operation
cwd (basestring): working directory to use
""" """
self._action = gclient_utils.freeze(action) self._action = gclient_utils.freeze(action)
self._pattern = pattern self._pattern = pattern
self._name = name self._name = name
self._cwd = cwd
@staticmethod @staticmethod
def from_dict(d): def from_dict(d):
"""Creates a Hook instance from a dict like in the DEPS file.""" """Creates a Hook instance from a dict like in the DEPS file."""
return Hook(d['action'], d.get('pattern'), d.get('name')) return Hook(d['action'], d.get('pattern'), d.get('name'), d.get('cwd'))
@property @property
def action(self): def action(self):
@ -235,10 +237,14 @@ class Hook(object):
# Python script. Run it by starting a new copy of the same # Python script. Run it by starting a new copy of the same
# interpreter. # interpreter.
cmd[0] = sys.executable cmd[0] = sys.executable
cwd = root
if self._cwd:
cwd = os.path.join(cwd, self._cwd)
try: try:
start_time = time.time() start_time = time.time()
gclient_utils.CheckCallAndFilterAndHeader( gclient_utils.CheckCallAndFilterAndHeader(
cmd, cwd=root, always=True) cmd, cwd=cwd, always=True)
except (gclient_utils.Error, subprocess2.CalledProcessError) as e: except (gclient_utils.Error, subprocess2.CalledProcessError) as e:
# Use a discrete exit status code of 2 to indicate that a hook action # Use a discrete exit status code of 2 to indicate that a hook action
# failed. Users of this script may wish to treat hook action failures # failed. Users of this script may wish to treat hook action failures
@ -1833,8 +1839,7 @@ def _FlattenDep(dep, deps, deps_os, hooks, pre_deps_hooks, unpinned_deps):
# TODO(phajdan.jr): also handle hooks_os. # TODO(phajdan.jr): also handle hooks_os.
hooks.extend([(dep, hook) for hook in dep.deps_hooks]) hooks.extend([(dep, hook) for hook in dep.deps_hooks])
pre_deps_hooks.extend( pre_deps_hooks.extend([(dep, hook) for hook in dep.pre_deps_hooks])
[(dep, {'action': hook}) for hook in dep.pre_deps_hooks])
def _FlattenRecurse(dep, deps, deps_os, hooks, pre_deps_hooks, unpinned_deps): def _FlattenRecurse(dep, deps, deps_os, hooks, pre_deps_hooks, unpinned_deps):
@ -1929,9 +1934,9 @@ def _HooksToLines(name, hooks):
s.append(' "name": "%s",' % hook.name) s.append(' "name": "%s",' % hook.name)
if hook.pattern is not None: if hook.pattern is not None:
s.append(' "pattern": "%s",' % hook.pattern) s.append(' "pattern": "%s",' % hook.pattern)
# TODO(phajdan.jr): actions may contain paths that need to be adjusted,
# i.e. they may be relative to the dependency path, not solution root.
s.extend( s.extend(
# Hooks run in the parent directory of their dep.
[' "cwd": "%s"' % os.path.normpath(os.path.dirname(dep.name))] +
[' "action": ['] + [' "action": ['] +
[' "%s",' % arg for arg in hook.action] + [' "%s",' % arg for arg in hook.action] +
[' ]', ' },', ''] [' ]', ' },', '']

@ -20,6 +20,9 @@ _GCLIENT_HOOKS_SCHEMA = [{
# only when files matching the pattern have changed. In practice, with git, # only when files matching the pattern have changed. In practice, with git,
# gclient runs all the hooks regardless of this field. # gclient runs all the hooks regardless of this field.
schema.Optional('pattern'): basestring, schema.Optional('pattern'): basestring,
# Working directory where to execute the hook.
schema.Optional('cwd'): basestring,
}] }]
_GCLIENT_SCHEMA = schema.Schema({ _GCLIENT_SCHEMA = schema.Schema({

@ -638,6 +638,7 @@ class GClientSmokeGIT(GClientSmokeBase):
' # src', ' # src',
' {', ' {',
' "pattern": ".",', ' "pattern": ".",',
' "cwd": "."',
' "action": [', ' "action": [',
' "python",', ' "python",',
' "-c",', ' "-c",',
@ -648,6 +649,7 @@ class GClientSmokeGIT(GClientSmokeBase):
' # src', ' # src',
' {', ' {',
' "pattern": "nonexistent",', ' "pattern": "nonexistent",',
' "cwd": "."',
' "action": [', ' "action": [',
' "python",', ' "python",',
' "-c",', ' "-c",',

Loading…
Cancel
Save