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 fnmatch | |
8 import optparse | 7 import optparse |
9 import os | 8 import os |
10 import shutil | 9 import shutil |
11 import re | 10 import re |
12 import sys | 11 import sys |
13 import textwrap | 12 import textwrap |
14 | 13 |
15 from util import build_utils | 14 from util import build_utils |
16 from util import md5_check | 15 from util import md5_check |
17 | 16 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 return '\n'.join(map(ApplyColor, output.split('\n'))) | 53 return '\n'.join(map(ApplyColor, output.split('\n'))) |
55 | 54 |
56 | 55 |
57 ERRORPRONE_OPTIONS = [ | 56 ERRORPRONE_OPTIONS = [ |
58 # These crash on lots of targets. | 57 # These crash on lots of targets. |
59 '-Xep:ParameterPackage:OFF', | 58 '-Xep:ParameterPackage:OFF', |
60 '-Xep:OverridesGuiceInjectableMethod:OFF', | 59 '-Xep:OverridesGuiceInjectableMethod:OFF', |
61 '-Xep:OverridesJavaxInjectableMethod:OFF', | 60 '-Xep:OverridesJavaxInjectableMethod:OFF', |
62 ] | 61 ] |
63 | 62 |
64 def DoJavac( | |
65 bootclasspath, classpath, classes_dir, chromium_code, | |
66 use_errorprone_path, java_files): | |
67 """Runs javac. | |
68 | 63 |
69 Builds |java_files| with the provided |classpath| and puts the generated | 64 def _FilterJavaFiles(paths, filters): |
70 .class files into |classes_dir|. If |chromium_code| is true, extra lint | 65 return [f for f in paths |
71 checking will be enabled. | 66 if not filters or build_utils.MatchesGlob(f, filters)] |
72 """ | |
73 | |
74 jar_inputs = [] | |
75 for path in classpath: | |
76 if os.path.exists(path + '.TOC'): | |
77 jar_inputs.append(path + '.TOC') | |
78 else: | |
79 jar_inputs.append(path) | |
80 | |
81 javac_args = [ | |
82 '-g', | |
83 # Chromium only allows UTF8 source files. Being explicit avoids | |
84 # javac pulling a default encoding from the user's environment. | |
85 '-encoding', 'UTF-8', | |
86 '-classpath', ':'.join(classpath), | |
87 '-d', classes_dir] | |
88 | |
89 if bootclasspath: | |
90 javac_args.extend([ | |
91 '-bootclasspath', ':'.join(bootclasspath), | |
92 '-source', '1.7', | |
93 '-target', '1.7', | |
94 ]) | |
95 | |
96 if chromium_code: | |
97 # TODO(aurimas): re-enable '-Xlint:deprecation' checks once they are fixed. | |
98 javac_args.extend(['-Xlint:unchecked']) | |
99 else: | |
100 # XDignore.symbol.file makes javac compile against rt.jar instead of | |
101 # ct.sym. This means that using a java internal package/class will not | |
102 # trigger a compile warning or error. | |
103 javac_args.extend(['-XDignore.symbol.file']) | |
104 | |
105 if use_errorprone_path: | |
106 javac_cmd = [use_errorprone_path] + ERRORPRONE_OPTIONS | |
107 else: | |
108 javac_cmd = ['javac'] | |
109 | |
110 javac_cmd = javac_cmd + javac_args + java_files | |
111 | |
112 def Compile(): | |
113 build_utils.CheckOutput( | |
114 javac_cmd, | |
115 print_stdout=chromium_code, | |
116 stderr_filter=ColorJavacOutput) | |
117 | |
118 record_path = os.path.join(classes_dir, 'javac.md5.stamp') | |
119 md5_check.CallAndRecordIfStale( | |
120 Compile, | |
121 record_path=record_path, | |
122 input_paths=java_files + jar_inputs, | |
123 input_strings=javac_cmd) | |
124 | 67 |
125 | 68 |
126 _MAX_MANIFEST_LINE_LEN = 72 | 69 _MAX_MANIFEST_LINE_LEN = 72 |
127 | 70 |
128 | 71 |
129 def CreateManifest(manifest_path, classpath, main_class=None, | 72 def _CreateManifest(manifest_path, classpath, main_class=None, |
130 manifest_entries=None): | 73 manifest_entries=None): |
131 """Creates a manifest file with the given parameters. | 74 """Creates a manifest file with the given parameters. |
132 | 75 |
133 This generates a manifest file that compiles with the spec found at | 76 This generates a manifest file that compiles with the spec found at |
134 http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#JAR_Manifes
t | 77 http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#JAR_Manifes
t |
135 | 78 |
136 Args: | 79 Args: |
137 manifest_path: The path to the manifest file that should be created. | 80 manifest_path: The path to the manifest file that should be created. |
138 classpath: The JAR files that should be listed on the manifest file's | 81 classpath: The JAR files that should be listed on the manifest file's |
139 classpath. | 82 classpath. |
140 main_class: If present, the class containing the main() function. | 83 main_class: If present, the class containing the main() function. |
(...skipping 18 matching lines...) Expand all Loading... |
159 wrapper = textwrap.TextWrapper(break_long_words=True, | 102 wrapper = textwrap.TextWrapper(break_long_words=True, |
160 drop_whitespace=False, | 103 drop_whitespace=False, |
161 subsequent_indent=' ', | 104 subsequent_indent=' ', |
162 width=_MAX_MANIFEST_LINE_LEN - 2) | 105 width=_MAX_MANIFEST_LINE_LEN - 2) |
163 output = '\r\n'.join(w for l in output for w in wrapper.wrap(l)) | 106 output = '\r\n'.join(w for l in output for w in wrapper.wrap(l)) |
164 | 107 |
165 with open(manifest_path, 'w') as f: | 108 with open(manifest_path, 'w') as f: |
166 f.write(output) | 109 f.write(output) |
167 | 110 |
168 | 111 |
169 def main(argv): | 112 def _ParseOptions(argv): |
170 colorama.init() | |
171 | |
172 argv = build_utils.ExpandFileArgs(argv) | |
173 | |
174 parser = optparse.OptionParser() | 113 parser = optparse.OptionParser() |
175 build_utils.AddDepfileOption(parser) | 114 build_utils.AddDepfileOption(parser) |
176 | 115 |
177 parser.add_option( | 116 parser.add_option( |
178 '--src-gendirs', | 117 '--src-gendirs', |
179 help='Directories containing generated java files.') | 118 help='Directories containing generated java files.') |
180 parser.add_option( | 119 parser.add_option( |
181 '--java-srcjars', | 120 '--java-srcjars', |
182 action='append', | 121 action='append', |
183 default=[], | 122 default=[], |
184 help='List of srcjars to include in compilation.') | 123 help='List of srcjars to include in compilation.') |
185 parser.add_option( | 124 parser.add_option( |
186 '--bootclasspath', | 125 '--bootclasspath', |
187 action='append', | 126 action='append', |
188 default=[], | 127 default=[], |
189 help='Boot classpath for javac. If this is specified multiple times, ' | 128 help='Boot classpath for javac. If this is specified multiple times, ' |
190 'they will all be appended to construct the classpath.') | 129 'they will all be appended to construct the classpath.') |
191 parser.add_option( | 130 parser.add_option( |
192 '--classpath', | 131 '--classpath', |
193 action='append', | 132 action='append', |
194 help='Classpath for javac. If this is specified multiple times, they ' | 133 help='Classpath for javac. If this is specified multiple times, they ' |
195 'will all be appended to construct the classpath.') | 134 'will all be appended to construct the classpath.') |
196 parser.add_option( | 135 parser.add_option( |
197 '--javac-includes', | 136 '--javac-includes', |
| 137 default='', |
198 help='A list of file patterns. If provided, only java files that match' | 138 help='A list of file patterns. If provided, only java files that match' |
199 'one of the patterns will be compiled.') | 139 'one of the patterns will be compiled.') |
200 parser.add_option( | 140 parser.add_option( |
201 '--jar-excluded-classes', | 141 '--jar-excluded-classes', |
202 default='', | 142 default='', |
203 help='List of .class file patterns to exclude from the jar.') | 143 help='List of .class file patterns to exclude from the jar.') |
204 | 144 |
205 parser.add_option( | 145 parser.add_option( |
206 '--chromium-code', | 146 '--chromium-code', |
207 type='int', | 147 type='int', |
208 help='Whether code being compiled should be built with stricter ' | 148 help='Whether code being compiled should be built with stricter ' |
209 'warnings for chromium code.') | 149 'warnings for chromium code.') |
210 | 150 |
211 parser.add_option( | 151 parser.add_option( |
212 '--use-errorprone-path', | 152 '--use-errorprone-path', |
213 help='Use the Errorprone compiler at this path.') | 153 help='Use the Errorprone compiler at this path.') |
214 | 154 |
215 parser.add_option( | |
216 '--classes-dir', | |
217 help='Directory for compiled .class files.') | |
218 parser.add_option('--jar-path', help='Jar output path.') | 155 parser.add_option('--jar-path', help='Jar output path.') |
219 parser.add_option( | 156 parser.add_option( |
220 '--main-class', | 157 '--main-class', |
221 help='The class containing the main method.') | 158 help='The class containing the main method.') |
222 parser.add_option( | 159 parser.add_option( |
223 '--manifest-entry', | 160 '--manifest-entry', |
224 action='append', | 161 action='append', |
225 help='Key:value pairs to add to the .jar manifest.') | 162 help='Key:value pairs to add to the .jar manifest.') |
226 | 163 |
227 parser.add_option('--stamp', help='Path to touch on success.') | 164 parser.add_option('--stamp', help='Path to touch on success.') |
228 | 165 |
229 options, args = parser.parse_args(argv) | 166 options, args = parser.parse_args(argv) |
230 | 167 build_utils.CheckOptions(options, parser, required=('jar_path',)) |
231 if options.main_class and not options.jar_path: | |
232 parser.error('--main-class requires --jar-path') | |
233 | 168 |
234 bootclasspath = [] | 169 bootclasspath = [] |
235 for arg in options.bootclasspath: | 170 for arg in options.bootclasspath: |
236 bootclasspath += build_utils.ParseGypList(arg) | 171 bootclasspath += build_utils.ParseGypList(arg) |
| 172 options.bootclasspath = bootclasspath |
237 | 173 |
238 classpath = [] | 174 classpath = [] |
239 for arg in options.classpath: | 175 for arg in options.classpath: |
240 classpath += build_utils.ParseGypList(arg) | 176 classpath += build_utils.ParseGypList(arg) |
| 177 options.classpath = classpath |
241 | 178 |
242 java_srcjars = [] | 179 java_srcjars = [] |
243 for arg in options.java_srcjars: | 180 for arg in options.java_srcjars: |
244 java_srcjars += build_utils.ParseGypList(arg) | 181 java_srcjars += build_utils.ParseGypList(arg) |
| 182 options.java_srcjars = java_srcjars |
245 | 183 |
246 java_files = args | |
247 if options.src_gendirs: | 184 if options.src_gendirs: |
248 src_gendirs = build_utils.ParseGypList(options.src_gendirs) | 185 options.src_gendirs = build_utils.ParseGypList(options.src_gendirs) |
249 java_files += build_utils.FindInDirectories(src_gendirs, '*.java') | |
250 | 186 |
251 input_files = bootclasspath + classpath + java_srcjars + java_files | 187 options.javac_includes = build_utils.ParseGypList(options.javac_includes) |
252 with build_utils.TempDir() as temp_dir: | 188 options.jar_excluded_classes = ( |
253 classes_dir = os.path.join(temp_dir, 'classes') | 189 build_utils.ParseGypList(options.jar_excluded_classes)) |
254 os.makedirs(classes_dir) | 190 return options, args |
255 if java_srcjars: | |
256 java_dir = os.path.join(temp_dir, 'java') | |
257 os.makedirs(java_dir) | |
258 for srcjar in java_srcjars: | |
259 build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java') | |
260 java_files += build_utils.FindInDirectory(java_dir, '*.java') | |
261 | 191 |
262 if options.javac_includes: | |
263 javac_includes = build_utils.ParseGypList(options.javac_includes) | |
264 filtered_java_files = [] | |
265 for f in java_files: | |
266 for include in javac_includes: | |
267 if fnmatch.fnmatch(f, include): | |
268 filtered_java_files.append(f) | |
269 break | |
270 java_files = filtered_java_files | |
271 | 192 |
272 if len(java_files) != 0: | 193 def main(argv): |
273 DoJavac( | 194 colorama.init() |
274 bootclasspath, | |
275 classpath, | |
276 classes_dir, | |
277 options.chromium_code, | |
278 options.use_errorprone_path, | |
279 java_files) | |
280 | 195 |
281 if options.jar_path: | 196 argv = build_utils.ExpandFileArgs(argv) |
| 197 options, java_files = _ParseOptions(argv) |
| 198 |
| 199 if options.src_gendirs: |
| 200 java_files += build_utils.FindInDirectories(options.src_gendirs, '*.java') |
| 201 |
| 202 java_files = _FilterJavaFiles(java_files, options.javac_includes) |
| 203 |
| 204 javac_args = [ |
| 205 '-g', |
| 206 # Chromium only allows UTF8 source files. Being explicit avoids |
| 207 # javac pulling a default encoding from the user's environment. |
| 208 '-encoding', 'UTF-8', |
| 209 '-classpath', ':'.join(options.classpath), |
| 210 ] |
| 211 |
| 212 if options.bootclasspath: |
| 213 javac_args.extend([ |
| 214 '-bootclasspath', ':'.join(options.bootclasspath), |
| 215 '-source', '1.7', |
| 216 '-target', '1.7', |
| 217 ]) |
| 218 |
| 219 if options.chromium_code: |
| 220 # TODO(aurimas): re-enable '-Xlint:deprecation' checks once they are fixed. |
| 221 javac_args.extend(['-Xlint:unchecked']) |
| 222 else: |
| 223 # XDignore.symbol.file makes javac compile against rt.jar instead of |
| 224 # ct.sym. This means that using a java internal package/class will not |
| 225 # trigger a compile warning or error. |
| 226 javac_args.extend(['-XDignore.symbol.file']) |
| 227 |
| 228 javac_cmd = ['javac'] |
| 229 if options.use_errorprone_path: |
| 230 javac_cmd = [options.use_errorprone_path] + ERRORPRONE_OPTIONS |
| 231 |
| 232 # Compute the list of paths that when changed, we need to rebuild. |
| 233 input_paths = options.bootclasspath + options.java_srcjars + java_files |
| 234 for path in options.classpath: |
| 235 if os.path.exists(path + '.TOC'): |
| 236 input_paths.append(path + '.TOC') |
| 237 else: |
| 238 input_paths.append(path) |
| 239 python_deps = build_utils.GetPythonDependencies() |
| 240 |
| 241 def OnStaleMd5(): |
| 242 with build_utils.TempDir() as temp_dir: |
| 243 if options.java_srcjars: |
| 244 java_dir = os.path.join(temp_dir, 'java') |
| 245 os.makedirs(java_dir) |
| 246 for srcjar in options.java_srcjars: |
| 247 build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java') |
| 248 jar_srcs = build_utils.FindInDirectory(java_dir, '*.java') |
| 249 java_files.extend(_FilterJavaFiles(jar_srcs, options.javac_includes)) |
| 250 |
| 251 if not java_files: |
| 252 return |
| 253 |
| 254 classes_dir = os.path.join(temp_dir, 'classes') |
| 255 os.makedirs(classes_dir) |
| 256 # Don't include the output directory in the initial set of args since it |
| 257 # being in a temp dir makes it unstable (breaks md5 stamping). |
| 258 cmd = javac_cmd + javac_args + ['-d', classes_dir] + java_files |
| 259 |
| 260 build_utils.CheckOutput( |
| 261 cmd, |
| 262 print_stdout=options.chromium_code, |
| 263 stderr_filter=ColorJavacOutput) |
| 264 |
282 if options.main_class or options.manifest_entry: | 265 if options.main_class or options.manifest_entry: |
| 266 entries = [] |
283 if options.manifest_entry: | 267 if options.manifest_entry: |
284 entries = map(lambda e: e.split(":"), options.manifest_entry) | 268 entries = [e.split(':') for e in options.manifest_entry] |
285 else: | |
286 entries = [] | |
287 manifest_file = os.path.join(temp_dir, 'manifest') | 269 manifest_file = os.path.join(temp_dir, 'manifest') |
288 CreateManifest(manifest_file, classpath, options.main_class, entries) | 270 _CreateManifest(manifest_file, options.classpath, options.main_class, |
| 271 entries) |
289 else: | 272 else: |
290 manifest_file = None | 273 manifest_file = None |
291 jar.JarDirectory(classes_dir, | 274 jar.JarDirectory(classes_dir, |
292 build_utils.ParseGypList(options.jar_excluded_classes), | 275 options.jar_excluded_classes, |
293 options.jar_path, | 276 options.jar_path, |
294 manifest_file=manifest_file) | 277 manifest_file=manifest_file) |
295 | 278 |
296 if options.classes_dir: | 279 if options.stamp: |
297 # Delete the old classes directory. This ensures that all .class files in | 280 build_utils.Touch(options.stamp) |
298 # the output are actually from the input .java files. For example, if a | |
299 # .java file is deleted or an inner class is removed, the classes | |
300 # directory should not contain the corresponding old .class file after | |
301 # running this action. | |
302 build_utils.DeleteDirectory(options.classes_dir) | |
303 shutil.copytree(classes_dir, options.classes_dir) | |
304 | 281 |
305 if options.depfile: | 282 if options.depfile: |
306 build_utils.WriteDepfile( | 283 build_utils.WriteDepfile(options.depfile, input_paths + python_deps) |
307 options.depfile, | |
308 input_files + build_utils.GetPythonDependencies()) | |
309 | 284 |
310 if options.stamp: | 285 |
311 build_utils.Touch(options.stamp) | 286 # List python deps in input_strings rather than input_paths since the contents |
| 287 # of them does not change what gets written to the depsfile. |
| 288 md5_check.CallAndRecordIfStale( |
| 289 OnStaleMd5, |
| 290 record_path=options.jar_path + '.javac.md5.stamp', |
| 291 input_paths=input_paths, |
| 292 input_strings=javac_cmd + javac_args + python_deps, |
| 293 force=not os.path.exists(options.jar_path)) |
| 294 |
312 | 295 |
313 | 296 |
314 if __name__ == '__main__': | 297 if __name__ == '__main__': |
315 sys.exit(main(sys.argv[1:])) | 298 sys.exit(main(sys.argv[1:])) |
316 | 299 |
317 | 300 |
OLD | NEW |