OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python | |
2 # Copyright 2015 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 | |
6 """Checks that released mojom.dart files in the source tree are up to date""" | |
7 | |
8 import os | |
9 import subprocess | |
10 import sys | |
11 | |
12 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) | |
13 SRC_DIR = os.path.dirname( | |
14 os.path.dirname( | |
15 os.path.dirname( | |
16 os.path.dirname(SCRIPT_DIR)))) | |
17 | |
18 PACKAGES_DIR = os.path.join(SRC_DIR, 'mojo', 'dart', 'packages') | |
19 | |
20 # Script that calculates mojom output paths. | |
21 DART_OUTPUTS_SCRIPT = os.path.join(SRC_DIR, | |
22 'mojo', | |
23 'public', | |
24 'tools', | |
25 'bindings', | |
26 'mojom_list_dart_outputs.py') | |
27 | |
28 # Runs command line in args from cwd. Returns the output as a string. | |
29 def run(cwd, args): | |
30 return subprocess.check_output(args, cwd=cwd) | |
31 | |
32 | |
33 def _print_regenerate_message(package): | |
34 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.
| |
35 print('You must regenerate bindings for %s.' % package) | |
36 print('From the src directory, run:') | |
37 print('$ dart mojo/dart/packages/mojom/bin/mojom.dart gen -m mojo/public ' + | |
38 '-r mojo/ --output mojo/dart/packages/'); | |
39 | |
40 | |
41 # Returns a map from package name to source directory. | |
42 def _build_package_map(): | |
43 packages = {} | |
44 for package in os.listdir(PACKAGES_DIR): | |
45 package_path = os.path.join(PACKAGES_DIR, package) | |
46 # Skip everything but directories. | |
47 if not os.path.isdir(package_path): | |
48 continue | |
49 packages[package] = package_path | |
50 return packages | |
51 | |
52 | |
53 # Returns a list of paths to .mojom files vended by package_name. | |
54 def _find_mojoms_for_package(package_name): | |
55 # Run git grep for all .mojom files with DartPackage="package_name" | |
56 try: | |
57 output = run(SRC_DIR, ['git', | |
58 'grep', | |
59 '--name-only', | |
60 'DartPackage="' + package_name + '"', | |
61 '--', | |
62 '*.mojom']) | |
63 except subprocess.CalledProcessError as e: | |
64 # git grep exits with code 1 if nothing was found. | |
65 if e.returncode == 1: | |
66 return [] | |
67 | |
68 # Process output | |
69 mojoms = [] | |
70 for line in output.splitlines(): | |
71 line = line.strip() | |
72 # Skip empty lines. | |
73 if not line: | |
74 continue | |
75 mojoms.append(line) | |
76 return mojoms | |
77 | |
78 | |
79 # Return the list of expected mojom.dart files for a package. | |
80 def _expected_mojom_darts_for_package(mojoms): | |
81 output = run(SRC_DIR, ['python', | |
82 DART_OUTPUTS_SCRIPT, | |
83 '--mojoms'] + mojoms) | |
84 mojom_darts = [] | |
85 for line in output.splitlines(): | |
86 line = line.strip() | |
87 # Skip empty lines. | |
88 if not line: | |
89 continue | |
90 mojom_darts.append(line) | |
91 return mojom_darts | |
92 | |
93 | |
94 # Returns a map indexed by output mojom.dart name with the value of | |
95 # the modification time of the .mojom file in the source tree. | |
96 def _build_expected_map(mojoms, mojom_darts): | |
97 assert(len(mojom_darts) == len(mojoms)) | |
98 expected = {} | |
99 for i in range(0, len(mojoms)): | |
100 mojom_path = os.path.join(SRC_DIR, mojoms[i]) | |
101 expected[mojom_darts[i]] = os.path.getmtime(mojom_path) | |
102 return expected | |
103 | |
104 | |
105 # Returns a map indexed by output mojom.dart name with the value of | |
106 # the modification time of the .mojom.dart file in the source tree. | |
107 def _build_current_map(package): | |
108 current = {} | |
109 package_path = os.path.join(PACKAGES_DIR, package) | |
110 for directory, _, files in os.walk(package_path): | |
111 for filename in files: | |
112 if filename.endswith('.mojom.dart'): | |
113 path = os.path.abspath(os.path.join(directory, filename)) | |
114 relpath = os.path.relpath(path, start=PACKAGES_DIR) | |
115 current[relpath] = os.path.getmtime(path) | |
116 return current | |
117 | |
118 | |
119 # Checks if a mojom.dart file we expected in the source tree isn't there. | |
120 def _check_new(package, expected, current): | |
121 checkFailure = False | |
122 for mojom_dart in expected: | |
123 if not current.get(mojom_dart): | |
124 print("Package %s missing %s" % (package, mojom_dart)) | |
125 checkFailure = True | |
126 return checkFailure | |
127 | |
128 | |
129 # Checks if a mojom.dart file exists without an associated .mojom file. | |
130 def _check_delete(package, expected, current): | |
131 checkFailure = False | |
132 for mojom_dart in current: | |
133 if not expected.get(mojom_dart): | |
134 print("Package %s no longer has %s." % (package, mojom_dart)) | |
135 print("Delete %s", os.path.join(PACKAGES_DIR, mojom_dart)) | |
136 checkFailure = True | |
137 return checkFailure | |
138 | |
139 | |
140 # Checks if a .mojom.dart file is older than the associated .mojom file. | |
141 # TODO(johnmccutchan): Handle the case where someone edited a .mojom.dart file | |
142 # directly instead of through the bindings generation script. | |
143 def _check_stale(package, expected, current): | |
144 checkFailure = False | |
145 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
| |
146 # Missing mojom.dart file in source tree case handled by _check_new. | |
147 source_mtime = expected[mojom_dart] | |
148 if not current.get(mojom_dart): | |
149 continue | |
150 generated_mtime = current[mojom_dart] | |
151 if generated_mtime < source_mtime: | |
152 print("Package %s has old %s" % (package, mojom_dart)) | |
153 checkFailure = True | |
154 return checkFailure | |
155 | |
156 | |
157 # Returns True if any checks fail. | |
158 def _check(package, expected, current): | |
159 checkFailure = False | |
160 if _check_new(package, expected, current): | |
161 checkFailure = True | |
162 if _check_stale(package, expected, current): | |
163 checkFailure = True | |
164 if _check_delete(package, expected, current): | |
165 checkFailure = True | |
166 # No check failures. | |
167 return checkFailure | |
168 | |
169 def main(): | |
170 packages = _build_package_map() | |
171 checkFailed = False | |
172 for package in packages: | |
173 mojoms = _find_mojoms_for_package(package) | |
174 if not mojoms: | |
175 continue | |
176 mojom_darts = _expected_mojom_darts_for_package(mojoms) | |
177 # We only feed in mojom files with DartPackage annotations, therefore, we | |
178 # should have a 1:1 mapping from mojoms[i] to mojom_darts[i]. | |
179 assert(len(mojom_darts) == len(mojoms)) | |
180 expected = _build_expected_map(mojoms, mojom_darts) | |
181 current = _build_current_map(package) | |
182 if _check(package, expected, current): | |
183 _print_regenerate_message(package) | |
184 checkFailed = True | |
185 if checkFailed: | |
186 sys.exit(2) | |
187 print('OK.') | |
188 sys.exit(0) | |
189 | |
190 if __name__ == '__main__': | |
191 sys.exit(main()) | |
OLD | NEW |