130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma#!/usr/bin/env python
230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma#
330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma# Copyright 2016 - The Android Open Source Project
430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma#
530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma# Licensed under the Apache License, Version 2.0 (the "License");
630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma# you may not use this file except in compliance with the License.
730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma# You may obtain a copy of the License at
830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma#
930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma#     http://www.apache.org/licenses/LICENSE-2.0
1030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma#
1130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma# Unless required by applicable law or agreed to in writing, software
1230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma# distributed under the License is distributed on an "AS IS" BASIS,
1330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma# See the License for the specific language governing permissions and
1530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma# limitations under the License.
1630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma#
1730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
1830b765ffef37427ca3715389a2a057c875f56e4aYuexi Maimport os
1930b765ffef37427ca3715389a2a057c875f56e4aYuexi Maimport argparse
2030b765ffef37427ca3715389a2a057c875f56e4aYuexi Maimport math
2130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
227086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma
2330b765ffef37427ca3715389a2a057c875f56e4aYuexi Maclass Module(object):
2430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    """class used to represent a ltp module
2530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
2630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    Attribute:
2730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma       _lines: list of string, lines of module text
2830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma       _header: list of string, first line of module splited by :=
2930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma       _type: string, type of module
3030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma       _path: string, path of module
3130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma       _output_dir: string, output directory of module
3230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    """
3330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    _lines = None
3430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    _header = None
3530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    _type = None
3630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    _path = None
3730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    _output_dir = None
3830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
3930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    def __init__(self, output_dir):
4030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        self._output_dir = output_dir
4130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
4230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    def parse(self, module_text):
4330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """parse a module text
4430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
4530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        Args:
4630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           module_text: string, one block of ltp module build rule.
4730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           output_dir: string, ltp compile output directory
4830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
4930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        Return:
5030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           None if the input text is not a ltp module
5130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           Self if parsed succesfully
5230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """
5330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        self._lines = module_text.splitlines()
5430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        if len(self._lines) < 2:
5530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma            self._type = None
5630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma            return None
5730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        self._header = self._lines[0].split(' := ')
5830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        if len(self._header) < 2:
5930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma            self._type = None
6030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma            return None
6130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        self._type = self._header[0]
6230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        self._path = self._header[1]
6330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        return self
6430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
6530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    def IsBuildSuccess(self, counts):
6630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """Check whether a given module specified in Android.mk file
6730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           is succesfully built
6830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
6930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           Returns:
7030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma               True if success
7130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """
7230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        if self._type is None:
7330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma            return False
7430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
7530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        counts[self._type] = counts.get(self._type, 0) + 1
7630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
777086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        success = {"module_testname": self.IsBuildSuccessModuleTestname,
787086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma                   "module_libname": self.IsBuildSuccessModuleLibname,
797086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma                   "module_prebuilt": self.IsBuildSuccessModulePrebuilt,
807086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma                   }[self._type]()
8130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
8230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        if not success:
8330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma            print "  Module build failed: " + os.path.basename(self._path)
8430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        return success
8530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
8630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    def IsBuildSuccessModuleTestname(self):
8730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """Check whether a given ltp test module in Android.mk file
8830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           is succesfully built
8930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
9030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           Args:
9130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma               module_path: string, the path of module on the first
9230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma                            line of the block
9330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
9430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           Returns:
9530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma               True if success
9630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """
9730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
9830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        return os.path.isfile(self._output_dir + \
9930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma                              "testcases/bin/" + \
10030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma                              os.path.basename(self._path))
10130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
10230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    def IsBuildSuccessModuleLibname(self):
10330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """Check whether a given ltp lib module in Android.mk file
10430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           is succesfully built
10530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
10630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           Args:
10730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma               module_path: the path of module on the first line of
10830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma                            the block
10930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
11030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           Returns:
11130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma               True if success
11230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """
11330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        # TODO(yuexima) check lib build
11430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        print "Checking module_lib is not supported now, " + \
11530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma            "assuming build success: " + self._path
11630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        return True
11730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
11830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    def IsBuildSuccessModulePrebuilt(self):
11930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """Check whether a given prebuilt module in Android.mk file
12030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           is succesfully built
12130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
12230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           Args:
12330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma               module_path: string, the path of module on the first
12430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma                            line of the block
12530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
12630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           Returns:
12730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma               True if success
12830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """
12930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        return os.path.isfile(self._output_dir + self._path)
13030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
13130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
13230b765ffef37427ca3715389a2a057c875f56e4aYuexi Maclass LtpModuleChecker(object):
13330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    """LTP module result check class.
13430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    Checks for success build of each module in LTP's Android.mk file
13530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    and rewrite it with only successfully built modules.
13630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    """
13730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    _output_dir = ""
13830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    _file_path_android_ltp_mk = ""
13930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    _module_counts = {}
14030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
14130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    def __init__(self, android_build_top, ltp_dir, target_product):
14230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        self._output_dir = android_build_top + '/out/target/product/' + \
14330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma                          target_product + '/data/nativetest/ltp/'
14430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        self._file_path_android_ltp_mk = ltp_dir + '/Android.ltp.mk'
14530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
14630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    def Read(self, file_path):
14730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """Read a file and return its entire content
14830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
14930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           Args:
15030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma               file_path: string, file path
15130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
15230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           Returns:
15330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma               entire file content in string format
15430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """
15530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        with open(file_path, 'r') as file:
15630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma            return file.read()
15730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
15830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    def LoadModules(self):
15930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """Read the LTP Android.mk file and seperate modules into
16030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma           a list of string
16130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """
1627086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        return self.Read(self._file_path_android_ltp_mk).split("\n\n")
16330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
16430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    def CheckModules(self):
16530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        """Start the LTP module build result checking and counting."""
16630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        modules = [Module(self._output_dir).parse(module)
1677086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma                   for module in self.LoadModules()]
16830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        modules_succeed = \
16930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma            [module for module in modules
17030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma             if module is not None and
17130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma             module.IsBuildSuccess(self._module_counts)
17230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma            ]
17330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
17430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        print "module type counts:"
17530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        print self._module_counts
17630b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
17730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        print str(len(modules_succeed)) + \
17830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma              " of " + str(sum([self._module_counts[i]
17930b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma              for i in self._module_counts])) + \
18030b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma              " modules were succesfully built."
18130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma        print "--Check complete."
18230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
18330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
18430b765ffef37427ca3715389a2a057c875f56e4aYuexi Madef main():
18530b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    parser = argparse.ArgumentParser(
1867086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        description='Generate Android.mk from parsed LTP make output')
1877086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma    parser.add_argument(
1887086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        '--android_build_top',
1897086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        dest='android_build_top',
1907086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        required=True,
1917086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        help='android build top directory')
1927086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma    parser.add_argument(
1937086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        '--ltp_dir',
1947086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        dest='ltp_dir',
1957086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        required=True,
1967086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        help='directory for the forked ltp project')
1977086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma    parser.add_argument(
1987086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        '--target_product',
1997086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        dest='target_product',
2007086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        required=True,
2017086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma        help='target product name, \
20230b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma                                such as "bullhead", "angler", etc.')
20330b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    args = parser.parse_args()
20430b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
2057086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma    checker = LtpModuleChecker(args.android_build_top, args.ltp_dir,
2067086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma                               args.target_product)
20730b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    checker.CheckModules()
20830b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma
2097086b40fbaf278f8af6d37ce55e196ea8c654d27Yuexi Ma
21030b765ffef37427ca3715389a2a057c875f56e4aYuexi Maif __name__ == '__main__':
21130b765ffef37427ca3715389a2a057c875f56e4aYuexi Ma    main()
212