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.
15 from util
import build_utils
16 from util
import md5_check
20 sys
.path
.append(build_utils
.COLORAMA_ROOT
)
24 def ColorJavacOutput(output
):
25 fileline_prefix
= r
'(?P<fileline>(?P<file>[-.\w/\\]+.java):(?P<line>[0-9]+):)'
26 warning_re
= re
.compile(
27 fileline_prefix
+ r
'(?P<full_message> warning: (?P<message>.*))$')
28 error_re
= re
.compile(
29 fileline_prefix
+ r
'(?P<full_message> (?P<message>.*))$')
30 marker_re
= re
.compile(r
'\s*(?P<marker>\^)\s*$')
32 warning_color
= ['full_message', colorama
.Fore
.YELLOW
+ colorama
.Style
.DIM
]
33 error_color
= ['full_message', colorama
.Fore
.MAGENTA
+ colorama
.Style
.BRIGHT
]
34 marker_color
= ['marker', colorama
.Fore
.BLUE
+ colorama
.Style
.BRIGHT
]
36 def Colorize(line
, regex
, color
):
37 match
= regex
.match(line
)
38 start
= match
.start(color
[0])
39 end
= match
.end(color
[0])
41 + color
[1] + line
[start
:end
]
42 + colorama
.Fore
.RESET
+ colorama
.Style
.RESET_ALL
46 if warning_re
.match(line
):
47 line
= Colorize(line
, warning_re
, warning_color
)
48 elif error_re
.match(line
):
49 line
= Colorize(line
, error_re
, error_color
)
50 elif marker_re
.match(line
):
51 line
= Colorize(line
, marker_re
, marker_color
)
54 return '\n'.join(map(ApplyColor
, output
.split('\n')))
57 ERRORPRONE_OPTIONS
= [
59 # Something in chrome_private_java makes this check crash.
60 'com.google.errorprone.bugpatterns.ClassCanBeStatic,'
61 # These crash on lots of targets.
62 'com.google.errorprone.bugpatterns.WrongParameterPackage,'
63 'com.google.errorprone.bugpatterns.GuiceOverridesGuiceInjectableMethod,'
64 'com.google.errorprone.bugpatterns.GuiceOverridesJavaxInjectableMethod,'
65 'com.google.errorprone.bugpatterns.ElementsCountedInLoop'
69 bootclasspath
, classpath
, classes_dir
, chromium_code
,
70 use_errorprone_path
, java_files
):
73 Builds |java_files| with the provided |classpath| and puts the generated
74 .class files into |classes_dir|. If |chromium_code| is true, extra lint
75 checking will be enabled.
79 for path
in classpath
:
80 if os
.path
.exists(path
+ '.TOC'):
81 jar_inputs
.append(path
+ '.TOC')
83 jar_inputs
.append(path
)
87 # Chromium only allows UTF8 source files. Being explicit avoids
88 # javac pulling a default encoding from the user's environment.
90 '-classpath', ':'.join(classpath
),
95 '-bootclasspath', ':'.join(bootclasspath
),
101 # TODO(aurimas): re-enable '-Xlint:deprecation' checks once they are fixed.
102 javac_args
.extend(['-Xlint:unchecked'])
104 # XDignore.symbol.file makes javac compile against rt.jar instead of
105 # ct.sym. This means that using a java internal package/class will not
106 # trigger a compile warning or error.
107 javac_args
.extend(['-XDignore.symbol.file'])
109 if use_errorprone_path
:
110 javac_cmd
= [use_errorprone_path
] + ERRORPRONE_OPTIONS
112 javac_cmd
= ['javac']
114 javac_cmd
= javac_cmd
+ javac_args
+ java_files
117 build_utils
.CheckOutput(
119 print_stdout
=chromium_code
,
120 stderr_filter
=ColorJavacOutput
)
122 record_path
= os
.path
.join(classes_dir
, 'javac.md5.stamp')
123 md5_check
.CallAndRecordIfStale(
125 record_path
=record_path
,
126 input_paths
=java_files
+ jar_inputs
,
127 input_strings
=javac_cmd
)
130 _MAX_MANIFEST_LINE_LEN
= 72
133 def CreateManifest(manifest_path
, classpath
, main_class
=None,
134 manifest_entries
=None):
135 """Creates a manifest file with the given parameters.
137 This generates a manifest file that compiles with the spec found at
138 http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#JAR_Manifest
141 manifest_path: The path to the manifest file that should be created.
142 classpath: The JAR files that should be listed on the manifest file's
144 main_class: If present, the class containing the main() function.
145 manifest_entries: If present, a list of (key, value) pairs to add to
149 output
= ['Manifest-Version: 1.0']
151 output
.append('Main-Class: %s' % main_class
)
153 for k
, v
in manifest_entries
:
154 output
.append('%s: %s' % (k
, v
))
157 for path
in classpath
:
158 sanitized_paths
.append(os
.path
.basename(path
.strip('"')))
159 output
.append('Class-Path: %s' % ' '.join(sanitized_paths
))
160 output
.append('Created-By: ')
163 wrapper
= textwrap
.TextWrapper(break_long_words
=True,
164 drop_whitespace
=False,
165 subsequent_indent
=' ',
166 width
=_MAX_MANIFEST_LINE_LEN
- 2)
167 output
= '\r\n'.join(w
for l
in output
for w
in wrapper
.wrap(l
))
169 with
open(manifest_path
, 'w') as f
:
176 argv
= build_utils
.ExpandFileArgs(argv
)
178 parser
= optparse
.OptionParser()
179 build_utils
.AddDepfileOption(parser
)
183 help='Directories containing generated java files.')
188 help='List of srcjars to include in compilation.')
193 help='Boot classpath for javac. If this is specified multiple times, '
194 'they will all be appended to construct the classpath.')
198 help='Classpath for javac. If this is specified multiple times, they '
199 'will all be appended to construct the classpath.')
202 help='A list of file patterns. If provided, only java files that match'
203 'one of the patterns will be compiled.')
205 '--jar-excluded-classes',
207 help='List of .class file patterns to exclude from the jar.')
212 help='Whether code being compiled should be built with stricter '
213 'warnings for chromium code.')
216 '--use-errorprone-path',
217 help='Use the Errorprone compiler at this path.')
221 help='Directory for compiled .class files.')
222 parser
.add_option('--jar-path', help='Jar output path.')
225 help='The class containing the main method.')
229 help='Key:value pairs to add to the .jar manifest.')
231 parser
.add_option('--stamp', help='Path to touch on success.')
233 options
, args
= parser
.parse_args(argv
)
235 if options
.main_class
and not options
.jar_path
:
236 parser
.error('--main-class requires --jar-path')
239 for arg
in options
.bootclasspath
:
240 bootclasspath
+= build_utils
.ParseGypList(arg
)
243 for arg
in options
.classpath
:
244 classpath
+= build_utils
.ParseGypList(arg
)
247 for arg
in options
.java_srcjars
:
248 java_srcjars
+= build_utils
.ParseGypList(arg
)
251 if options
.src_gendirs
:
252 src_gendirs
= build_utils
.ParseGypList(options
.src_gendirs
)
253 java_files
+= build_utils
.FindInDirectories(src_gendirs
, '*.java')
255 input_files
= bootclasspath
+ classpath
+ java_srcjars
+ java_files
256 with build_utils
.TempDir() as temp_dir
:
257 classes_dir
= os
.path
.join(temp_dir
, 'classes')
258 os
.makedirs(classes_dir
)
260 java_dir
= os
.path
.join(temp_dir
, 'java')
261 os
.makedirs(java_dir
)
262 for srcjar
in java_srcjars
:
263 build_utils
.ExtractAll(srcjar
, path
=java_dir
, pattern
='*.java')
264 java_files
+= build_utils
.FindInDirectory(java_dir
, '*.java')
266 if options
.javac_includes
:
267 javac_includes
= build_utils
.ParseGypList(options
.javac_includes
)
268 filtered_java_files
= []
270 for include
in javac_includes
:
271 if fnmatch
.fnmatch(f
, include
):
272 filtered_java_files
.append(f
)
274 java_files
= filtered_java_files
276 if len(java_files
) != 0:
281 options
.chromium_code
,
282 options
.use_errorprone_path
,
286 if options
.main_class
or options
.manifest_entry
:
287 if options
.manifest_entry
:
288 entries
= map(lambda e
: e
.split(":"), options
.manifest_entry
)
291 manifest_file
= os
.path
.join(temp_dir
, 'manifest')
292 CreateManifest(manifest_file
, classpath
, options
.main_class
, entries
)
295 jar
.JarDirectory(classes_dir
,
296 build_utils
.ParseGypList(options
.jar_excluded_classes
),
298 manifest_file
=manifest_file
)
300 if options
.classes_dir
:
301 # Delete the old classes directory. This ensures that all .class files in
302 # the output are actually from the input .java files. For example, if a
303 # .java file is deleted or an inner class is removed, the classes
304 # directory should not contain the corresponding old .class file after
305 # running this action.
306 build_utils
.DeleteDirectory(options
.classes_dir
)
307 shutil
.copytree(classes_dir
, options
.classes_dir
)
310 build_utils
.WriteDepfile(
312 input_files
+ build_utils
.GetPythonDependencies())
315 build_utils
.Touch(options
.stamp
)
318 if __name__
== '__main__':
319 sys
.exit(main(sys
.argv
[1:]))