OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2013 The Chromium Authors. All rights reserved. | 3 # Copyright 2013 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 import optparse | 7 import optparse |
8 import os | 8 import os |
9 import shutil | 9 import shutil |
10 import re | 10 import re |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 wrapper = textwrap.TextWrapper(break_long_words=True, | 101 wrapper = textwrap.TextWrapper(break_long_words=True, |
102 drop_whitespace=False, | 102 drop_whitespace=False, |
103 subsequent_indent=' ', | 103 subsequent_indent=' ', |
104 width=_MAX_MANIFEST_LINE_LEN - 2) | 104 width=_MAX_MANIFEST_LINE_LEN - 2) |
105 output = '\r\n'.join(w for l in output for w in wrapper.wrap(l)) | 105 output = '\r\n'.join(w for l in output for w in wrapper.wrap(l)) |
106 | 106 |
107 with open(manifest_path, 'w') as f: | 107 with open(manifest_path, 'w') as f: |
108 f.write(output) | 108 f.write(output) |
109 | 109 |
110 | 110 |
| 111 def _ExtractClassFiles(jar_path, dest_dir, java_files): |
| 112 """Extracts all .class files not corresponding to |java_files|.""" |
| 113 # Two challenges exist here: |
| 114 # 1. |java_files| have prefixes that are not represented in the the jar paths. |
| 115 # 2. A single .java file results in multiple .class files when it contains |
| 116 # nested classes. |
| 117 # Here's an example: |
| 118 # source path: ../../base/android/java/src/org/chromium/Foo.java |
| 119 # jar paths: org/chromium/Foo.class, org/chromium/Foo$Inner.class |
| 120 # To extract only .class files not related to the given .java files, we strip |
| 121 # off ".class" and "$*.class" and use a substring match against java_files. |
| 122 def extract_predicate(path): |
| 123 if not path.endswith('.class'): |
| 124 return False |
| 125 path_without_suffix = re.sub(r'(?:\$[^/]+)?\.class$', '', path) |
| 126 return not any(path_without_suffix in p for p in java_files) |
| 127 |
| 128 build_utils.ExtractAll(jar_path, path=dest_dir, predicate=extract_predicate) |
| 129 |
| 130 |
| 131 def _OnStaleMd5(changes, options, javac_cmd, java_files, classpath_inputs, |
| 132 runtime_classpath): |
| 133 with build_utils.TempDir() as temp_dir: |
| 134 srcjars = options.java_srcjars |
| 135 # The .excluded.jar contains .class files excluded from the main jar. |
| 136 # It is used for incremental compiles. |
| 137 excluded_jar_path = options.jar_path.replace('.jar', '.excluded.jar') |
| 138 |
| 139 classes_dir = os.path.join(temp_dir, 'classes') |
| 140 os.makedirs(classes_dir) |
| 141 |
| 142 changed_paths = None |
| 143 if options.incremental and changes.AddedOrModifiedOnly(): |
| 144 changed_paths = set(changes.IterChangedPaths()) |
| 145 # Do a full compile if classpath has changed. |
| 146 if any(p in changed_paths for p in classpath_inputs): |
| 147 changed_paths = None |
| 148 else: |
| 149 java_files = [p for p in java_files if p in changed_paths] |
| 150 srcjars = [p for p in srcjars if p in changed_paths] |
| 151 |
| 152 if srcjars: |
| 153 java_dir = os.path.join(temp_dir, 'java') |
| 154 os.makedirs(java_dir) |
| 155 for srcjar in options.java_srcjars: |
| 156 extract_predicate = None |
| 157 if changed_paths: |
| 158 changed_subpaths = set(changes.IterChangedSubpaths(srcjar)) |
| 159 extract_predicate = lambda p: p in changed_subpaths |
| 160 build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java', |
| 161 predicate=extract_predicate) |
| 162 jar_srcs = build_utils.FindInDirectory(java_dir, '*.java') |
| 163 java_files.extend(_FilterJavaFiles(jar_srcs, options.javac_includes)) |
| 164 |
| 165 if java_files: |
| 166 if changed_paths: |
| 167 # When no files have been removed and the output jar already |
| 168 # exists, reuse .class files from the existing jar. |
| 169 _ExtractClassFiles(options.jar_path, classes_dir, java_files) |
| 170 _ExtractClassFiles(excluded_jar_path, classes_dir, java_files) |
| 171 # Add the extracted files to the classpath. |
| 172 classpath_idx = javac_cmd.index('-classpath') |
| 173 javac_cmd[classpath_idx + 1] += ':' + classes_dir |
| 174 |
| 175 # Don't include the output directory in the initial set of args since it |
| 176 # being in a temp dir makes it unstable (breaks md5 stamping). |
| 177 cmd = javac_cmd + ['-d', classes_dir] + java_files |
| 178 |
| 179 build_utils.CheckOutput( |
| 180 cmd, |
| 181 print_stdout=options.chromium_code, |
| 182 stderr_filter=ColorJavacOutput) |
| 183 |
| 184 if options.main_class or options.manifest_entry: |
| 185 entries = [] |
| 186 if options.manifest_entry: |
| 187 entries = [e.split(':') for e in options.manifest_entry] |
| 188 manifest_file = os.path.join(temp_dir, 'manifest') |
| 189 _CreateManifest(manifest_file, runtime_classpath, options.main_class, |
| 190 entries) |
| 191 else: |
| 192 manifest_file = None |
| 193 |
| 194 glob = options.jar_excluded_classes |
| 195 inclusion_predicate = lambda f: not build_utils.MatchesGlob(f, glob) |
| 196 exclusion_predicate = lambda f: not inclusion_predicate(f) |
| 197 |
| 198 jar.JarDirectory(classes_dir, |
| 199 options.jar_path, |
| 200 manifest_file=manifest_file, |
| 201 predicate=inclusion_predicate) |
| 202 jar.JarDirectory(classes_dir, |
| 203 excluded_jar_path, |
| 204 predicate=exclusion_predicate) |
| 205 |
| 206 |
111 def _ParseOptions(argv): | 207 def _ParseOptions(argv): |
112 parser = optparse.OptionParser() | 208 parser = optparse.OptionParser() |
113 build_utils.AddDepfileOption(parser) | 209 build_utils.AddDepfileOption(parser) |
114 | 210 |
115 parser.add_option( | 211 parser.add_option( |
116 '--src-gendirs', | 212 '--src-gendirs', |
117 help='Directories containing generated java files.') | 213 help='Directories containing generated java files.') |
118 parser.add_option( | 214 parser.add_option( |
119 '--java-srcjars', | 215 '--java-srcjars', |
120 action='append', | 216 action='append', |
121 default=[], | 217 default=[], |
122 help='List of srcjars to include in compilation.') | 218 help='List of srcjars to include in compilation.') |
123 parser.add_option( | 219 parser.add_option( |
124 '--bootclasspath', | 220 '--bootclasspath', |
125 action='append', | 221 action='append', |
126 default=[], | 222 default=[], |
127 help='Boot classpath for javac. If this is specified multiple times, ' | 223 help='Boot classpath for javac. If this is specified multiple times, ' |
128 'they will all be appended to construct the classpath.') | 224 'they will all be appended to construct the classpath.') |
129 parser.add_option( | 225 parser.add_option( |
130 '--classpath', | 226 '--classpath', |
131 action='append', | 227 action='append', |
132 help='Classpath for javac. If this is specified multiple times, they ' | 228 help='Classpath for javac. If this is specified multiple times, they ' |
133 'will all be appended to construct the classpath.') | 229 'will all be appended to construct the classpath.') |
134 parser.add_option( | 230 parser.add_option( |
135 '--use-ijars', | 231 '--use-ijars', |
136 action='store_true', | 232 action='store_true', |
137 help='Whether to use interface jars (.interface.jar) when compiling') | 233 help='Whether to use interface jars (.interface.jar) when compiling') |
138 parser.add_option( | 234 parser.add_option( |
| 235 '--incremental', |
| 236 action='store_true', |
| 237 help='Whether to re-use .class files rather than recompiling them ' |
| 238 '(when possible).') |
| 239 parser.add_option( |
139 '--javac-includes', | 240 '--javac-includes', |
140 default='', | 241 default='', |
141 help='A list of file patterns. If provided, only java files that match' | 242 help='A list of file patterns. If provided, only java files that match' |
142 'one of the patterns will be compiled.') | 243 'one of the patterns will be compiled.') |
143 parser.add_option( | 244 parser.add_option( |
144 '--jar-excluded-classes', | 245 '--jar-excluded-classes', |
145 default='', | 246 default='', |
146 help='List of .class file patterns to exclude from the jar.') | 247 help='List of .class file patterns to exclude from the jar.') |
147 | 248 |
148 parser.add_option( | 249 parser.add_option( |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 | 333 |
233 if options.chromium_code: | 334 if options.chromium_code: |
234 # TODO(aurimas): re-enable '-Xlint:deprecation' checks once they are fixed. | 335 # TODO(aurimas): re-enable '-Xlint:deprecation' checks once they are fixed. |
235 javac_cmd.extend(['-Xlint:unchecked']) | 336 javac_cmd.extend(['-Xlint:unchecked']) |
236 else: | 337 else: |
237 # XDignore.symbol.file makes javac compile against rt.jar instead of | 338 # XDignore.symbol.file makes javac compile against rt.jar instead of |
238 # ct.sym. This means that using a java internal package/class will not | 339 # ct.sym. This means that using a java internal package/class will not |
239 # trigger a compile warning or error. | 340 # trigger a compile warning or error. |
240 javac_cmd.extend(['-XDignore.symbol.file']) | 341 javac_cmd.extend(['-XDignore.symbol.file']) |
241 | 342 |
242 # Compute the list of paths that when changed, we need to rebuild. | 343 classpath_inputs = options.bootclasspath |
243 input_paths = options.bootclasspath + options.java_srcjars + java_files | |
244 # TODO(agrieve): Remove this .TOC heuristic once GYP is no more. | 344 # TODO(agrieve): Remove this .TOC heuristic once GYP is no more. |
245 if not options.use_ijars: | 345 if options.use_ijars: |
| 346 classpath_inputs.extend(compile_classpath) |
| 347 else: |
246 for path in compile_classpath: | 348 for path in compile_classpath: |
247 if os.path.exists(path + '.TOC'): | 349 if os.path.exists(path + '.TOC'): |
248 input_paths.append(path + '.TOC') | 350 classpath_inputs.append(path + '.TOC') |
249 else: | 351 else: |
250 input_paths.append(path) | 352 classpath_inputs.append(path) |
251 | 353 |
252 def on_stale_md5(): | 354 # Compute the list of paths that when changed, we need to rebuild. |
253 with build_utils.TempDir() as temp_dir: | 355 input_paths = classpath_inputs + options.java_srcjars + java_files |
254 if options.java_srcjars: | |
255 java_dir = os.path.join(temp_dir, 'java') | |
256 os.makedirs(java_dir) | |
257 for srcjar in options.java_srcjars: | |
258 build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java') | |
259 jar_srcs = build_utils.FindInDirectory(java_dir, '*.java') | |
260 java_files.extend(_FilterJavaFiles(jar_srcs, options.javac_includes)) | |
261 | 356 |
262 classes_dir = os.path.join(temp_dir, 'classes') | 357 output_paths = [ |
263 os.makedirs(classes_dir) | 358 options.jar_path, |
| 359 options.jar_path.replace('.jar', '.excluded.jar'), |
| 360 ] |
264 | 361 |
265 if java_files: | 362 # An escape hatch to be able to check if incremental compiles are causing |
266 # Don't include the output directory in the initial set of args since it | 363 # problems. |
267 # being in a temp dir makes it unstable (breaks md5 stamping). | 364 force = int(os.environ.get('DISABLE_INCREMENTAL_JAVAC', 0)) |
268 cmd = javac_cmd + ['-d', classes_dir] + java_files | |
269 | |
270 build_utils.CheckOutput( | |
271 cmd, | |
272 print_stdout=options.chromium_code, | |
273 stderr_filter=ColorJavacOutput) | |
274 | |
275 if options.main_class or options.manifest_entry: | |
276 entries = [] | |
277 if options.manifest_entry: | |
278 entries = [e.split(':') for e in options.manifest_entry] | |
279 manifest_file = os.path.join(temp_dir, 'manifest') | |
280 _CreateManifest(manifest_file, runtime_classpath, options.main_class, | |
281 entries) | |
282 else: | |
283 manifest_file = None | |
284 jar.JarDirectory(classes_dir, | |
285 options.jar_excluded_classes, | |
286 options.jar_path, | |
287 manifest_file=manifest_file) | |
288 | |
289 | 365 |
290 # List python deps in input_strings rather than input_paths since the contents | 366 # List python deps in input_strings rather than input_paths since the contents |
291 # of them does not change what gets written to the depsfile. | 367 # of them does not change what gets written to the depsfile. |
292 build_utils.CallAndWriteDepfileIfStale( | 368 build_utils.CallAndWriteDepfileIfStale( |
293 on_stale_md5, | 369 lambda changes: _OnStaleMd5(changes, options, javac_cmd, java_files, |
| 370 classpath_inputs, runtime_classpath), |
294 options, | 371 options, |
295 input_paths=input_paths, | 372 input_paths=input_paths, |
296 input_strings=javac_cmd, | 373 input_strings=javac_cmd, |
297 output_paths=[options.jar_path]) | 374 output_paths=output_paths, |
| 375 force=force, |
| 376 pass_changes=True) |
298 | 377 |
299 | 378 |
300 if __name__ == '__main__': | 379 if __name__ == '__main__': |
301 sys.exit(main(sys.argv[1:])) | 380 sys.exit(main(sys.argv[1:])) |
OLD | NEW |