xref: /aosp_15_r20/tools/asuite/aidegen/lib/common_util.py (revision c2e18aaa1096c836b086f94603d04f4eb9cf37f5)
1*c2e18aaaSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*c2e18aaaSAndroid Build Coastguard Worker#
3*c2e18aaaSAndroid Build Coastguard Worker# Copyright 2018 - The Android Open Source Project
4*c2e18aaaSAndroid Build Coastguard Worker#
5*c2e18aaaSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*c2e18aaaSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*c2e18aaaSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*c2e18aaaSAndroid Build Coastguard Worker#
9*c2e18aaaSAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
10*c2e18aaaSAndroid Build Coastguard Worker#
11*c2e18aaaSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*c2e18aaaSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*c2e18aaaSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*c2e18aaaSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*c2e18aaaSAndroid Build Coastguard Worker# limitations under the License.
16*c2e18aaaSAndroid Build Coastguard Worker
17*c2e18aaaSAndroid Build Coastguard Worker"""common_util
18*c2e18aaaSAndroid Build Coastguard Worker
19*c2e18aaaSAndroid Build Coastguard WorkerThis module has a collection of functions that provide helper functions to
20*c2e18aaaSAndroid Build Coastguard Workerother modules.
21*c2e18aaaSAndroid Build Coastguard Worker"""
22*c2e18aaaSAndroid Build Coastguard Worker
23*c2e18aaaSAndroid Build Coastguard Workerimport fnmatch
24*c2e18aaaSAndroid Build Coastguard Workerimport inspect
25*c2e18aaaSAndroid Build Coastguard Workerimport json
26*c2e18aaaSAndroid Build Coastguard Workerimport logging
27*c2e18aaaSAndroid Build Coastguard Workerimport os
28*c2e18aaaSAndroid Build Coastguard Workerimport re
29*c2e18aaaSAndroid Build Coastguard Workerimport sys
30*c2e18aaaSAndroid Build Coastguard Workerimport time
31*c2e18aaaSAndroid Build Coastguard Workerimport xml.dom.minidom
32*c2e18aaaSAndroid Build Coastguard Workerimport zipfile
33*c2e18aaaSAndroid Build Coastguard Worker
34*c2e18aaaSAndroid Build Coastguard Workerfrom functools import partial
35*c2e18aaaSAndroid Build Coastguard Workerfrom functools import wraps
36*c2e18aaaSAndroid Build Coastguard Workerfrom xml.etree import ElementTree
37*c2e18aaaSAndroid Build Coastguard Worker
38*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen import constant
39*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen.lib import errors
40*c2e18aaaSAndroid Build Coastguard Workerfrom atest import atest_utils
41*c2e18aaaSAndroid Build Coastguard Workerfrom atest import constants
42*c2e18aaaSAndroid Build Coastguard Workerfrom atest import module_info
43*c2e18aaaSAndroid Build Coastguard Worker
44*c2e18aaaSAndroid Build Coastguard Worker
45*c2e18aaaSAndroid Build Coastguard WorkerCOLORED_INFO = partial(atest_utils.colorize, color=constants.MAGENTA)
46*c2e18aaaSAndroid Build Coastguard WorkerCOLORED_PASS = partial(atest_utils.colorize, color=constants.GREEN)
47*c2e18aaaSAndroid Build Coastguard WorkerCOLORED_FAIL = partial(atest_utils.colorize, color=constants.RED)
48*c2e18aaaSAndroid Build Coastguard WorkerFAKE_MODULE_ERROR = '{} is a fake module.'
49*c2e18aaaSAndroid Build Coastguard WorkerOUTSIDE_ROOT_ERROR = '{} is outside android root.'
50*c2e18aaaSAndroid Build Coastguard WorkerPATH_NOT_EXISTS_ERROR = 'The path {} doesn\'t exist.'
51*c2e18aaaSAndroid Build Coastguard WorkerNO_MODULE_DEFINED_ERROR = 'No modules defined at {}.'
52*c2e18aaaSAndroid Build Coastguard Worker_REBUILD_MODULE_INFO = '%s We should rebuild module-info.json file for it.'
53*c2e18aaaSAndroid Build Coastguard Worker_ENVSETUP_NOT_RUN = ('Please run "source build/envsetup.sh" and "lunch" before '
54*c2e18aaaSAndroid Build Coastguard Worker                     'running aidegen.')
55*c2e18aaaSAndroid Build Coastguard Worker_LOG_FORMAT = '%(asctime)s %(filename)s:%(lineno)s:%(levelname)s: %(message)s'
56*c2e18aaaSAndroid Build Coastguard Worker_DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
57*c2e18aaaSAndroid Build Coastguard Worker_ARG_IS_NULL_ERROR = "{0}.{1}: argument '{2}' is null."
58*c2e18aaaSAndroid Build Coastguard Worker_ARG_TYPE_INCORRECT_ERROR = "{0}.{1}: argument '{2}': type is {3}, must be {4}."
59*c2e18aaaSAndroid Build Coastguard Worker_IDE_UNDEFINED = constant.IDE_DICT[constant.IDE_UNDEFINED]
60*c2e18aaaSAndroid Build Coastguard Worker_IDE_INTELLIJ = constant.IDE_DICT[constant.IDE_INTELLIJ]
61*c2e18aaaSAndroid Build Coastguard Worker_IDE_CLION = constant.IDE_DICT[constant.IDE_CLION]
62*c2e18aaaSAndroid Build Coastguard Worker_IDE_VSCODE = constant.IDE_DICT[constant.IDE_VSCODE]
63*c2e18aaaSAndroid Build Coastguard Worker
64*c2e18aaaSAndroid Build Coastguard Worker
65*c2e18aaaSAndroid Build Coastguard Workerdef time_logged(func=None, *, message='', maximum=1):
66*c2e18aaaSAndroid Build Coastguard Worker    """Decorate a function to find out how much time it spends.
67*c2e18aaaSAndroid Build Coastguard Worker
68*c2e18aaaSAndroid Build Coastguard Worker    Args:
69*c2e18aaaSAndroid Build Coastguard Worker        func: a function is to be calculated its spending time.
70*c2e18aaaSAndroid Build Coastguard Worker        message: the message the decorated function wants to show.
71*c2e18aaaSAndroid Build Coastguard Worker        maximum: an integer, minutes. If time exceeds the maximum time show
72*c2e18aaaSAndroid Build Coastguard Worker                 message, otherwise doesn't.
73*c2e18aaaSAndroid Build Coastguard Worker
74*c2e18aaaSAndroid Build Coastguard Worker    Returns:
75*c2e18aaaSAndroid Build Coastguard Worker        The wrapper function.
76*c2e18aaaSAndroid Build Coastguard Worker    """
77*c2e18aaaSAndroid Build Coastguard Worker    if func is None:
78*c2e18aaaSAndroid Build Coastguard Worker        return partial(time_logged, message=message, maximum=maximum)
79*c2e18aaaSAndroid Build Coastguard Worker
80*c2e18aaaSAndroid Build Coastguard Worker    @wraps(func)
81*c2e18aaaSAndroid Build Coastguard Worker    def wrapper(*args, **kwargs):
82*c2e18aaaSAndroid Build Coastguard Worker        """A wrapper function."""
83*c2e18aaaSAndroid Build Coastguard Worker
84*c2e18aaaSAndroid Build Coastguard Worker        start = time.time()
85*c2e18aaaSAndroid Build Coastguard Worker        try:
86*c2e18aaaSAndroid Build Coastguard Worker            return func(*args, **kwargs)
87*c2e18aaaSAndroid Build Coastguard Worker        finally:
88*c2e18aaaSAndroid Build Coastguard Worker            timestamp = time.time() - start
89*c2e18aaaSAndroid Build Coastguard Worker            logging.debug('{}.{} takes: {:.2f}s'.format(
90*c2e18aaaSAndroid Build Coastguard Worker                func.__module__, func.__name__, timestamp))
91*c2e18aaaSAndroid Build Coastguard Worker            if message and timestamp > maximum * 60:
92*c2e18aaaSAndroid Build Coastguard Worker                print(message)
93*c2e18aaaSAndroid Build Coastguard Worker
94*c2e18aaaSAndroid Build Coastguard Worker    return wrapper
95*c2e18aaaSAndroid Build Coastguard Worker
96*c2e18aaaSAndroid Build Coastguard Worker
97*c2e18aaaSAndroid Build Coastguard Workerdef get_related_paths(atest_module_info, target=None):
98*c2e18aaaSAndroid Build Coastguard Worker    """Get the relative and absolute paths of target from module-info.
99*c2e18aaaSAndroid Build Coastguard Worker
100*c2e18aaaSAndroid Build Coastguard Worker    Args:
101*c2e18aaaSAndroid Build Coastguard Worker        atest_module_info: A ModuleInfo instance.
102*c2e18aaaSAndroid Build Coastguard Worker        target: A string user input from command line. It could be several cases
103*c2e18aaaSAndroid Build Coastguard Worker                such as:
104*c2e18aaaSAndroid Build Coastguard Worker                1. Module name, e.g. Settings
105*c2e18aaaSAndroid Build Coastguard Worker                2. Module path, e.g. packages/apps/Settings
106*c2e18aaaSAndroid Build Coastguard Worker                3. Relative path, e.g. ../../packages/apps/Settings
107*c2e18aaaSAndroid Build Coastguard Worker                4. Current directory, e.g. '.' or no argument
108*c2e18aaaSAndroid Build Coastguard Worker                5. An empty string, which added by AIDEGen, used for generating
109*c2e18aaaSAndroid Build Coastguard Worker                   the iml files for the whole Android repo tree.
110*c2e18aaaSAndroid Build Coastguard Worker                   e.g.
111*c2e18aaaSAndroid Build Coastguard Worker                   1. ~/aosp$ aidegen
112*c2e18aaaSAndroid Build Coastguard Worker                   2. ~/aosp/frameworks/base$ aidegen -a
113*c2e18aaaSAndroid Build Coastguard Worker                6. An absolute path, e.g. /usr/local/home/test/aosp
114*c2e18aaaSAndroid Build Coastguard Worker
115*c2e18aaaSAndroid Build Coastguard Worker    Return:
116*c2e18aaaSAndroid Build Coastguard Worker        rel_path: The relative path of a module, return None if no matching
117*c2e18aaaSAndroid Build Coastguard Worker                  module found.
118*c2e18aaaSAndroid Build Coastguard Worker        abs_path: The absolute path of a module, return None if no matching
119*c2e18aaaSAndroid Build Coastguard Worker                  module found.
120*c2e18aaaSAndroid Build Coastguard Worker    """
121*c2e18aaaSAndroid Build Coastguard Worker    rel_path = None
122*c2e18aaaSAndroid Build Coastguard Worker    abs_path = None
123*c2e18aaaSAndroid Build Coastguard Worker    # take the command 'aidegen .' as 'aidegen'.
124*c2e18aaaSAndroid Build Coastguard Worker    if target == '.':
125*c2e18aaaSAndroid Build Coastguard Worker        target = None
126*c2e18aaaSAndroid Build Coastguard Worker    if target:
127*c2e18aaaSAndroid Build Coastguard Worker        # For the case of whole Android repo tree.
128*c2e18aaaSAndroid Build Coastguard Worker        if target == constant.WHOLE_ANDROID_TREE_TARGET:
129*c2e18aaaSAndroid Build Coastguard Worker            rel_path = ''
130*c2e18aaaSAndroid Build Coastguard Worker            abs_path = get_android_root_dir()
131*c2e18aaaSAndroid Build Coastguard Worker        # User inputs an absolute path.
132*c2e18aaaSAndroid Build Coastguard Worker        elif os.path.isabs(target):
133*c2e18aaaSAndroid Build Coastguard Worker            abs_path = target
134*c2e18aaaSAndroid Build Coastguard Worker            rel_path = os.path.relpath(abs_path, get_android_root_dir())
135*c2e18aaaSAndroid Build Coastguard Worker        # User inputs a module name.
136*c2e18aaaSAndroid Build Coastguard Worker        elif atest_module_info.is_module(target):
137*c2e18aaaSAndroid Build Coastguard Worker            paths = atest_module_info.get_paths(target)
138*c2e18aaaSAndroid Build Coastguard Worker            if paths:
139*c2e18aaaSAndroid Build Coastguard Worker                rel_path = paths[0].strip(os.sep)
140*c2e18aaaSAndroid Build Coastguard Worker                abs_path = os.path.join(get_android_root_dir(), rel_path)
141*c2e18aaaSAndroid Build Coastguard Worker        # User inputs a module path or a relative path of android root folder.
142*c2e18aaaSAndroid Build Coastguard Worker        elif (atest_module_info.get_module_names(target)
143*c2e18aaaSAndroid Build Coastguard Worker              or os.path.isdir(os.path.join(get_android_root_dir(), target))):
144*c2e18aaaSAndroid Build Coastguard Worker            rel_path = target.strip(os.sep)
145*c2e18aaaSAndroid Build Coastguard Worker            abs_path = os.path.join(get_android_root_dir(), rel_path)
146*c2e18aaaSAndroid Build Coastguard Worker        # User inputs a relative path of current directory.
147*c2e18aaaSAndroid Build Coastguard Worker        else:
148*c2e18aaaSAndroid Build Coastguard Worker            abs_path = os.path.abspath(os.path.join(os.getcwd(), target))
149*c2e18aaaSAndroid Build Coastguard Worker            rel_path = os.path.relpath(abs_path, get_android_root_dir())
150*c2e18aaaSAndroid Build Coastguard Worker    else:
151*c2e18aaaSAndroid Build Coastguard Worker        # User doesn't input.
152*c2e18aaaSAndroid Build Coastguard Worker        abs_path = os.getcwd()
153*c2e18aaaSAndroid Build Coastguard Worker        if is_android_root(abs_path):
154*c2e18aaaSAndroid Build Coastguard Worker            rel_path = ''
155*c2e18aaaSAndroid Build Coastguard Worker        else:
156*c2e18aaaSAndroid Build Coastguard Worker            rel_path = os.path.relpath(abs_path, get_android_root_dir())
157*c2e18aaaSAndroid Build Coastguard Worker    return rel_path, abs_path
158*c2e18aaaSAndroid Build Coastguard Worker
159*c2e18aaaSAndroid Build Coastguard Worker
160*c2e18aaaSAndroid Build Coastguard Workerdef is_target_android_root(atest_module_info, targets):
161*c2e18aaaSAndroid Build Coastguard Worker    """Check if any target is the Android root path.
162*c2e18aaaSAndroid Build Coastguard Worker
163*c2e18aaaSAndroid Build Coastguard Worker    Args:
164*c2e18aaaSAndroid Build Coastguard Worker        atest_module_info: A ModuleInfo instance contains data of
165*c2e18aaaSAndroid Build Coastguard Worker                           module-info.json.
166*c2e18aaaSAndroid Build Coastguard Worker        targets: A list of target modules or project paths from user input.
167*c2e18aaaSAndroid Build Coastguard Worker
168*c2e18aaaSAndroid Build Coastguard Worker    Returns:
169*c2e18aaaSAndroid Build Coastguard Worker        True if target is Android root, otherwise False.
170*c2e18aaaSAndroid Build Coastguard Worker    """
171*c2e18aaaSAndroid Build Coastguard Worker    for target in targets:
172*c2e18aaaSAndroid Build Coastguard Worker        _, abs_path = get_related_paths(atest_module_info, target)
173*c2e18aaaSAndroid Build Coastguard Worker        if is_android_root(abs_path):
174*c2e18aaaSAndroid Build Coastguard Worker            return True
175*c2e18aaaSAndroid Build Coastguard Worker    return False
176*c2e18aaaSAndroid Build Coastguard Worker
177*c2e18aaaSAndroid Build Coastguard Worker
178*c2e18aaaSAndroid Build Coastguard Workerdef is_android_root(abs_path):
179*c2e18aaaSAndroid Build Coastguard Worker    """Check if an absolute path is the Android root path.
180*c2e18aaaSAndroid Build Coastguard Worker
181*c2e18aaaSAndroid Build Coastguard Worker    Args:
182*c2e18aaaSAndroid Build Coastguard Worker        abs_path: The absolute path of a module.
183*c2e18aaaSAndroid Build Coastguard Worker
184*c2e18aaaSAndroid Build Coastguard Worker    Returns:
185*c2e18aaaSAndroid Build Coastguard Worker        True if abs_path is Android root, otherwise False.
186*c2e18aaaSAndroid Build Coastguard Worker    """
187*c2e18aaaSAndroid Build Coastguard Worker    return abs_path == get_android_root_dir()
188*c2e18aaaSAndroid Build Coastguard Worker
189*c2e18aaaSAndroid Build Coastguard Worker
190*c2e18aaaSAndroid Build Coastguard Workerdef has_build_target(atest_module_info, rel_path):
191*c2e18aaaSAndroid Build Coastguard Worker    """Determine if a relative path contains buildable module.
192*c2e18aaaSAndroid Build Coastguard Worker
193*c2e18aaaSAndroid Build Coastguard Worker    Args:
194*c2e18aaaSAndroid Build Coastguard Worker        atest_module_info: A ModuleInfo instance contains data of
195*c2e18aaaSAndroid Build Coastguard Worker                           module-info.json.
196*c2e18aaaSAndroid Build Coastguard Worker        rel_path: The module path relative to android root.
197*c2e18aaaSAndroid Build Coastguard Worker
198*c2e18aaaSAndroid Build Coastguard Worker    Returns:
199*c2e18aaaSAndroid Build Coastguard Worker        True if the relative path contains a build target, otherwise false.
200*c2e18aaaSAndroid Build Coastguard Worker    """
201*c2e18aaaSAndroid Build Coastguard Worker    return any(
202*c2e18aaaSAndroid Build Coastguard Worker        is_source_under_relative_path(mod_path, rel_path)
203*c2e18aaaSAndroid Build Coastguard Worker        for mod_path in atest_module_info.path_to_module_info)
204*c2e18aaaSAndroid Build Coastguard Worker
205*c2e18aaaSAndroid Build Coastguard Worker
206*c2e18aaaSAndroid Build Coastguard Workerdef _check_modules(atest_module_info, targets, raise_on_lost_module=True):
207*c2e18aaaSAndroid Build Coastguard Worker    """Check if all targets are valid build targets.
208*c2e18aaaSAndroid Build Coastguard Worker
209*c2e18aaaSAndroid Build Coastguard Worker    Args:
210*c2e18aaaSAndroid Build Coastguard Worker        atest_module_info: A ModuleInfo instance contains data of
211*c2e18aaaSAndroid Build Coastguard Worker                           module-info.json.
212*c2e18aaaSAndroid Build Coastguard Worker        targets: A list of target modules or project paths from user input.
213*c2e18aaaSAndroid Build Coastguard Worker                When locating the path of the target, given a matched module
214*c2e18aaaSAndroid Build Coastguard Worker                name has priority over path. Below is the priority of locating a
215*c2e18aaaSAndroid Build Coastguard Worker                target:
216*c2e18aaaSAndroid Build Coastguard Worker                1. Module name, e.g. Settings
217*c2e18aaaSAndroid Build Coastguard Worker                2. Module path, e.g. packages/apps/Settings
218*c2e18aaaSAndroid Build Coastguard Worker                3. Relative path, e.g. ../../packages/apps/Settings
219*c2e18aaaSAndroid Build Coastguard Worker                4. Current directory, e.g. '.' or no argument
220*c2e18aaaSAndroid Build Coastguard Worker        raise_on_lost_module: A boolean, pass to _check_module to determine if
221*c2e18aaaSAndroid Build Coastguard Worker                ProjectPathNotExistError or NoModuleDefinedInModuleInfoError
222*c2e18aaaSAndroid Build Coastguard Worker                should be raised.
223*c2e18aaaSAndroid Build Coastguard Worker
224*c2e18aaaSAndroid Build Coastguard Worker    Returns:
225*c2e18aaaSAndroid Build Coastguard Worker        True if any _check_module return flip the True/False.
226*c2e18aaaSAndroid Build Coastguard Worker    """
227*c2e18aaaSAndroid Build Coastguard Worker    for target in targets:
228*c2e18aaaSAndroid Build Coastguard Worker        if not check_module(atest_module_info, target, raise_on_lost_module):
229*c2e18aaaSAndroid Build Coastguard Worker            return False
230*c2e18aaaSAndroid Build Coastguard Worker    return True
231*c2e18aaaSAndroid Build Coastguard Worker
232*c2e18aaaSAndroid Build Coastguard Worker
233*c2e18aaaSAndroid Build Coastguard Workerdef check_module(atest_module_info, target, raise_on_lost_module=True):
234*c2e18aaaSAndroid Build Coastguard Worker    """Check if a target is valid or it's a path containing build target.
235*c2e18aaaSAndroid Build Coastguard Worker
236*c2e18aaaSAndroid Build Coastguard Worker    Args:
237*c2e18aaaSAndroid Build Coastguard Worker        atest_module_info: A ModuleInfo instance contains the data of
238*c2e18aaaSAndroid Build Coastguard Worker                module-info.json.
239*c2e18aaaSAndroid Build Coastguard Worker        target: A target module or project path from user input.
240*c2e18aaaSAndroid Build Coastguard Worker                When locating the path of the target, given a matched module
241*c2e18aaaSAndroid Build Coastguard Worker                name has priority over path. Below is the priority of locating a
242*c2e18aaaSAndroid Build Coastguard Worker                target:
243*c2e18aaaSAndroid Build Coastguard Worker                1. Module name, e.g. Settings
244*c2e18aaaSAndroid Build Coastguard Worker                2. Module path, e.g. packages/apps/Settings
245*c2e18aaaSAndroid Build Coastguard Worker                3. Relative path, e.g. ../../packages/apps/Settings
246*c2e18aaaSAndroid Build Coastguard Worker                4. Current directory, e.g. . or no argument
247*c2e18aaaSAndroid Build Coastguard Worker                5. An absolute path, e.g. /usr/local/home/test/aosp
248*c2e18aaaSAndroid Build Coastguard Worker        raise_on_lost_module: A boolean, handles if ProjectPathNotExistError or
249*c2e18aaaSAndroid Build Coastguard Worker                NoModuleDefinedInModuleInfoError should be raised.
250*c2e18aaaSAndroid Build Coastguard Worker
251*c2e18aaaSAndroid Build Coastguard Worker    Returns:
252*c2e18aaaSAndroid Build Coastguard Worker        1. If there is no error _check_module always return True.
253*c2e18aaaSAndroid Build Coastguard Worker        2. If there is an error,
254*c2e18aaaSAndroid Build Coastguard Worker            a. When raise_on_lost_module is False, _check_module will raise the
255*c2e18aaaSAndroid Build Coastguard Worker               error.
256*c2e18aaaSAndroid Build Coastguard Worker            b. When raise_on_lost_module is True, _check_module will return
257*c2e18aaaSAndroid Build Coastguard Worker               False if module's error is ProjectPathNotExistError or
258*c2e18aaaSAndroid Build Coastguard Worker               NoModuleDefinedInModuleInfoError else raise the error.
259*c2e18aaaSAndroid Build Coastguard Worker
260*c2e18aaaSAndroid Build Coastguard Worker    Raises:
261*c2e18aaaSAndroid Build Coastguard Worker        Raise ProjectPathNotExistError and NoModuleDefinedInModuleInfoError only
262*c2e18aaaSAndroid Build Coastguard Worker        when raise_on_lost_module is True, others don't subject to the limit.
263*c2e18aaaSAndroid Build Coastguard Worker        The rules for raising exceptions:
264*c2e18aaaSAndroid Build Coastguard Worker        1. Absolute path of a module is None -> FakeModuleError
265*c2e18aaaSAndroid Build Coastguard Worker        2. Module doesn't exist in repo root -> ProjectOutsideAndroidRootError
266*c2e18aaaSAndroid Build Coastguard Worker        3. The given absolute path is not a dir -> ProjectPathNotExistError
267*c2e18aaaSAndroid Build Coastguard Worker        4. If the given abs path doesn't contain any target and not repo root
268*c2e18aaaSAndroid Build Coastguard Worker           -> NoModuleDefinedInModuleInfoError
269*c2e18aaaSAndroid Build Coastguard Worker    """
270*c2e18aaaSAndroid Build Coastguard Worker    rel_path, abs_path = get_related_paths(atest_module_info, target)
271*c2e18aaaSAndroid Build Coastguard Worker    if not abs_path:
272*c2e18aaaSAndroid Build Coastguard Worker        err = FAKE_MODULE_ERROR.format(target)
273*c2e18aaaSAndroid Build Coastguard Worker        logging.error(err)
274*c2e18aaaSAndroid Build Coastguard Worker        raise errors.FakeModuleError(err)
275*c2e18aaaSAndroid Build Coastguard Worker    if not is_source_under_relative_path(abs_path, get_android_root_dir()):
276*c2e18aaaSAndroid Build Coastguard Worker        err = OUTSIDE_ROOT_ERROR.format(abs_path)
277*c2e18aaaSAndroid Build Coastguard Worker        logging.error(err)
278*c2e18aaaSAndroid Build Coastguard Worker        raise errors.ProjectOutsideAndroidRootError(err)
279*c2e18aaaSAndroid Build Coastguard Worker    if not os.path.isdir(abs_path):
280*c2e18aaaSAndroid Build Coastguard Worker        err = PATH_NOT_EXISTS_ERROR.format(rel_path)
281*c2e18aaaSAndroid Build Coastguard Worker        if raise_on_lost_module:
282*c2e18aaaSAndroid Build Coastguard Worker            logging.error(err)
283*c2e18aaaSAndroid Build Coastguard Worker            raise errors.ProjectPathNotExistError(err)
284*c2e18aaaSAndroid Build Coastguard Worker        logging.debug(_REBUILD_MODULE_INFO, err)
285*c2e18aaaSAndroid Build Coastguard Worker        return False
286*c2e18aaaSAndroid Build Coastguard Worker    if (not has_build_target(atest_module_info, rel_path)
287*c2e18aaaSAndroid Build Coastguard Worker            and not is_android_root(abs_path)):
288*c2e18aaaSAndroid Build Coastguard Worker        err = NO_MODULE_DEFINED_ERROR.format(rel_path)
289*c2e18aaaSAndroid Build Coastguard Worker        if raise_on_lost_module:
290*c2e18aaaSAndroid Build Coastguard Worker            logging.error(err)
291*c2e18aaaSAndroid Build Coastguard Worker            raise errors.NoModuleDefinedInModuleInfoError(err)
292*c2e18aaaSAndroid Build Coastguard Worker        logging.debug(_REBUILD_MODULE_INFO, err)
293*c2e18aaaSAndroid Build Coastguard Worker        return False
294*c2e18aaaSAndroid Build Coastguard Worker    return True
295*c2e18aaaSAndroid Build Coastguard Worker
296*c2e18aaaSAndroid Build Coastguard Worker
297*c2e18aaaSAndroid Build Coastguard Workerdef get_abs_path(rel_path):
298*c2e18aaaSAndroid Build Coastguard Worker    """Get absolute path from a relative path.
299*c2e18aaaSAndroid Build Coastguard Worker
300*c2e18aaaSAndroid Build Coastguard Worker    Args:
301*c2e18aaaSAndroid Build Coastguard Worker        rel_path: A string, a relative path to get_android_root_dir().
302*c2e18aaaSAndroid Build Coastguard Worker
303*c2e18aaaSAndroid Build Coastguard Worker    Returns:
304*c2e18aaaSAndroid Build Coastguard Worker        abs_path: A string, an absolute path starts with
305*c2e18aaaSAndroid Build Coastguard Worker                  get_android_root_dir().
306*c2e18aaaSAndroid Build Coastguard Worker    """
307*c2e18aaaSAndroid Build Coastguard Worker    if not rel_path:
308*c2e18aaaSAndroid Build Coastguard Worker        return get_android_root_dir()
309*c2e18aaaSAndroid Build Coastguard Worker    if is_source_under_relative_path(rel_path, get_android_root_dir()):
310*c2e18aaaSAndroid Build Coastguard Worker        return rel_path
311*c2e18aaaSAndroid Build Coastguard Worker    return os.path.join(get_android_root_dir(), rel_path)
312*c2e18aaaSAndroid Build Coastguard Worker
313*c2e18aaaSAndroid Build Coastguard Worker
314*c2e18aaaSAndroid Build Coastguard Workerdef is_target(src_file, src_file_extensions):
315*c2e18aaaSAndroid Build Coastguard Worker    """Check if src_file is a type of src_file_extensions.
316*c2e18aaaSAndroid Build Coastguard Worker
317*c2e18aaaSAndroid Build Coastguard Worker    Args:
318*c2e18aaaSAndroid Build Coastguard Worker        src_file: A string of the file path to be checked.
319*c2e18aaaSAndroid Build Coastguard Worker        src_file_extensions: A list of file types to be checked
320*c2e18aaaSAndroid Build Coastguard Worker
321*c2e18aaaSAndroid Build Coastguard Worker    Returns:
322*c2e18aaaSAndroid Build Coastguard Worker        True if src_file is one of the types of src_file_extensions, otherwise
323*c2e18aaaSAndroid Build Coastguard Worker        False.
324*c2e18aaaSAndroid Build Coastguard Worker    """
325*c2e18aaaSAndroid Build Coastguard Worker    return any(src_file.endswith(x) for x in src_file_extensions)
326*c2e18aaaSAndroid Build Coastguard Worker
327*c2e18aaaSAndroid Build Coastguard Worker
328*c2e18aaaSAndroid Build Coastguard Workerdef get_atest_module_info(targets=None):
329*c2e18aaaSAndroid Build Coastguard Worker    """Get the right version of atest ModuleInfo instance.
330*c2e18aaaSAndroid Build Coastguard Worker
331*c2e18aaaSAndroid Build Coastguard Worker    The rules:
332*c2e18aaaSAndroid Build Coastguard Worker        1. If targets is None:
333*c2e18aaaSAndroid Build Coastguard Worker           We just want to get an atest ModuleInfo instance.
334*c2e18aaaSAndroid Build Coastguard Worker        2. If targets isn't None:
335*c2e18aaaSAndroid Build Coastguard Worker           Check if the targets don't exist in ModuleInfo, we'll regain a new
336*c2e18aaaSAndroid Build Coastguard Worker           atest ModuleInfo instance by setting force_build=True and call
337*c2e18aaaSAndroid Build Coastguard Worker           _check_modules again. If targets still don't exist, raise exceptions.
338*c2e18aaaSAndroid Build Coastguard Worker
339*c2e18aaaSAndroid Build Coastguard Worker    Args:
340*c2e18aaaSAndroid Build Coastguard Worker        targets: A list of targets to be built.
341*c2e18aaaSAndroid Build Coastguard Worker
342*c2e18aaaSAndroid Build Coastguard Worker    Returns:
343*c2e18aaaSAndroid Build Coastguard Worker        An atest ModuleInfo instance.
344*c2e18aaaSAndroid Build Coastguard Worker    """
345*c2e18aaaSAndroid Build Coastguard Worker    amodule_info = module_info.ModuleInfo()
346*c2e18aaaSAndroid Build Coastguard Worker    if targets and not _check_modules(
347*c2e18aaaSAndroid Build Coastguard Worker            amodule_info, targets, raise_on_lost_module=False):
348*c2e18aaaSAndroid Build Coastguard Worker        amodule_info = module_info.ModuleInfo(force_build=True)
349*c2e18aaaSAndroid Build Coastguard Worker        _check_modules(amodule_info, targets)
350*c2e18aaaSAndroid Build Coastguard Worker    return amodule_info
351*c2e18aaaSAndroid Build Coastguard Worker
352*c2e18aaaSAndroid Build Coastguard Worker
353*c2e18aaaSAndroid Build Coastguard Workerdef get_blueprint_json_path(file_name):
354*c2e18aaaSAndroid Build Coastguard Worker    """Assemble the path of blueprint json file.
355*c2e18aaaSAndroid Build Coastguard Worker
356*c2e18aaaSAndroid Build Coastguard Worker    Args:
357*c2e18aaaSAndroid Build Coastguard Worker        file_name: A string of blueprint json file name.
358*c2e18aaaSAndroid Build Coastguard Worker
359*c2e18aaaSAndroid Build Coastguard Worker    Returns:
360*c2e18aaaSAndroid Build Coastguard Worker        The path of json file.
361*c2e18aaaSAndroid Build Coastguard Worker    """
362*c2e18aaaSAndroid Build Coastguard Worker    return os.path.join(get_soong_out_path(), file_name)
363*c2e18aaaSAndroid Build Coastguard Worker
364*c2e18aaaSAndroid Build Coastguard Worker
365*c2e18aaaSAndroid Build Coastguard Workerdef back_to_cwd(func):
366*c2e18aaaSAndroid Build Coastguard Worker    """Decorate a function change directory back to its original one.
367*c2e18aaaSAndroid Build Coastguard Worker
368*c2e18aaaSAndroid Build Coastguard Worker    Args:
369*c2e18aaaSAndroid Build Coastguard Worker        func: a function is to be changed back to its original directory.
370*c2e18aaaSAndroid Build Coastguard Worker
371*c2e18aaaSAndroid Build Coastguard Worker    Returns:
372*c2e18aaaSAndroid Build Coastguard Worker        The wrapper function.
373*c2e18aaaSAndroid Build Coastguard Worker    """
374*c2e18aaaSAndroid Build Coastguard Worker
375*c2e18aaaSAndroid Build Coastguard Worker    @wraps(func)
376*c2e18aaaSAndroid Build Coastguard Worker    def wrapper(*args, **kwargs):
377*c2e18aaaSAndroid Build Coastguard Worker        """A wrapper function."""
378*c2e18aaaSAndroid Build Coastguard Worker        cwd = os.getcwd()
379*c2e18aaaSAndroid Build Coastguard Worker        try:
380*c2e18aaaSAndroid Build Coastguard Worker            return func(*args, **kwargs)
381*c2e18aaaSAndroid Build Coastguard Worker        finally:
382*c2e18aaaSAndroid Build Coastguard Worker            os.chdir(cwd)
383*c2e18aaaSAndroid Build Coastguard Worker
384*c2e18aaaSAndroid Build Coastguard Worker    return wrapper
385*c2e18aaaSAndroid Build Coastguard Worker
386*c2e18aaaSAndroid Build Coastguard Worker
387*c2e18aaaSAndroid Build Coastguard Workerdef get_android_out_dir():
388*c2e18aaaSAndroid Build Coastguard Worker    """Get out directory in different conditions.
389*c2e18aaaSAndroid Build Coastguard Worker
390*c2e18aaaSAndroid Build Coastguard Worker    Returns:
391*c2e18aaaSAndroid Build Coastguard Worker        Android out directory path.
392*c2e18aaaSAndroid Build Coastguard Worker    """
393*c2e18aaaSAndroid Build Coastguard Worker    android_root_path = get_android_root_dir()
394*c2e18aaaSAndroid Build Coastguard Worker    android_out_dir = os.getenv(constants.ANDROID_OUT_DIR)
395*c2e18aaaSAndroid Build Coastguard Worker    out_dir_common_base = os.getenv(constant.OUT_DIR_COMMON_BASE_ENV_VAR)
396*c2e18aaaSAndroid Build Coastguard Worker    android_out_dir_common_base = (os.path.join(
397*c2e18aaaSAndroid Build Coastguard Worker        out_dir_common_base, os.path.basename(android_root_path))
398*c2e18aaaSAndroid Build Coastguard Worker                                   if out_dir_common_base else None)
399*c2e18aaaSAndroid Build Coastguard Worker    return (android_out_dir or android_out_dir_common_base
400*c2e18aaaSAndroid Build Coastguard Worker            or constant.ANDROID_DEFAULT_OUT)
401*c2e18aaaSAndroid Build Coastguard Worker
402*c2e18aaaSAndroid Build Coastguard Worker
403*c2e18aaaSAndroid Build Coastguard Workerdef get_android_root_dir():
404*c2e18aaaSAndroid Build Coastguard Worker    """Get Android root directory.
405*c2e18aaaSAndroid Build Coastguard Worker
406*c2e18aaaSAndroid Build Coastguard Worker    If the path doesn't exist show message to ask users to run envsetup.sh and
407*c2e18aaaSAndroid Build Coastguard Worker    lunch first.
408*c2e18aaaSAndroid Build Coastguard Worker
409*c2e18aaaSAndroid Build Coastguard Worker    Returns:
410*c2e18aaaSAndroid Build Coastguard Worker        Android root directory path.
411*c2e18aaaSAndroid Build Coastguard Worker    """
412*c2e18aaaSAndroid Build Coastguard Worker    android_root_path = os.environ.get(constants.ANDROID_BUILD_TOP)
413*c2e18aaaSAndroid Build Coastguard Worker    if not android_root_path:
414*c2e18aaaSAndroid Build Coastguard Worker        _show_env_setup_msg_and_exit()
415*c2e18aaaSAndroid Build Coastguard Worker    return android_root_path
416*c2e18aaaSAndroid Build Coastguard Worker
417*c2e18aaaSAndroid Build Coastguard Worker
418*c2e18aaaSAndroid Build Coastguard Workerdef get_aidegen_root_dir():
419*c2e18aaaSAndroid Build Coastguard Worker    """Get AIDEGen root directory.
420*c2e18aaaSAndroid Build Coastguard Worker
421*c2e18aaaSAndroid Build Coastguard Worker    Returns:
422*c2e18aaaSAndroid Build Coastguard Worker        AIDEGen root directory path.
423*c2e18aaaSAndroid Build Coastguard Worker    """
424*c2e18aaaSAndroid Build Coastguard Worker    return os.path.join(get_android_root_dir(), constant.AIDEGEN_ROOT_PATH)
425*c2e18aaaSAndroid Build Coastguard Worker
426*c2e18aaaSAndroid Build Coastguard Worker
427*c2e18aaaSAndroid Build Coastguard Workerdef _show_env_setup_msg_and_exit():
428*c2e18aaaSAndroid Build Coastguard Worker    """Show message if users didn't run envsetup.sh and lunch."""
429*c2e18aaaSAndroid Build Coastguard Worker    print(_ENVSETUP_NOT_RUN)
430*c2e18aaaSAndroid Build Coastguard Worker    sys.exit(0)
431*c2e18aaaSAndroid Build Coastguard Worker
432*c2e18aaaSAndroid Build Coastguard Worker
433*c2e18aaaSAndroid Build Coastguard Workerdef get_soong_out_path():
434*c2e18aaaSAndroid Build Coastguard Worker    """Assemble out directory's soong path.
435*c2e18aaaSAndroid Build Coastguard Worker
436*c2e18aaaSAndroid Build Coastguard Worker    Returns:
437*c2e18aaaSAndroid Build Coastguard Worker        Out directory's soong path.
438*c2e18aaaSAndroid Build Coastguard Worker    """
439*c2e18aaaSAndroid Build Coastguard Worker    return os.path.join(get_android_root_dir(), get_android_out_dir(), 'soong')
440*c2e18aaaSAndroid Build Coastguard Worker
441*c2e18aaaSAndroid Build Coastguard Worker
442*c2e18aaaSAndroid Build Coastguard Workerdef configure_logging(verbose):
443*c2e18aaaSAndroid Build Coastguard Worker    """Configure the logger.
444*c2e18aaaSAndroid Build Coastguard Worker
445*c2e18aaaSAndroid Build Coastguard Worker    Args:
446*c2e18aaaSAndroid Build Coastguard Worker        verbose: A boolean. If true, display DEBUG level logs.
447*c2e18aaaSAndroid Build Coastguard Worker    """
448*c2e18aaaSAndroid Build Coastguard Worker    log_format = _LOG_FORMAT
449*c2e18aaaSAndroid Build Coastguard Worker    datefmt = _DATE_FORMAT
450*c2e18aaaSAndroid Build Coastguard Worker    level = logging.DEBUG if verbose else logging.INFO
451*c2e18aaaSAndroid Build Coastguard Worker    # Clear all handlers to prevent setting level not working.
452*c2e18aaaSAndroid Build Coastguard Worker    logging.getLogger().handlers = []
453*c2e18aaaSAndroid Build Coastguard Worker    logging.basicConfig(level=level, format=log_format, datefmt=datefmt)
454*c2e18aaaSAndroid Build Coastguard Worker
455*c2e18aaaSAndroid Build Coastguard Worker
456*c2e18aaaSAndroid Build Coastguard Workerdef exist_android_bp(abs_path):
457*c2e18aaaSAndroid Build Coastguard Worker    """Check if the Android.bp exists under specific folder.
458*c2e18aaaSAndroid Build Coastguard Worker
459*c2e18aaaSAndroid Build Coastguard Worker    Args:
460*c2e18aaaSAndroid Build Coastguard Worker        abs_path: An absolute path string.
461*c2e18aaaSAndroid Build Coastguard Worker
462*c2e18aaaSAndroid Build Coastguard Worker    Returns: A boolean, true if the Android.bp exists under the folder,
463*c2e18aaaSAndroid Build Coastguard Worker             otherwise false.
464*c2e18aaaSAndroid Build Coastguard Worker    """
465*c2e18aaaSAndroid Build Coastguard Worker    return os.path.isfile(os.path.join(abs_path, constant.ANDROID_BP))
466*c2e18aaaSAndroid Build Coastguard Worker
467*c2e18aaaSAndroid Build Coastguard Worker
468*c2e18aaaSAndroid Build Coastguard Workerdef exist_android_mk(abs_path):
469*c2e18aaaSAndroid Build Coastguard Worker    """Check if the Android.mk exists under specific folder.
470*c2e18aaaSAndroid Build Coastguard Worker
471*c2e18aaaSAndroid Build Coastguard Worker    Args:
472*c2e18aaaSAndroid Build Coastguard Worker        abs_path: An absolute path string.
473*c2e18aaaSAndroid Build Coastguard Worker
474*c2e18aaaSAndroid Build Coastguard Worker    Returns: A boolean, true if the Android.mk exists under the folder,
475*c2e18aaaSAndroid Build Coastguard Worker             otherwise false.
476*c2e18aaaSAndroid Build Coastguard Worker    """
477*c2e18aaaSAndroid Build Coastguard Worker    return os.path.isfile(os.path.join(abs_path, constant.ANDROID_MK))
478*c2e18aaaSAndroid Build Coastguard Worker
479*c2e18aaaSAndroid Build Coastguard Worker
480*c2e18aaaSAndroid Build Coastguard Workerdef is_source_under_relative_path(source, relative_path):
481*c2e18aaaSAndroid Build Coastguard Worker    """Check if a source file is a project relative path file.
482*c2e18aaaSAndroid Build Coastguard Worker
483*c2e18aaaSAndroid Build Coastguard Worker    Args:
484*c2e18aaaSAndroid Build Coastguard Worker        source: Android source file path.
485*c2e18aaaSAndroid Build Coastguard Worker        relative_path: Relative path of the module.
486*c2e18aaaSAndroid Build Coastguard Worker
487*c2e18aaaSAndroid Build Coastguard Worker    Returns:
488*c2e18aaaSAndroid Build Coastguard Worker        True if source file is a project relative path file, otherwise False.
489*c2e18aaaSAndroid Build Coastguard Worker    """
490*c2e18aaaSAndroid Build Coastguard Worker    return re.search(
491*c2e18aaaSAndroid Build Coastguard Worker        constant.RE_INSIDE_PATH_CHECK.format(relative_path), source)
492*c2e18aaaSAndroid Build Coastguard Worker
493*c2e18aaaSAndroid Build Coastguard Worker
494*c2e18aaaSAndroid Build Coastguard Workerdef remove_user_home_path(data):
495*c2e18aaaSAndroid Build Coastguard Worker    """Replace the user home path string with a constant string.
496*c2e18aaaSAndroid Build Coastguard Worker
497*c2e18aaaSAndroid Build Coastguard Worker    Args:
498*c2e18aaaSAndroid Build Coastguard Worker        data: A string of xml content or an attributeError of error message.
499*c2e18aaaSAndroid Build Coastguard Worker
500*c2e18aaaSAndroid Build Coastguard Worker    Returns:
501*c2e18aaaSAndroid Build Coastguard Worker        A string which replaced the user home path to $USER_HOME$.
502*c2e18aaaSAndroid Build Coastguard Worker    """
503*c2e18aaaSAndroid Build Coastguard Worker    return str(data).replace(os.path.expanduser('~'), constant.USER_HOME)
504*c2e18aaaSAndroid Build Coastguard Worker
505*c2e18aaaSAndroid Build Coastguard Worker
506*c2e18aaaSAndroid Build Coastguard Workerdef io_error_handle(func):
507*c2e18aaaSAndroid Build Coastguard Worker    """Decorates a function of handling io error and raising exception.
508*c2e18aaaSAndroid Build Coastguard Worker
509*c2e18aaaSAndroid Build Coastguard Worker    Args:
510*c2e18aaaSAndroid Build Coastguard Worker        func: A function is to be raised exception if writing file failed.
511*c2e18aaaSAndroid Build Coastguard Worker
512*c2e18aaaSAndroid Build Coastguard Worker    Returns:
513*c2e18aaaSAndroid Build Coastguard Worker        The wrapper function.
514*c2e18aaaSAndroid Build Coastguard Worker    """
515*c2e18aaaSAndroid Build Coastguard Worker
516*c2e18aaaSAndroid Build Coastguard Worker    @wraps(func)
517*c2e18aaaSAndroid Build Coastguard Worker    def wrapper(*args, **kwargs):
518*c2e18aaaSAndroid Build Coastguard Worker        """A wrapper function."""
519*c2e18aaaSAndroid Build Coastguard Worker        try:
520*c2e18aaaSAndroid Build Coastguard Worker            return func(*args, **kwargs)
521*c2e18aaaSAndroid Build Coastguard Worker        except (OSError, IOError) as err:
522*c2e18aaaSAndroid Build Coastguard Worker            print('{0}.{1} I/O error: {2}'.format(
523*c2e18aaaSAndroid Build Coastguard Worker                func.__module__, func.__name__, err))
524*c2e18aaaSAndroid Build Coastguard Worker            raise
525*c2e18aaaSAndroid Build Coastguard Worker    return wrapper
526*c2e18aaaSAndroid Build Coastguard Worker
527*c2e18aaaSAndroid Build Coastguard Worker
528*c2e18aaaSAndroid Build Coastguard Workerdef check_args(**decls):
529*c2e18aaaSAndroid Build Coastguard Worker    """Decorates a function to check its argument types.
530*c2e18aaaSAndroid Build Coastguard Worker
531*c2e18aaaSAndroid Build Coastguard Worker    Usage:
532*c2e18aaaSAndroid Build Coastguard Worker        @check_args(name=str, text=str)
533*c2e18aaaSAndroid Build Coastguard Worker        def parse_rule(name, text):
534*c2e18aaaSAndroid Build Coastguard Worker            ...
535*c2e18aaaSAndroid Build Coastguard Worker
536*c2e18aaaSAndroid Build Coastguard Worker    Args:
537*c2e18aaaSAndroid Build Coastguard Worker        decls: A dictionary with keys as arguments' names and values as
538*c2e18aaaSAndroid Build Coastguard Worker             arguments' types.
539*c2e18aaaSAndroid Build Coastguard Worker
540*c2e18aaaSAndroid Build Coastguard Worker    Returns:
541*c2e18aaaSAndroid Build Coastguard Worker        The wrapper function.
542*c2e18aaaSAndroid Build Coastguard Worker    """
543*c2e18aaaSAndroid Build Coastguard Worker
544*c2e18aaaSAndroid Build Coastguard Worker    def decorator(func):
545*c2e18aaaSAndroid Build Coastguard Worker        """A wrapper function."""
546*c2e18aaaSAndroid Build Coastguard Worker        fmodule = func.__module__
547*c2e18aaaSAndroid Build Coastguard Worker        fname = func.__name__
548*c2e18aaaSAndroid Build Coastguard Worker        fparams = inspect.signature(func).parameters
549*c2e18aaaSAndroid Build Coastguard Worker
550*c2e18aaaSAndroid Build Coastguard Worker        @wraps(func)
551*c2e18aaaSAndroid Build Coastguard Worker        def decorated(*args, **kwargs):
552*c2e18aaaSAndroid Build Coastguard Worker            """A wrapper function."""
553*c2e18aaaSAndroid Build Coastguard Worker            params = dict(zip(fparams, args))
554*c2e18aaaSAndroid Build Coastguard Worker            for arg_name, arg_type in decls.items():
555*c2e18aaaSAndroid Build Coastguard Worker                try:
556*c2e18aaaSAndroid Build Coastguard Worker                    arg_val = params[arg_name]
557*c2e18aaaSAndroid Build Coastguard Worker                except KeyError:
558*c2e18aaaSAndroid Build Coastguard Worker                    # If arg_name can't be found in function's signature, it
559*c2e18aaaSAndroid Build Coastguard Worker                    # might be a case of a partial function or default
560*c2e18aaaSAndroid Build Coastguard Worker                    # parameters, we'll neglect it.
561*c2e18aaaSAndroid Build Coastguard Worker                    if arg_name not in kwargs:
562*c2e18aaaSAndroid Build Coastguard Worker                        continue
563*c2e18aaaSAndroid Build Coastguard Worker                    arg_val = kwargs.get(arg_name)
564*c2e18aaaSAndroid Build Coastguard Worker                if arg_val is None:
565*c2e18aaaSAndroid Build Coastguard Worker                    raise TypeError(_ARG_IS_NULL_ERROR.format(
566*c2e18aaaSAndroid Build Coastguard Worker                        fmodule, fname, arg_name))
567*c2e18aaaSAndroid Build Coastguard Worker                if not isinstance(arg_val, arg_type):
568*c2e18aaaSAndroid Build Coastguard Worker                    raise TypeError(_ARG_TYPE_INCORRECT_ERROR.format(
569*c2e18aaaSAndroid Build Coastguard Worker                        fmodule, fname, arg_name, type(arg_val), arg_type))
570*c2e18aaaSAndroid Build Coastguard Worker            return func(*args, **kwargs)
571*c2e18aaaSAndroid Build Coastguard Worker        return decorated
572*c2e18aaaSAndroid Build Coastguard Worker
573*c2e18aaaSAndroid Build Coastguard Worker    return decorator
574*c2e18aaaSAndroid Build Coastguard Worker
575*c2e18aaaSAndroid Build Coastguard Worker
576*c2e18aaaSAndroid Build Coastguard Worker@io_error_handle
577*c2e18aaaSAndroid Build Coastguard Workerdef dump_json_dict(json_path, data):
578*c2e18aaaSAndroid Build Coastguard Worker    """Dumps a dictionary of data into a json file.
579*c2e18aaaSAndroid Build Coastguard Worker
580*c2e18aaaSAndroid Build Coastguard Worker    Args:
581*c2e18aaaSAndroid Build Coastguard Worker        json_path: An absolute json file path string.
582*c2e18aaaSAndroid Build Coastguard Worker        data: A dictionary of data to be written into a json file.
583*c2e18aaaSAndroid Build Coastguard Worker    """
584*c2e18aaaSAndroid Build Coastguard Worker    with open(json_path, 'w', encoding='utf-8') as json_file:
585*c2e18aaaSAndroid Build Coastguard Worker        json.dump(data, json_file, indent=4)
586*c2e18aaaSAndroid Build Coastguard Worker
587*c2e18aaaSAndroid Build Coastguard Worker
588*c2e18aaaSAndroid Build Coastguard Worker@io_error_handle
589*c2e18aaaSAndroid Build Coastguard Workerdef get_json_dict(json_path):
590*c2e18aaaSAndroid Build Coastguard Worker    """Loads a json file from path and convert it into a json dictionary.
591*c2e18aaaSAndroid Build Coastguard Worker
592*c2e18aaaSAndroid Build Coastguard Worker    Args:
593*c2e18aaaSAndroid Build Coastguard Worker        json_path: An absolute json file path string.
594*c2e18aaaSAndroid Build Coastguard Worker
595*c2e18aaaSAndroid Build Coastguard Worker    Returns:
596*c2e18aaaSAndroid Build Coastguard Worker        A dictionary loaded from the json_path.
597*c2e18aaaSAndroid Build Coastguard Worker    """
598*c2e18aaaSAndroid Build Coastguard Worker    with open(json_path, 'r', encoding='utf-8') as jfile:
599*c2e18aaaSAndroid Build Coastguard Worker        return json.load(jfile)
600*c2e18aaaSAndroid Build Coastguard Worker
601*c2e18aaaSAndroid Build Coastguard Worker
602*c2e18aaaSAndroid Build Coastguard Worker@io_error_handle
603*c2e18aaaSAndroid Build Coastguard Workerdef read_file_line_to_list(file_path):
604*c2e18aaaSAndroid Build Coastguard Worker    """Read a file line by line and write them into a list.
605*c2e18aaaSAndroid Build Coastguard Worker
606*c2e18aaaSAndroid Build Coastguard Worker    Args:
607*c2e18aaaSAndroid Build Coastguard Worker        file_path: A string of a file's path.
608*c2e18aaaSAndroid Build Coastguard Worker
609*c2e18aaaSAndroid Build Coastguard Worker    Returns:
610*c2e18aaaSAndroid Build Coastguard Worker        A list of the file's content by line.
611*c2e18aaaSAndroid Build Coastguard Worker    """
612*c2e18aaaSAndroid Build Coastguard Worker    files = []
613*c2e18aaaSAndroid Build Coastguard Worker    with open(file_path, 'r', encoding='utf8') as infile:
614*c2e18aaaSAndroid Build Coastguard Worker        for line in infile:
615*c2e18aaaSAndroid Build Coastguard Worker            files.append(line.strip())
616*c2e18aaaSAndroid Build Coastguard Worker    return files
617*c2e18aaaSAndroid Build Coastguard Worker
618*c2e18aaaSAndroid Build Coastguard Worker
619*c2e18aaaSAndroid Build Coastguard Worker@io_error_handle
620*c2e18aaaSAndroid Build Coastguard Workerdef read_file_content(path, encode_type='utf8'):
621*c2e18aaaSAndroid Build Coastguard Worker    """Read file's content.
622*c2e18aaaSAndroid Build Coastguard Worker
623*c2e18aaaSAndroid Build Coastguard Worker    Args:
624*c2e18aaaSAndroid Build Coastguard Worker        path: Path of input file.
625*c2e18aaaSAndroid Build Coastguard Worker        encode_type: A string of encoding name, default to UTF-8.
626*c2e18aaaSAndroid Build Coastguard Worker
627*c2e18aaaSAndroid Build Coastguard Worker    Returns:
628*c2e18aaaSAndroid Build Coastguard Worker        String: Content of the file.
629*c2e18aaaSAndroid Build Coastguard Worker    """
630*c2e18aaaSAndroid Build Coastguard Worker    with open(path, 'r', encoding=encode_type) as template:
631*c2e18aaaSAndroid Build Coastguard Worker        return template.read()
632*c2e18aaaSAndroid Build Coastguard Worker
633*c2e18aaaSAndroid Build Coastguard Worker
634*c2e18aaaSAndroid Build Coastguard Worker@io_error_handle
635*c2e18aaaSAndroid Build Coastguard Workerdef file_generate(path, content):
636*c2e18aaaSAndroid Build Coastguard Worker    """Generate file from content.
637*c2e18aaaSAndroid Build Coastguard Worker
638*c2e18aaaSAndroid Build Coastguard Worker    Args:
639*c2e18aaaSAndroid Build Coastguard Worker        path: Path of target file.
640*c2e18aaaSAndroid Build Coastguard Worker        content: String content of file.
641*c2e18aaaSAndroid Build Coastguard Worker    """
642*c2e18aaaSAndroid Build Coastguard Worker    if not os.path.exists(os.path.dirname(path)):
643*c2e18aaaSAndroid Build Coastguard Worker        os.makedirs(os.path.dirname(path))
644*c2e18aaaSAndroid Build Coastguard Worker    with open(path, 'w', encoding='utf-8') as target:
645*c2e18aaaSAndroid Build Coastguard Worker        target.write(content)
646*c2e18aaaSAndroid Build Coastguard Worker
647*c2e18aaaSAndroid Build Coastguard Worker
648*c2e18aaaSAndroid Build Coastguard Workerdef get_lunch_target():
649*c2e18aaaSAndroid Build Coastguard Worker    """Gets the Android lunch target in current console.
650*c2e18aaaSAndroid Build Coastguard Worker
651*c2e18aaaSAndroid Build Coastguard Worker    Returns:
652*c2e18aaaSAndroid Build Coastguard Worker        A json format string of lunch target in current console.
653*c2e18aaaSAndroid Build Coastguard Worker    """
654*c2e18aaaSAndroid Build Coastguard Worker    product = os.environ.get(constant.TARGET_PRODUCT)
655*c2e18aaaSAndroid Build Coastguard Worker    build_variant = os.environ.get(constant.TARGET_BUILD_VARIANT)
656*c2e18aaaSAndroid Build Coastguard Worker    if product and build_variant:
657*c2e18aaaSAndroid Build Coastguard Worker        return json.dumps(
658*c2e18aaaSAndroid Build Coastguard Worker            {constant.LUNCH_TARGET: "-".join([product, build_variant])})
659*c2e18aaaSAndroid Build Coastguard Worker    return None
660*c2e18aaaSAndroid Build Coastguard Worker
661*c2e18aaaSAndroid Build Coastguard Worker
662*c2e18aaaSAndroid Build Coastguard Workerdef get_blueprint_json_files_relative_dict():
663*c2e18aaaSAndroid Build Coastguard Worker    """Gets a dictionary with key: environment variable, value: absolute path.
664*c2e18aaaSAndroid Build Coastguard Worker
665*c2e18aaaSAndroid Build Coastguard Worker    Returns:
666*c2e18aaaSAndroid Build Coastguard Worker        A dictionary  with key: environment variable and value: absolute path of
667*c2e18aaaSAndroid Build Coastguard Worker        the file generated by the environment variable.
668*c2e18aaaSAndroid Build Coastguard Worker    """
669*c2e18aaaSAndroid Build Coastguard Worker    data = {}
670*c2e18aaaSAndroid Build Coastguard Worker    root_dir = get_android_root_dir()
671*c2e18aaaSAndroid Build Coastguard Worker    bp_java_path = os.path.join(
672*c2e18aaaSAndroid Build Coastguard Worker        root_dir, get_blueprint_json_path(
673*c2e18aaaSAndroid Build Coastguard Worker            constant.BLUEPRINT_JAVA_JSONFILE_NAME))
674*c2e18aaaSAndroid Build Coastguard Worker    data[constant.GEN_JAVA_DEPS] = bp_java_path
675*c2e18aaaSAndroid Build Coastguard Worker    bp_cc_path = os.path.join(
676*c2e18aaaSAndroid Build Coastguard Worker        root_dir, get_blueprint_json_path(constant.BLUEPRINT_CC_JSONFILE_NAME))
677*c2e18aaaSAndroid Build Coastguard Worker    data[constant.GEN_CC_DEPS] = bp_cc_path
678*c2e18aaaSAndroid Build Coastguard Worker    data[constant.GEN_COMPDB] = os.path.join(get_soong_out_path(),
679*c2e18aaaSAndroid Build Coastguard Worker                                             constant.RELATIVE_COMPDB_PATH,
680*c2e18aaaSAndroid Build Coastguard Worker                                             constant.COMPDB_JSONFILE_NAME)
681*c2e18aaaSAndroid Build Coastguard Worker    data[constant.GEN_RUST] = os.path.join(
682*c2e18aaaSAndroid Build Coastguard Worker        root_dir, get_blueprint_json_path(constant.RUST_PROJECT_JSON))
683*c2e18aaaSAndroid Build Coastguard Worker    return data
684*c2e18aaaSAndroid Build Coastguard Worker
685*c2e18aaaSAndroid Build Coastguard Worker
686*c2e18aaaSAndroid Build Coastguard Workerdef to_pretty_xml(root, indent="  "):
687*c2e18aaaSAndroid Build Coastguard Worker    """Gets pretty xml from an xml.etree.ElementTree root.
688*c2e18aaaSAndroid Build Coastguard Worker
689*c2e18aaaSAndroid Build Coastguard Worker    Args:
690*c2e18aaaSAndroid Build Coastguard Worker        root: An element tree root.
691*c2e18aaaSAndroid Build Coastguard Worker        indent: The indent of XML.
692*c2e18aaaSAndroid Build Coastguard Worker    Returns:
693*c2e18aaaSAndroid Build Coastguard Worker        A string of pretty xml.
694*c2e18aaaSAndroid Build Coastguard Worker    """
695*c2e18aaaSAndroid Build Coastguard Worker    xml_string = xml.dom.minidom.parseString(
696*c2e18aaaSAndroid Build Coastguard Worker        ElementTree.tostring(root)).toprettyxml(indent)
697*c2e18aaaSAndroid Build Coastguard Worker    # Remove the xml declaration since IntelliJ doesn't use it.
698*c2e18aaaSAndroid Build Coastguard Worker    xml_string = xml_string.split("\n", 1)[1]
699*c2e18aaaSAndroid Build Coastguard Worker    # Remove the weird newline issue from toprettyxml.
700*c2e18aaaSAndroid Build Coastguard Worker    return os.linesep.join([s for s in xml_string.splitlines() if s.strip()])
701*c2e18aaaSAndroid Build Coastguard Worker
702*c2e18aaaSAndroid Build Coastguard Worker
703*c2e18aaaSAndroid Build Coastguard Workerdef to_boolean(str_bool):
704*c2e18aaaSAndroid Build Coastguard Worker    """Converts a string to a boolean.
705*c2e18aaaSAndroid Build Coastguard Worker
706*c2e18aaaSAndroid Build Coastguard Worker    Args:
707*c2e18aaaSAndroid Build Coastguard Worker        str_bool: A string in the expression of boolean type.
708*c2e18aaaSAndroid Build Coastguard Worker
709*c2e18aaaSAndroid Build Coastguard Worker    Returns:
710*c2e18aaaSAndroid Build Coastguard Worker        A boolean True if the string is one of ('True', 'true', 'T', 't', '1')
711*c2e18aaaSAndroid Build Coastguard Worker        else False.
712*c2e18aaaSAndroid Build Coastguard Worker    """
713*c2e18aaaSAndroid Build Coastguard Worker    return str_bool and str_bool.lower() in ('true', 't', '1')
714*c2e18aaaSAndroid Build Coastguard Worker
715*c2e18aaaSAndroid Build Coastguard Worker
716*c2e18aaaSAndroid Build Coastguard Workerdef find_git_root(relpath):
717*c2e18aaaSAndroid Build Coastguard Worker    """Finds the parent directory which has a .git folder from the relpath.
718*c2e18aaaSAndroid Build Coastguard Worker
719*c2e18aaaSAndroid Build Coastguard Worker    Args:
720*c2e18aaaSAndroid Build Coastguard Worker        relpath: A string of relative path.
721*c2e18aaaSAndroid Build Coastguard Worker
722*c2e18aaaSAndroid Build Coastguard Worker    Returns:
723*c2e18aaaSAndroid Build Coastguard Worker        A string of the absolute path which contains a .git, otherwise, none.
724*c2e18aaaSAndroid Build Coastguard Worker    """
725*c2e18aaaSAndroid Build Coastguard Worker    dir_list = relpath.split(os.sep)
726*c2e18aaaSAndroid Build Coastguard Worker    for i in range(len(dir_list), 0, -1):
727*c2e18aaaSAndroid Build Coastguard Worker        real_path = os.path.join(get_android_root_dir(),
728*c2e18aaaSAndroid Build Coastguard Worker                                 os.sep.join(dir_list[:i]),
729*c2e18aaaSAndroid Build Coastguard Worker                                 constant.GIT_FOLDER_NAME)
730*c2e18aaaSAndroid Build Coastguard Worker        if os.path.exists(real_path):
731*c2e18aaaSAndroid Build Coastguard Worker            return os.path.dirname(real_path)
732*c2e18aaaSAndroid Build Coastguard Worker    logging.warning('%s can\'t find its .git folder.', relpath)
733*c2e18aaaSAndroid Build Coastguard Worker    return None
734*c2e18aaaSAndroid Build Coastguard Worker
735*c2e18aaaSAndroid Build Coastguard Worker
736*c2e18aaaSAndroid Build Coastguard Workerdef determine_language_ide(lang, ide, jlist=None, clist=None, rlist=None):
737*c2e18aaaSAndroid Build Coastguard Worker    """Determines the language and IDE by the input language and IDE arguments.
738*c2e18aaaSAndroid Build Coastguard Worker
739*c2e18aaaSAndroid Build Coastguard Worker    If IDE and language are undefined, the priority of the language is:
740*c2e18aaaSAndroid Build Coastguard Worker      1. Java
741*c2e18aaaSAndroid Build Coastguard Worker      2. C/C++
742*c2e18aaaSAndroid Build Coastguard Worker      3. Rust
743*c2e18aaaSAndroid Build Coastguard Worker
744*c2e18aaaSAndroid Build Coastguard Worker    Args:
745*c2e18aaaSAndroid Build Coastguard Worker        lang: A character represents the input language.
746*c2e18aaaSAndroid Build Coastguard Worker        ide: A character represents the input IDE.
747*c2e18aaaSAndroid Build Coastguard Worker        jlist: A list of Android Java projects, the default value is None.
748*c2e18aaaSAndroid Build Coastguard Worker        clist: A list of Android C/C++ projects, the default value is None.
749*c2e18aaaSAndroid Build Coastguard Worker        rlist: A list of Android Rust projects, the default value is None.
750*c2e18aaaSAndroid Build Coastguard Worker
751*c2e18aaaSAndroid Build Coastguard Worker    Returns:
752*c2e18aaaSAndroid Build Coastguard Worker        A tuple of the determined language and IDE name strings.
753*c2e18aaaSAndroid Build Coastguard Worker    """
754*c2e18aaaSAndroid Build Coastguard Worker    if ide == _IDE_UNDEFINED and lang == constant.LANG_UNDEFINED:
755*c2e18aaaSAndroid Build Coastguard Worker        if jlist:
756*c2e18aaaSAndroid Build Coastguard Worker            lang = constant.LANG_JAVA
757*c2e18aaaSAndroid Build Coastguard Worker        elif clist:
758*c2e18aaaSAndroid Build Coastguard Worker            lang = constant.LANG_CC
759*c2e18aaaSAndroid Build Coastguard Worker        elif rlist:
760*c2e18aaaSAndroid Build Coastguard Worker            lang = constant.LANG_RUST
761*c2e18aaaSAndroid Build Coastguard Worker    if lang in (constant.LANG_UNDEFINED, constant.LANG_JAVA):
762*c2e18aaaSAndroid Build Coastguard Worker        if ide == _IDE_UNDEFINED:
763*c2e18aaaSAndroid Build Coastguard Worker            ide = _IDE_INTELLIJ
764*c2e18aaaSAndroid Build Coastguard Worker        lang = constant.LANG_JAVA
765*c2e18aaaSAndroid Build Coastguard Worker        if constant.IDE_NAME_DICT[ide] == constant.IDE_CLION:
766*c2e18aaaSAndroid Build Coastguard Worker            lang = constant.LANG_CC
767*c2e18aaaSAndroid Build Coastguard Worker    elif lang == constant.LANG_CC:
768*c2e18aaaSAndroid Build Coastguard Worker        if ide == _IDE_UNDEFINED:
769*c2e18aaaSAndroid Build Coastguard Worker            ide = _IDE_CLION
770*c2e18aaaSAndroid Build Coastguard Worker        if constant.IDE_NAME_DICT[ide] == constant.IDE_INTELLIJ:
771*c2e18aaaSAndroid Build Coastguard Worker            lang = constant.LANG_JAVA
772*c2e18aaaSAndroid Build Coastguard Worker    elif lang == constant.LANG_RUST:
773*c2e18aaaSAndroid Build Coastguard Worker        ide = _IDE_VSCODE
774*c2e18aaaSAndroid Build Coastguard Worker    return constant.LANGUAGE_NAME_DICT[lang], constant.IDE_NAME_DICT[ide]
775*c2e18aaaSAndroid Build Coastguard Worker
776*c2e18aaaSAndroid Build Coastguard Worker
777*c2e18aaaSAndroid Build Coastguard Workerdef check_java_or_kotlin_file_exists(abs_path):
778*c2e18aaaSAndroid Build Coastguard Worker    """Checks if any Java or Kotlin files exist in an abs_path directory.
779*c2e18aaaSAndroid Build Coastguard Worker
780*c2e18aaaSAndroid Build Coastguard Worker    Args:
781*c2e18aaaSAndroid Build Coastguard Worker        abs_path: A string of absolute path of a directory to be checked.
782*c2e18aaaSAndroid Build Coastguard Worker
783*c2e18aaaSAndroid Build Coastguard Worker    Returns:
784*c2e18aaaSAndroid Build Coastguard Worker        True if any Java or Kotlin files exist otherwise False.
785*c2e18aaaSAndroid Build Coastguard Worker    """
786*c2e18aaaSAndroid Build Coastguard Worker    for _, _, filenames in os.walk(abs_path):
787*c2e18aaaSAndroid Build Coastguard Worker        for extension in (constant.JAVA_FILES, constant.KOTLIN_FILES):
788*c2e18aaaSAndroid Build Coastguard Worker            if fnmatch.filter(filenames, extension):
789*c2e18aaaSAndroid Build Coastguard Worker                return True
790*c2e18aaaSAndroid Build Coastguard Worker    return False
791*c2e18aaaSAndroid Build Coastguard Worker
792*c2e18aaaSAndroid Build Coastguard Worker
793*c2e18aaaSAndroid Build Coastguard Worker@io_error_handle
794*c2e18aaaSAndroid Build Coastguard Workerdef unzip_file(src, dest):
795*c2e18aaaSAndroid Build Coastguard Worker    """Unzips the source zip file and extract it to the destination directory.
796*c2e18aaaSAndroid Build Coastguard Worker
797*c2e18aaaSAndroid Build Coastguard Worker    Args:
798*c2e18aaaSAndroid Build Coastguard Worker        src: A string of the file to be unzipped.
799*c2e18aaaSAndroid Build Coastguard Worker        dest: A string of the destination directory to be extracted to.
800*c2e18aaaSAndroid Build Coastguard Worker    """
801*c2e18aaaSAndroid Build Coastguard Worker    with zipfile.ZipFile(src, 'r') as zip_ref:
802*c2e18aaaSAndroid Build Coastguard Worker        zip_ref.extractall(dest)
803