Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / build / android / gyp / javac.py
index a0725cf..6a3024b 100755 (executable)
@@ -7,12 +7,16 @@
 import fnmatch
 import optparse
 import os
+import shutil
 import re
 import sys
+import textwrap
 
 from util import build_utils
 from util import md5_check
 
+import jar
+
 sys.path.append(build_utils.COLORAMA_ROOT)
 import colorama
 
@@ -50,26 +54,14 @@ def ColorJavacOutput(output):
   return '\n'.join(map(ApplyColor, output.split('\n')))
 
 
-def DoJavac(options, args):
-  output_dir = options.output_dir
-
-  src_gendirs = build_utils.ParseGypList(options.src_gendirs)
-  java_files = args + build_utils.FindInDirectories(src_gendirs, '*.java')
-  if options.javac_includes:
-    javac_includes = build_utils.ParseGypList(options.javac_includes)
-    filtered_java_files = []
-    for f in java_files:
-      for include in javac_includes:
-        if fnmatch.fnmatch(f, include):
-          filtered_java_files.append(f)
-          break
-    java_files = filtered_java_files
+def DoJavac(
+    classpath, classes_dir, chromium_code, java_files):
+  """Runs javac.
 
-  # Compiling guava with certain orderings of input files causes a compiler
-  # crash... Sorted order works, so use that.
-  # See https://code.google.com/p/guava-libraries/issues/detail?id=950
-  java_files.sort()
-  classpath = build_utils.ParseGypList(options.classpath)
+  Builds |java_files| with the provided |classpath| and puts the generated
+  .class files into |classes_dir|. If |chromium_code| is true, extra lint
+  checking will be enabled.
+  """
 
   jar_inputs = []
   for path in classpath:
@@ -80,11 +72,11 @@ def DoJavac(options, args):
 
   javac_args = [
       '-g',
-      '-source', '1.5',
-      '-target', '1.5',
+      '-source', '1.7',
+      '-target', '1.7',
       '-classpath', ':'.join(classpath),
-      '-d', output_dir]
-  if options.chromium_code:
+      '-d', classes_dir]
+  if chromium_code:
     javac_args.extend(['-Xlint:unchecked', '-Xlint:deprecation'])
   else:
     # XDignore.symbol.file makes javac compile against rt.jar instead of
@@ -95,19 +87,12 @@ def DoJavac(options, args):
   javac_cmd = ['javac'] + javac_args + java_files
 
   def Compile():
-    # Delete the classes directory. This ensures that all .class files in the
-    # output are actually from the input .java files. For example, if a .java
-    # file is deleted or an inner class is removed, the classes directory should
-    # not contain the corresponding old .class file after running this action.
-    build_utils.DeleteDirectory(output_dir)
-    build_utils.MakeDirectory(output_dir)
     build_utils.CheckOutput(
         javac_cmd,
-        print_stdout=options.chromium_code,
+        print_stdout=chromium_code,
         stderr_filter=ColorJavacOutput)
 
-
-  record_path = '%s/javac.md5.stamp' % options.output_dir
+  record_path = os.path.join(classes_dir, 'javac.md5.stamp')
   md5_check.CallAndRecordIfStale(
       Compile,
       record_path=record_path,
@@ -115,31 +100,165 @@ def DoJavac(options, args):
       input_strings=javac_cmd)
 
 
-def main():
+_MAX_MANIFEST_LINE_LEN = 72
+
+
+def CreateManifest(manifest_path, classpath, main_class=None):
+  """Creates a manifest file with the given parameters.
+
+  This generates a manifest file that compiles with the spec found at
+  http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#JAR_Manifest
+
+  Args:
+    manifest_path: The path to the manifest file that should be created.
+    classpath: The JAR files that should be listed on the manifest file's
+      classpath.
+    main_class: If present, the class containing the main() function.
+
+  """
+  output = ['Manifest-Version: 1.0']
+  if main_class:
+    output.append('Main-Class: %s' % main_class)
+  if classpath:
+    sanitized_paths = []
+    for path in classpath:
+      sanitized_paths.append(os.path.basename(path.strip('"')))
+    output.append('Class-Path: %s' % ' '.join(sanitized_paths))
+  output.append('Created-By: ')
+  output.append('')
+
+  wrapper = textwrap.TextWrapper(break_long_words=True,
+                                 drop_whitespace=False,
+                                 subsequent_indent=' ',
+                                 width=_MAX_MANIFEST_LINE_LEN - 2)
+  output = '\r\n'.join(w for l in output for w in wrapper.wrap(l))
+
+  with open(manifest_path, 'w') as f:
+    f.write(output)
+
+
+def main(argv):
   colorama.init()
 
