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
)
77 '-classpath', ':'.join(classpath
),
80 javac_args
.extend(['-Xlint:unchecked', '-Xlint:deprecation'])
82 # XDignore.symbol.file makes javac compile against rt.jar instead of
83 # ct.sym. This means that using a java internal package/class will not
84 # trigger a compile warning or error.
85 javac_args
.extend(['-XDignore.symbol.file'])
87 javac_cmd
= ['javac'] + javac_args
+ java_files
90 build_utils
.CheckOutput(
92 print_stdout
=chromium_code
,
93 stderr_filter
=ColorJavacOutput
)
95 record_path
= os
.path
.join(classes_dir
, 'javac.md5.stamp')
96 md5_check
.CallAndRecordIfStale(
98 record_path
=record_path
,
99 input_paths
=java_files
+ jar_inputs
,
100 input_strings
=javac_cmd
)
103 _MAX_MANIFEST_LINE_LEN
= 72
106 def CreateManifest(manifest_path
, classpath
, main_class
=None):
107 """Creates a manifest file with the given parameters.
109 This generates a manifest file that compiles with the spec found at
110 http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#JAR_Manifest
113 manifest_path: The path to the manifest file that should be created.
114 classpath: The JAR files that should be listed on the manifest file's
116 main_class: If present, the class containing the main() function.
119 output
= ['Manifest-Version: 1.0']
121 output
.append('Main-Class: %s' % main_class
)
124 for path
in classpath
:
125 sanitized_paths
.append(os
.path
.basename(path
.strip('"')))
126 output
.append('Class-Path: %s' % ' '.join(sanitized_paths
))
127 output
.append('Created-By: ')
130 wrapper
= textwrap
.TextWrapper(break_long_words
=True,
131 drop_whitespace
=False,
132 subsequent_indent
=' ',
133 width
=_MAX_MANIFEST_LINE_LEN
- 2)
134 output
= '\r\n'.join(w
for l
in output
for w
in wrapper
.wrap(l
))
136 with
open(manifest_path
, 'w') as f
:
143 argv
= build_utils
.ExpandFileArgs(argv
)
145 parser
= optparse
.OptionParser()
146 build_utils
.AddDepfileOption(parser
)
150 help='Directories containing generated java files.')
155 help='List of srcjars to include in compilation.')
159 help='Classpath for javac. If this is specified multiple times, they '
160 'will all be appended to construct the classpath.')
163 help='A list of file patterns. If provided, only java files that match'
164 'one of the patterns will be compiled.')
166 '--jar-excluded-classes',
168 help='List of .class file patterns to exclude from the jar.')
173 help='Whether code being compiled should be built with stricter '
174 'warnings for chromium code.')
178 help='Directory for compiled .class files.')
179 parser
.add_option('--jar-path', help='Jar output path.')
182 help='The class containing the main method.')
184 parser
.add_option('--stamp', help='Path to touch on success.')
186 options
, args
= parser
.parse_args(argv
)
188 if options
.main_class
and not options
.jar_path
:
189 parser
.error('--main-class requires --jar-path')
192 for arg
in options
.classpath
:
193 classpath
+= build_utils
.ParseGypList(arg
)
196 for arg
in options
.java_srcjars
:
197 java_srcjars
+= build_utils
.ParseGypList(arg
)
200 if options
.src_gendirs
:
201 src_gendirs
= build_utils
.ParseGypList(options
.src_gendirs
)
202 java_files
+= build_utils
.FindInDirectories(src_gendirs
, '*.java')
204 input_files
= classpath
+ java_srcjars
+ java_files
205 with build_utils
.TempDir() as temp_dir
:
206 classes_dir
= os
.path
.join(temp_dir
, 'classes')
207 os
.makedirs(classes_dir
)
209 java_dir
= os
.path
.join(temp_dir
, 'java')
210 os
.makedirs(java_dir
)
211 for srcjar
in java_srcjars
:
212 build_utils
.ExtractAll(srcjar
, path
=java_dir
, pattern
='*.java')
213 java_files
+= build_utils
.FindInDirectory(java_dir
, '*.java')
215 if options
.javac_includes
:
216 javac_includes
= build_utils
.ParseGypList(options
.javac_includes
)
217 filtered_java_files
= []
219 for include
in javac_includes
:
220 if fnmatch
.fnmatch(f
, include
):
221 filtered_java_files
.append(f
)
223 java_files
= filtered_java_files
228 options
.chromium_code
,
232 if options
.main_class
:
233 manifest_file
= os
.path
.join(temp_dir
, 'manifest')
234 CreateManifest(manifest_file
, classpath
,
238 jar
.JarDirectory(classes_dir
,
239 build_utils
.ParseGypList(options
.jar_excluded_classes
),
241 manifest_file
=manifest_file
)
243 if options
.classes_dir
:
244 # Delete the old classes directory. This ensures that all .class files in
245 # the output are actually from the input .java files. For example, if a
246 # .java file is deleted or an inner class is removed, the classes
247 # directory should not contain the corresponding old .class file after
248 # running this action.
249 build_utils
.DeleteDirectory(options
.classes_dir
)
250 shutil
.copytree(classes_dir
, options
.classes_dir
)
253 build_utils
.WriteDepfile(
255 input_files
+ build_utils
.GetPythonDependencies())
258 build_utils
.Touch(options
.stamp
)
261 if __name__
== '__main__':
262 sys
.exit(main(sys
.argv
[1:]))