Chromium Code Reviews| Index: mojo/dart/tools/presubmit/check_mojom_dart.py |
| diff --git a/mojo/dart/tools/presubmit/check_mojom_dart.py b/mojo/dart/tools/presubmit/check_mojom_dart.py |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..eea2ba34c20bfb73f1d1269575f7400e18f0c92b |
| --- /dev/null |
| +++ b/mojo/dart/tools/presubmit/check_mojom_dart.py |
| @@ -0,0 +1,191 @@ |
| +#!/usr/bin/env python |
| +# Copyright 2015 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. |
| + |
| +"""Checks that released mojom.dart files in the source tree are up to date""" |
| + |
| +import os |
| +import subprocess |
| +import sys |
| + |
| +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
| +SRC_DIR = os.path.dirname( |
| + os.path.dirname( |
| + os.path.dirname( |
| + os.path.dirname(SCRIPT_DIR)))) |
| + |
| +PACKAGES_DIR = os.path.join(SRC_DIR, 'mojo', 'dart', 'packages') |
| + |
| +# Script that calculates mojom output paths. |
| +DART_OUTPUTS_SCRIPT = os.path.join(SRC_DIR, |
| + 'mojo', |
| + 'public', |
| + 'tools', |
| + 'bindings', |
| + 'mojom_list_dart_outputs.py') |
| + |
| +# Runs command line in args from cwd. Returns the output as a string. |
| +def run(cwd, args): |
| + return subprocess.check_output(args, cwd=cwd) |
| + |
| + |
| +def _print_regenerate_message(package): |
| + print('*** Dart Generated Bindings Check Failed:') |
|
jamesr
2015/11/17 01:35:07
this is a good place to use python's """, i.e.
pr
Cutch
2015/11/17 18:17:15
Done.
|
| + print('You must regenerate bindings for %s.' % package) |
| + print('From the src directory, run:') |
| + print('$ dart mojo/dart/packages/mojom/bin/mojom.dart gen -m mojo/public ' + |
| + '-r mojo/ --output mojo/dart/packages/'); |
| + |
| + |
| +# Returns a map from package name to source directory. |
| +def _build_package_map(): |
| + packages = {} |
| + for package in os.listdir(PACKAGES_DIR): |
| + package_path = os.path.join(PACKAGES_DIR, package) |
| + # Skip everything but directories. |
| + if not os.path.isdir(package_path): |
| + continue |
| + packages[package] = package_path |
| + return packages |
| + |
| + |
| +# Returns a list of paths to .mojom files vended by package_name. |
| +def _find_mojoms_for_package(package_name): |
| + # Run git grep for all .mojom files with DartPackage="package_name" |
| + try: |
| + output = run(SRC_DIR, ['git', |
| + 'grep', |
| + '--name-only', |
| + 'DartPackage="' + package_name + '"', |
| + '--', |
| + '*.mojom']) |
| + except subprocess.CalledProcessError as e: |
| + # git grep exits with code 1 if nothing was found. |
| + if e.returncode == 1: |
| + return [] |
| + |
| + # Process output |
| + mojoms = [] |
| + for line in output.splitlines(): |
| + line = line.strip() |
| + # Skip empty lines. |
| + if not line: |
| + continue |
| + mojoms.append(line) |
| + return mojoms |
| + |
| + |
| +# Return the list of expected mojom.dart files for a package. |
| +def _expected_mojom_darts_for_package(mojoms): |
| + output = run(SRC_DIR, ['python', |
| + DART_OUTPUTS_SCRIPT, |
| + '--mojoms'] + mojoms) |
| + mojom_darts = [] |
| + for line in output.splitlines(): |
| + line = line.strip() |
| + # Skip empty lines. |
| + if not line: |
| + continue |
| + mojom_darts.append(line) |
| + return mojom_darts |
| + |
| + |
| +# Returns a map indexed by output mojom.dart name with the value of |
| +# the modification time of the .mojom file in the source tree. |
| +def _build_expected_map(mojoms, mojom_darts): |
| + assert(len(mojom_darts) == len(mojoms)) |
| + expected = {} |
| + for i in range(0, len(mojoms)): |
| + mojom_path = os.path.join(SRC_DIR, mojoms[i]) |
| + expected[mojom_darts[i]] = os.path.getmtime(mojom_path) |
| + return expected |
| + |
| + |
| +# Returns a map indexed by output mojom.dart name with the value of |
| +# the modification time of the .mojom.dart file in the source tree. |
| +def _build_current_map(package): |
| + current = {} |
| + package_path = os.path.join(PACKAGES_DIR, package) |
| + for directory, _, files in os.walk(package_path): |
| + for filename in files: |
| + if filename.endswith('.mojom.dart'): |
| + path = os.path.abspath(os.path.join(directory, filename)) |
| + relpath = os.path.relpath(path, start=PACKAGES_DIR) |
| + current[relpath] = os.path.getmtime(path) |
| + return current |
| + |
| + |
| +# Checks if a mojom.dart file we expected in the source tree isn't there. |
| +def _check_new(package, expected, current): |
| + checkFailure = False |
| + for mojom_dart in expected: |
| + if not current.get(mojom_dart): |
| + print("Package %s missing %s" % (package, mojom_dart)) |
| + checkFailure = True |
| + return checkFailure |
| + |
| + |
| +# Checks if a mojom.dart file exists without an associated .mojom file. |
| +def _check_delete(package, expected, current): |
| + checkFailure = False |
| + for mojom_dart in current: |
| + if not expected.get(mojom_dart): |
| + print("Package %s no longer has %s." % (package, mojom_dart)) |
| + print("Delete %s", os.path.join(PACKAGES_DIR, mojom_dart)) |
| + checkFailure = True |
| + return checkFailure |
| + |
| + |
| +# Checks if a .mojom.dart file is older than the associated .mojom file. |
| +# TODO(johnmccutchan): Handle the case where someone edited a .mojom.dart file |
| +# directly instead of through the bindings generation script. |
| +def _check_stale(package, expected, current): |
| + checkFailure = False |
| + for mojom_dart in expected: |
|
jamesr
2015/11/17 01:35:07
the mix of hacker_style and camelCase is confusing
Cutch
2015/11/17 18:17:15
Done. I was switching between Dart and Python yest
|
| + # Missing mojom.dart file in source tree case handled by _check_new. |
| + source_mtime = expected[mojom_dart] |
| + if not current.get(mojom_dart): |
| + continue |
| + generated_mtime = current[mojom_dart] |
| + if generated_mtime < source_mtime: |
| + print("Package %s has old %s" % (package, mojom_dart)) |
| + checkFailure = True |
| + return checkFailure |
| + |
| + |
| +# Returns True if any checks fail. |
| +def _check(package, expected, current): |
| + checkFailure = False |
| + if _check_new(package, expected, current): |
| + checkFailure = True |
| + if _check_stale(package, expected, current): |
| + checkFailure = True |
| + if _check_delete(package, expected, current): |
| + checkFailure = True |
| + # No check failures. |
| + return checkFailure |
| + |
| +def main(): |
| + packages = _build_package_map() |
| + checkFailed = False |
| + for package in packages: |
| + mojoms = _find_mojoms_for_package(package) |
| + if not mojoms: |
| + continue |
| + mojom_darts = _expected_mojom_darts_for_package(mojoms) |
| + # We only feed in mojom files with DartPackage annotations, therefore, we |
| + # should have a 1:1 mapping from mojoms[i] to mojom_darts[i]. |
| + assert(len(mojom_darts) == len(mojoms)) |
| + expected = _build_expected_map(mojoms, mojom_darts) |
| + current = _build_current_map(package) |
| + if _check(package, expected, current): |
| + _print_regenerate_message(package) |
| + checkFailed = True |
| + if checkFailed: |
| + sys.exit(2) |
| + print('OK.') |
| + sys.exit(0) |
| + |
| +if __name__ == '__main__': |
| + sys.exit(main()) |