+  argv = build_utils.ExpandFileArgs(argv)
+
   parser = optparse.OptionParser()
-  parser.add_option('--src-gendirs',
+  build_utils.AddDepfileOption(parser)
+
+  parser.add_option(
+      '--src-gendirs',
       help='Directories containing generated java files.')
-  parser.add_option('--javac-includes',
-      help='A list of file patterns. If provided, only java files that match' +
-        'one of the patterns will be compiled.')
-  parser.add_option('--classpath', help='Classpath for javac.')
-  parser.add_option('--output-dir', help='Directory for javac output.')
+  parser.add_option(
+      '--java-srcjars',
+      action='append',
+      default=[],
+      help='List of srcjars to include in compilation.')
+  parser.add_option(
+      '--classpath',
+      action='append',
+      help='Classpath for javac. If this is specified multiple times, they '
+      'will all be appended to construct the classpath.')
+  parser.add_option(
+      '--javac-includes',
+      help='A list of file patterns. If provided, only java files that match'
+      'one of the patterns will be compiled.')
+  parser.add_option(
+      '--jar-excluded-classes',
+      default='',
+      help='List of .class file patterns to exclude from the jar.')
+
+  parser.add_option(
+      '--chromium-code',
+      type='int',
+      help='Whether code being compiled should be built with stricter '
+      'warnings for chromium code.')
+
+  parser.add_option(
+      '--classes-dir',
+      help='Directory for compiled .class files.')
+  parser.add_option('--jar-path', help='Jar output path.')
+  parser.add_option(
+      '--main-class',
+      help='The class containing the main method.')
+
   parser.add_option('--stamp', help='Path to touch on success.')
-  parser.add_option('--chromium-code', type='int', help='Whether code being '
-                    'compiled should be built with stricter warnings for '
-                    'chromium code.')
 
-  options, args = parser.parse_args()
+  options, args = parser.parse_args(argv)
+
+  if options.main_class and not options.jar_path:
+    parser.error('--main-class requires --jar-path')
+
+  classpath = []
+  for arg in options.classpath:
+    classpath += build_utils.ParseGypList(arg)
+
+  java_srcjars = []
+  for arg in options.java_srcjars:
+    java_srcjars += build_utils.ParseGypList(arg)
+
+  java_files = args
+  if options.src_gendirs:
+    src_gendirs = build_utils.ParseGypList(options.src_gendirs)
+    java_files += build_utils.FindInDirectories(src_gendirs, '*.java')
+
+  input_files = classpath + java_srcjars + java_files
+  with build_utils.TempDir() as temp_dir:
+    classes_dir = os.path.join(temp_dir, 'classes')
+    os.makedirs(classes_dir)
+    if java_srcjars:
+      java_dir = os.path.join(temp_dir, 'java')
+      os.makedirs(java_dir)
+      for srcjar in java_srcjars:
+        build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java')
+      java_files += build_utils.FindInDirectory(java_dir, '*.java')
+
+    if options.javac_includes:
+      javac_includes = build_utils.ParseGypList(options.javac_includes)
+      filtered_java_files = []
+      for f in java_files:
+        for include in javac_includes:
+          if fnmatch.fnmatch(f, include):
+            filtered_java_files.append(f)
+            break
+      java_files = filtered_java_files
+
+    DoJavac(
+        classpath,
+        classes_dir,
+        options.chromium_code,
+        java_files)
+
+    if options.jar_path:
+      if options.main_class:
+        manifest_file = os.path.join(temp_dir, 'manifest')
+        CreateManifest(manifest_file, classpath,
+                       options.main_class)
+      else:
+        manifest_file = None
+      jar.JarDirectory(classes_dir,
+                       build_utils.ParseGypList(options.jar_excluded_classes),
+                       options.jar_path,
+                       manifest_file=manifest_file)
+
+    if options.classes_dir:
+      # Delete the old classes directory. This ensures that all .class files in
+      # the output are actually from the input .java files. For example, if a
+      # .java file is deleted or an inner class is removed, the classes
+      # directory should not contain the corresponding old .class file after
+      # running this action.
+      build_utils.DeleteDirectory(options.classes_dir)
+      shutil.copytree(classes_dir, options.classes_dir)
 
-  DoJavac(options, args)
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        input_files + build_utils.GetPythonDependencies())
 
   if options.stamp:
     build_utils.Touch(options.stamp)
 
 
 if __name__ == '__main__':
-  sys.exit(main())
+  sys.exit(main(sys.argv[1:]))