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')))
58 classpath
, classes_dir
, chromium_code
, java_files
):
61 Builds |java_files| with the provided |classpath| and puts the generated
62 .class files into |classes_dir|. If |chromium_code| is true, extra lint
63 checking will be enabled.
67 for path
in classpath
:
68 if os
.path
.exists(path
+ '.TOC'):
69 jar_inputs
.append(path
+ '.TOC')
71 jar_inputs
.append(path
)
75 # Chromium only allows UTF8 source files. Being explicit avoids
76 # javac pulling a default encoding from the user's environment.
80 '-classpath', ':'.join(classpath
),
83 # TODO(aurimas): re-enable '-Xlint:deprecation' checks once they are fixed.
84 javac_args
.extend(['-Xlint:unchecked'])
86 # XDignore.symbol.file makes javac compile against rt.jar instead of
87 # ct.sym. This means that using a java internal package/class will not
88 # trigger a compile warning or error.
89 javac_args
.extend(['-XDignore.symbol.file'])
91 javac_cmd
= ['javac'] + javac_args
+ java_files
94 build_utils
.CheckOutput(
96 print_stdout
=chromium_code
,
97 stderr_filter
=ColorJavacOutput
)
99 record_path
= os
.path
.join(classes_dir
, 'javac.md5.stamp')
100 md5_check
.CallAndRecordIfStale(
102 record_path
=record_path
,
103 input_paths
=java_files
+ jar_inputs
,
104 input_strings
=javac_cmd
)
107 _MAX_MANIFEST_LINE_LEN
= 72
110 def CreateManifest(manifest_path
, classpath
, main_class
=None,
111 manifest_entries
=None):
112 """Creates a manifest file with the given parameters.
114 This generates a manifest file that compiles with the spec found at
115 http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#JAR_Manifest
118 manifest_path: The path to the manifest file that should be created.
119 classpath: The JAR files that should be listed on the manifest file's
121 main_class: If present, the class containing the main() function.
122 manifest_entries: If present, a list of (key, value) pairs to add to
126 output
= ['Manifest-Version: 1.0']
128 output
.append('Main-Class: %s' % main_class
)
130 for k
, v
in manifest_entries
:
131 output
.append('%s: %s' % (k
, v
))
134 for path
in classpath
:
135 sanitized_paths
.append(os
.path
.basename(path
.strip('"')))
136 output
.append('Class-Path: %s' % ' '.join(sanitized_paths
))
137 output
.append('Created-By: ')
140 wrapper
= textwrap
.TextWrapper(break_long_words
=True,
141 drop_whitespace
=False,
142 subsequent_indent
=' ',
143 width
=_MAX_MANIFEST_LINE_LEN
- 2)
144 output
= '\r\n'.join(w
for l
in output
for w
in wrapper
.wrap(l
))
146 with
open(manifest_path
, 'w') as f
:
153 argv
= build_utils
.ExpandFileArgs(argv
)
155 parser
= optparse
.OptionParser()
156 build_utils
.AddDepfileOption(parser
)
160 help='Directories containing generated java files.')
165 help='List of srcjars to include in compilation.')
169 help='Classpath for javac. If this is specified multiple times, they '
170 'will all be appended to construct the classpath.')
173 help='A list of file patterns. If provided, only java files that match'
174 'one of the patterns will be compiled.')
176 '--jar-excluded-classes',
178 help='List of .class file patterns to exclude from the jar.')
183 help='Whether code being compiled should be built with stricter '
184 'warnings for chromium code.')
188 help='Directory for compiled .class files.')
189 parser
.add_option('--jar-path', help='Jar output path.')
192 help='The class containing the main method.')
196 help='Key:value pairs to add to the .jar manifest.')
198 parser
.add_option('--stamp', help='Path to touch on success.')
200 options
, args
= parser
.parse_args(argv
)
202 if options
.main_class
and not options
.jar_path
:
203 parser
.error('--main-class requires --jar-path')
206 for arg
in options
.classpath
:
207 classpath
+= build_utils
.ParseGypList(arg
)
210 for arg
in options
.java_srcjars
:
211 java_srcjars
+= build_utils
.ParseGypList(arg
)
214 if options
.src_gendirs
:
215 src_gendirs
= build_utils
.ParseGypList(options
.src_gendirs
)
216 java_files
+= build_utils
.FindInDirectories(src_gendirs
, '*.java')
218 input_files
= classpath
+ java_srcjars
+ java_files
219 with build_utils
.TempDir() as temp_dir
:
220 classes_dir
= os
.path
.join(temp_dir
, 'classes')
221 os
.makedirs(classes_dir
)
223 java_dir
= os
.path
.join(temp_dir
, 'java')
224 os
.makedirs(java_dir
)
225 for srcjar
in java_srcjars
:
226 build_utils
.ExtractAll(srcjar
, path
=java_dir
, pattern
='*.java')
227 java_files
+= build_utils
.FindInDirectory(java_dir
, '*.java')
229 if options
.javac_includes
:
230 javac_includes
= build_utils
.ParseGypList(options
.javac_includes
)
231 filtered_java_files
= []
233 for include
in javac_includes
:
234 if fnmatch
.fnmatch(f
, include
):
235 filtered_java_files
.append(f
)
237 java_files
= filtered_java_files
242 options
.chromium_code
,
246 if options
.main_class
or options
.manifest_entry
:
247 if options
.manifest_entry
:
248 entries
= map(lambda e
: e
.split(":"), options
.manifest_entry
)
251 manifest_file
= os
.path
.join(temp_dir
, 'manifest')
252 CreateManifest(manifest_file
, classpath
, options
.main_class
, entries
)
255 jar
.JarDirectory(classes_dir
,
256 build_utils
.ParseGypList(options
.jar_excluded_classes
),
258 manifest_file
=manifest_file
)
260 if options
.classes_dir
:
261 # Delete the old classes directory. This ensures that all .class files in
262 # the output are actually from the input .java files. For example, if a
263 # .java file is deleted or an inner class is removed, the classes
264 # directory should not contain the corresponding old .class file after
265 # running this action.
266 build_utils
.DeleteDirectory(options
.classes_dir
)
267 shutil
.copytree(classes_dir
, options
.classes_dir
)
270 build_utils
.WriteDepfile(
272 input_files
+ build_utils
.GetPythonDependencies())
275 build_utils
.Touch(options
.stamp
)
278 if __name__
== '__main__':
279 sys
.exit(main(sys
.argv
[1:]))