Home | History | Annotate | Download | only in util-src
      1 #!/usr/bin/python3
      2 #
      3 # Copyright (C) 2015 The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License");
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 #     http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 
     17 """
     18 Generate java test files for test 966.
     19 """
     20 
     21 import generate_smali as base
     22 import os
     23 import sys
     24 from pathlib import Path
     25 
     26 BUILD_TOP = os.getenv("ANDROID_BUILD_TOP")
     27 if BUILD_TOP is None:
     28   print("ANDROID_BUILD_TOP not set. Please run build/envsetup.sh", file=sys.stderr)
     29   sys.exit(1)
     30 
     31 # Allow us to import mixins.
     32 sys.path.append(str(Path(BUILD_TOP)/"art"/"test"/"utils"/"python"))
     33 
     34 import testgen.mixins as mixins
     35 import functools
     36 import operator
     37 import subprocess
     38 
     39 class JavaConverter(mixins.DumpMixin, mixins.Named, mixins.JavaFileMixin):
     40   """
     41   A class that can convert a SmaliFile to a JavaFile.
     42   """
     43   def __init__(self, inner):
     44     self.inner = inner
     45 
     46   def get_name(self):
     47     """Gets the name of this file."""
     48     return self.inner.get_name()
     49 
     50   def __str__(self):
     51     out = ""
     52     for line in str(self.inner).splitlines(keepends = True):
     53       if line.startswith("#"):
     54         out += line[1:]
     55     return out
     56 
     57 class Compiler:
     58   def __init__(self, sources, javac, temp_dir, classes_dir):
     59     self.javac = javac
     60     self.temp_dir = temp_dir
     61     self.classes_dir = classes_dir
     62     self.sources = sources
     63 
     64   def compile_files(self, args, files):
     65     """
     66     Compile the files given with the arguments given.
     67     """
     68     args = args.split()
     69     files = list(map(str, files))
     70     cmd = ['sh', '-a', '-e', '--', str(self.javac)] + args + files
     71     print("Running compile command: {}".format(cmd))
     72     subprocess.check_call(cmd)
     73     print("Compiled {} files".format(len(files)))
     74 
     75   def execute(self):
     76     """
     77     Compiles this test, doing partial compilation as necessary.
     78     """
     79     # Compile Main and all classes first. Force all interfaces to be default so that there will be
     80     # no compiler problems (works since classes only implement 1 interface).
     81     for f in self.sources:
     82       if isinstance(f, base.TestInterface):
     83         JavaConverter(f.get_specific_version(base.InterfaceType.default)).dump(self.temp_dir)
     84       else:
     85         JavaConverter(f).dump(self.temp_dir)
     86     self.compile_files("-d {}".format(self.classes_dir), self.temp_dir.glob("*.java"))
     87 
     88     # Now we compile the interfaces
     89     ifaces = set(i for i in self.sources if isinstance(i, base.TestInterface))
     90     while len(ifaces) != 0:
     91       # Find those ifaces where there are no (uncompiled) interfaces that are subtypes.
     92       tops = set(filter(lambda a: not any(map(lambda i: a in i.get_super_types(), ifaces)), ifaces))
     93       files = []
     94       # Dump these ones, they are getting compiled.
     95       for f in tops:
     96         out = JavaConverter(f)
     97         out.dump(self.temp_dir)
     98         files.append(self.temp_dir / out.get_file_name())
     99       # Force all superinterfaces of these to be empty so there will be no conflicts
    100       overrides = functools.reduce(operator.or_, map(lambda i: i.get_super_types(), tops), set())
    101       for overridden in overrides:
    102         out = JavaConverter(overridden.get_specific_version(base.InterfaceType.empty))
    103         out.dump(self.temp_dir)
    104         files.append(self.temp_dir / out.get_file_name())
    105       self.compile_files("-d {outdir} -cp {outdir}".format(outdir = self.classes_dir), files)
    106       # Remove these from the set of interfaces to be compiled.
    107       ifaces -= tops
    108     print("Finished compiling all files.")
    109     return
    110 
    111 def main(argv):
    112   javac_exec = Path(argv[1])
    113   if not javac_exec.exists() or not javac_exec.is_file():
    114     print("{} is not a shell script".format(javac_exec), file=sys.stderr)
    115     sys.exit(1)
    116   temp_dir = Path(argv[2])
    117   if not temp_dir.exists() or not temp_dir.is_dir():
    118     print("{} is not a valid source dir".format(temp_dir), file=sys.stderr)
    119     sys.exit(1)
    120   classes_dir = Path(argv[3])
    121   if not classes_dir.exists() or not classes_dir.is_dir():
    122     print("{} is not a valid classes directory".format(classes_dir), file=sys.stderr)
    123     sys.exit(1)
    124   expected_txt = Path(argv[4])
    125   mainclass, all_files = base.create_all_test_files()
    126 
    127   with expected_txt.open('w') as out:
    128     print(mainclass.get_expected(), file=out)
    129   print("Wrote expected output")
    130 
    131   Compiler(all_files, javac_exec, temp_dir, classes_dir).execute()
    132 
    133 if __name__ == '__main__':
    134   main(sys.argv)
    135