Skip to content

Instantly share code, notes, and snippets.

@Eloston
Last active April 12, 2018 19:02
Show Gist options
  • Save Eloston/e9a627ac94f6eaf46c98c362aeba225b to your computer and use it in GitHub Desktop.
Save Eloston/e9a627ac94f6eaf46c98c362aeba225b to your computer and use it in GitHub Desktop.
Get all deps and hooks exclusive to Chromium on Android
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
Prints out the deps and hooks exclusive to Chromium for Android
Usage: get_android_deps.py path/to/DEPS
"""
import ast
import sys
class _UnexpectedSyntax(RuntimeError):
"""Raised when unexpected syntax is used in DEPS"""
pass
class _DepsNodeVisitor(ast.NodeVisitor):
_valid_syntax_types = (
ast.mod, ast.expr_context, ast.boolop,
ast.Assign, ast.Add, ast.Name, ast.Dict, ast.Str, ast.NameConstant,
ast.List, ast.BinOp
)
_allowed_callables = ('Var',)
def visit_Call(self, node):
if node.func.id not in self._allowed_callables:
raise _UnexpectedSyntax(
'Unexpected call of "%s" at line %s, column %s' % (
node.func.id, node.lineno, node.col_offset))
def generic_visit(self, node):
for ast_type in self._valid_syntax_types:
if isinstance(node, ast_type):
super().generic_visit(node)
return
raise _UnexpectedSyntax(
'Unexpected {} at line {}, column {}'.format(
type(node).__name__, node.lineno, node.col_offset))
def _validate_deps(deps_text):
"""Returns True if the DEPS file passes validation; False otherwise"""
try:
_DepsNodeVisitor().visit(ast.parse(deps_text))
except _UnexpectedSyntax as exc:
print('ERROR: %s' % exc)
return False
return True
def _deps_var(deps_globals):
"""Return a function that implements DEPS's Var() function"""
def _var_impl(var_name):
"""Implementation of Var() in DEPS"""
return deps_globals['vars'][var_name]
return _var_impl
def _parse_deps(deps_text):
"""Returns a dict of parsed DEPS data"""
deps_globals = {'__builtins__': None}
deps_globals['Var'] = _deps_var(deps_globals)
exec(deps_text, deps_globals)
return deps_globals
def _get_android_deps(parsed_deps):
"""Yields deps that are needed only by Android"""
recursive_deps = dict()
for recurse_dep in parsed_deps['recursedeps']:
if isinstance(recurse_dep, str):
recursive_deps[recurse_dep] = 'DEPS'
elif isinstance(recurse_dep, list):
recursive_deps[recurse_dep[0]] = recurse_dep[1]
else:
raise ValueError('Unexpected recursedeps value: %s' % recurse_dep)
for dep_name, dep_def in parsed_deps['deps'].items():
if isinstance(dep_def, str):
# This is just a URL, so skip it
continue
condition = dep_def.get('condition', '')
if 'checkout_linux' not in condition and 'checkout_android' in condition:
yield dep_name, dep_def, recursive_deps.get(dep_name)
def _get_android_hooks(parsed_deps):
"""Yields hooks that are needed only by Android"""
for hook in parsed_deps['hooks']:
condition = hook.get('condition', '')
if 'checkout_linux' not in condition and 'checkout_android' in condition:
yield hook['name'], hook
def main(args):
assert len(args) == 1
with open(args[0]) as deps_file:
deps_text = deps_file.read()
if not _validate_deps(deps_text):
print('ERROR: DEPS does not pass validation. Aborting.')
return 1
parsed_deps = _parse_deps(deps_text)
print('***Dependencies:')
for dep_name, dep_def, recurse_dep in sorted(_get_android_deps(parsed_deps)):
if recurse_dep:
print(dep_name, '(Contains additional deps file: %s)' % recurse_dep)
else:
print(dep_name)
print('***Hooks:')
for hook_name, hook in sorted(_get_android_hooks(parsed_deps)):
print(hook_name)
return 0
if __name__ == '__main__':
exit(main(sys.argv[1:]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment