1#!/usr/bin/env python3
2#
3# Copyright 2019, 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"""Module Info class used to hold cached merged_module_info.json.json."""
18
19import logging
20import os
21
22from aidegen import constant
23from aidegen.lib import common_util
24from aidegen.lib import module_info_util
25from aidegen.lib.singleton import Singleton
26
27from atest import constants
28from atest import module_info
29
30
31class AidegenModuleInfo(module_info.ModuleInfo, metaclass=Singleton):
32    """Class that offers fast/easy lookup for Module related details."""
33
34    @staticmethod
35    def _discover_mod_file_and_target(force_build):
36        """Find the module file.
37
38        If force_build is True, we'll remove module_bp_java_deps.json first and
39        let module_info_util.generate_merged_module_info regenerate it again.
40
41        Args:
42            force_build: Boolean to indicate if we should rebuild the
43                         module_info file regardless if it's created or not.
44
45        Returns:
46            Tuple of the relative and absolute paths of the merged module info
47            file.
48        """
49        module_file_path = common_util.get_blueprint_json_path(
50            constant.BLUEPRINT_JAVA_JSONFILE_NAME)
51        if force_build and os.path.isfile(module_file_path):
52            os.remove(module_file_path)
53        merged_file_path = os.path.join(common_util.get_soong_out_path(),
54                                        constant.MERGED_MODULE_INFO)
55        if not os.path.isfile(module_file_path):
56            logging.debug(
57                'Generating %s - this is required for the initial runs.',
58                merged_file_path)
59        data = module_info_util.generate_merged_module_info()
60        common_util.dump_json_dict(merged_file_path, data)
61        merged_file_rel_path = os.path.relpath(
62            merged_file_path, common_util.get_android_root_dir())
63        return merged_file_rel_path, merged_file_path
64
65    @staticmethod
66    def is_target_module(mod_info):
67        """Determine if the module is a target module.
68
69        Determine if a module's class is in TARGET_CLASSES.
70
71        Args:
72            mod_info: A module's module-info dictionary to be checked.
73
74        Returns:
75            A boolean, true if it is a target module, otherwise false.
76        """
77        if mod_info:
78            return any(
79                x in mod_info.get(constants.MODULE_CLASS, [])
80                for x in constant.TARGET_CLASSES)
81        return False
82
83    @staticmethod
84    def is_project_path_relative_module(mod_info, rel_path):
85        """Determine if the given project path is relative to the module.
86
87        The rules:
88           1. If constant.KEY_PATH not in mod_info, we can't tell if it's a
89              module return False.
90           2. If rel_path is empty, it's under Android root, return True.
91           3. If module's path equals or starts with rel_path return True,
92              otherwise return False.
93
94        Args:
95            mod_info: the module-info dictionary of the checked module.
96            rel_path: project's relative path
97
98        Returns:
99            True if it's the given project path is relative to the module,
100            otherwise False.
101        """
102        if constant.KEY_PATH not in mod_info:
103            return False
104        path = mod_info[constant.KEY_PATH][0]
105        if rel_path == '':
106            return True
107        if (constant.KEY_CLASS in mod_info
108                and common_util.is_source_under_relative_path(path, rel_path)):
109            return True
110        return False
111