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
5 # found in the LICENSE file.
14 from util
import build_utils
15 from util
import md5_check
19 sys
.path
.append(build_utils
.COLORAMA_ROOT
)
23 def ColorJavacOutput(output
):
24 fileline_prefix
= r
'(?P<fileline>(?P<file>[-.\w/\\]+.java):(?P<line>[0-9]+):)'
25 warning_re
= re
.compile(
26 fileline_prefix
+ r
'(?P<full_message> warning: (?P<message>.*))$')
27 error_re
= re
.compile(
28 fileline_prefix
+ r
'(?P<full_message> (?P<message>.*))$')
29 marker_re
= re
.compile(r
'\s*(?P<marker>\^)\s*$')
31 warning_color
= ['full_message', colorama
.Fore
.YELLOW
+ colorama
.Style
.DIM
]
32 error_color
= ['full_message', colorama
.Fore
.MAGENTA
+ colorama
.Style
.BRIGHT
]
33 marker_color
= ['marker', colorama
.Fore
.BLUE
+ colorama
.Style
.BRIGHT
]
35 def Colorize(line
, regex
, color
):
36 match
= regex
.match(line
)
37 start
= match
.start(color
[0])
38 end
= match
.end(color
[0])
40 + color
[1] + line
[start
:end
]
41 + colorama
.Fore
.RESET
+ colorama
.Style
.RESET_ALL
45 if warning_re
.match(line
):
46 line
= Colorize(line
, warning_re
, warning_color
)
47 elif error_re
.match(line
):
48 line
= Colorize(line
, error_re
, error_color
)
49 elif marker_re
.match(line
):
50 line
= Colorize(line
, marker_re
, marker_color
)
53 return '\n'.join(map(ApplyColor
, output
.split('\n')))
56 ERRORPRONE_OPTIONS
= [
57 # These crash on lots of targets.
58 '-Xep:ParameterPackage:OFF',
59 '-Xep:OverridesGuiceInjectableMethod:OFF',
60 '-Xep:OverridesJavaxInjectableMethod:OFF',
64 def _FilterJavaFiles(paths
, filters
):
65 return [f
for f
in paths
66 if not filters
or build_utils
.MatchesGlob(f
, filters
)]
69 _MAX_MANIFEST_LINE_LEN
= 72
72 def _CreateManifest(manifest_path
, classpath
, main_class
=None,
73 manifest_entries
=None):
74 """Creates a manifest file with the given parameters.
76 This generates a manifest file that compiles with the spec found at
77 http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#JAR_Manifest
80 manifest_path: The path to the manifest file that should be created.
81 classpath: The JAR files that should be listed on the manifest file's
83 main_class: If present, the class containing the main() function.
84 manifest_entries: If present, a list of (key, value) pairs to add to
88 output
= ['Manifest-Version: 1.0']
90 output
.append('Main-Class: %s' % main_class
)
92 for k
, v
in manifest_entries
:
93 output
.append('%s: %s' % (k
, v
))
96 for path
in classpath
:
97 sanitized_paths
.append(os
.path
.basename(path
.strip('"')))
98 output
.append('Class-Path: %s' % ' '.join(sanitized_paths
))
99 output
.append('Created-By: ')
102 wrapper
= textwrap
.TextWrapper(break_long_words
=True,
103 drop_whitespace
=False,
104 subsequent_indent
=' ',
105 width
=_MAX_MANIFEST_LINE_LEN
- 2)
106 output
= '\r\n'.join(w
for l
in output
for w
in wrapper
.wrap(l
))
108 with
open(manifest_path
, 'w') as f
:
112 def _ParseOptions(argv
):
113 parser
= optparse
.OptionParser()
114 build_utils
.AddDepfileOption(parser
)
118 help='Directories containing generated java files.')
123 help='List of srcjars to include in compilation.')
128 help='Boot classpath for javac. If this is specified multiple times, '
129 'they will all be appended to construct the classpath.')
133 help='Classpath for javac. If this is specified multiple times, they '
134 'will all be appended to construct the classpath.')
138 help='Whether to use interface jars (.interface.jar) when compiling')
142 help='A list of file patterns. If provided, only java files that match'
143 'one of the patterns will be compiled.')
145 '--jar-excluded-classes',
147 help='List of .class file patterns to exclude from the jar.')
152 help='Whether code being compiled should be built with stricter '
153 'warnings for chromium code.')
156 '--use-errorprone-path',
157 help='Use the Errorprone compiler at this path.')
159 parser
.add_option('--jar-path', help='Jar output path.')
162 help='The class containing the main method.')
166 help='Key:value pairs to add to the .jar manifest.')
168 parser
.add_option('--stamp', help='Path to touch on success.')
170 options
, args
= parser
.parse_args(argv
)
171 build_utils
.CheckOptions(options
, parser
, required
=('jar_path',))
174 for arg
in options
.bootclasspath
:
175 bootclasspath
+= build_utils
.ParseGypList(arg
)
176 options
.bootclasspath
= bootclasspath
179 for arg
in options
.classpath
:
180 classpath
+= build_utils
.ParseGypList(arg
)
181 options
.classpath
= classpath
184 for arg
in options
.java_srcjars
:
185 java_srcjars
+= build_utils
.ParseGypList(arg
)
186 options
.java_srcjars
= java_srcjars
188 if options
.src_gendirs
:
189 options
.src_gendirs
= build_utils
.ParseGypList(options
.src_gendirs
)
191 options
.javac_includes
= build_utils
.ParseGypList(options
.javac_includes
)
192 options
.jar_excluded_classes
= (
193 build_utils
.ParseGypList(options
.jar_excluded_classes
))
200 argv
= build_utils
.ExpandFileArgs(argv
)
201 options
, java_files
= _ParseOptions(argv
)
203 if options
.src_gendirs
:
204 java_files
+= build_utils
.FindInDirectories(options
.src_gendirs
, '*.java')
206 java_files
= _FilterJavaFiles(java_files
, options
.javac_includes
)
208 runtime_classpath
= options
.classpath
209 compile_classpath
= runtime_classpath
210 if options
.use_ijars
:
211 ijar_re
= re
.compile(r
'\.jar$')
212 compile_classpath
= (
213 [ijar_re
.sub('.interface.jar', p
) for p
in runtime_classpath
])
217 # Chromium only allows UTF8 source files. Being explicit avoids
218 # javac pulling a default encoding from the user's environment.
219 '-encoding', 'UTF-8',
220 '-classpath', ':'.join(compile_classpath
),
223 if options
.bootclasspath
:
225 '-bootclasspath', ':'.join(options
.bootclasspath
),
230 if options
.chromium_code
:
231 # TODO(aurimas): re-enable '-Xlint:deprecation' checks once they are fixed.
232 javac_args
.extend(['-Xlint:unchecked'])
234 # XDignore.symbol.file makes javac compile against rt.jar instead of
235 # ct.sym. This means that using a java internal package/class will not
236 # trigger a compile warning or error.
237 javac_args
.extend(['-XDignore.symbol.file'])
239 javac_cmd
= ['javac']
240 if options
.use_errorprone_path
:
241 javac_cmd
= [options
.use_errorprone_path
] + ERRORPRONE_OPTIONS
243 # Compute the list of paths that when changed, we need to rebuild.
244 input_paths
= options
.bootclasspath
+ options
.java_srcjars
+ java_files
245 # TODO(agrieve): Remove this .TOC heuristic once GYP is no more.
246 if not options
.use_ijars
:
247 for path
in compile_classpath
:
248 if os
.path
.exists(path
+ '.TOC'):
249 input_paths
.append(path
+ '.TOC')
251 input_paths
.append(path
)
252 python_deps
= build_utils
.GetPythonDependencies()
255 with build_utils
.TempDir() as temp_dir
:
256 if options
.java_srcjars
:
257 java_dir
= os
.path
.join(temp_dir
, 'java')
258 os
.makedirs(java_dir
)
259 for srcjar
in options
.java_srcjars
:
260 build_utils
.ExtractAll(srcjar
, path
=java_dir
, pattern
='*.java')
261 jar_srcs
= build_utils
.FindInDirectory(java_dir
, '*.java')
262 java_files
.extend(_FilterJavaFiles(jar_srcs
, options
.javac_includes
))
264 classes_dir
= os
.path
.join(temp_dir
, 'classes')
265 os
.makedirs(classes_dir
)
268 # Don't include the output directory in the initial set of args since it
269 # being in a temp dir makes it unstable (breaks md5 stamping).
270 cmd
= javac_cmd
+ javac_args
+ ['-d', classes_dir
] + java_files
272 build_utils
.CheckOutput(
274 print_stdout
=options
.chromium_code
,
275 stderr_filter
=ColorJavacOutput
)
277 if options
.main_class
or options
.manifest_entry
:
279 if options
.manifest_entry
:
280 entries
= [e
.split(':') for e
in options
.manifest_entry
]
281 manifest_file
= os
.path
.join(temp_dir
, 'manifest')
282 _CreateManifest(manifest_file
, runtime_classpath
, options
.main_class
,
286 jar
.JarDirectory(classes_dir
,
287 options
.jar_excluded_classes
,
289 manifest_file
=manifest_file
)
292 build_utils
.Touch(options
.stamp
)
295 build_utils
.WriteDepfile(options
.depfile
, input_paths
+ python_deps
)
298 # List python deps in input_strings rather than input_paths since the contents
299 # of them does not change what gets written to the depsfile.
300 md5_check
.CallAndRecordIfStale(
302 record_path
=options
.jar_path
+ '.javac.md5.stamp',
303 input_paths
=input_paths
,
304 input_strings
=javac_cmd
+ javac_args
+ python_deps
,
305 force
=not os
.path
.exists(options
.jar_path
))
309 if __name__
== '__main__':
310 sys
.exit(main(sys
.argv
[1:]))