xref: /aosp_15_r20/tools/asuite/aidegen/lib/module_info_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"""module_info_util
18*c2e18aaaSAndroid Build Coastguard Worker
19*c2e18aaaSAndroid Build Coastguard WorkerThis module receives a module path which is relative to its root directory and
20*c2e18aaaSAndroid Build Coastguard Workermakes a command to generate two json files, one for mk files and one for bp
21*c2e18aaaSAndroid Build Coastguard Workerfiles. Then it will load these two json files into two json dictionaries,
22*c2e18aaaSAndroid Build Coastguard Workermerge them into one dictionary and return the merged dictionary to its caller.
23*c2e18aaaSAndroid Build Coastguard Worker
24*c2e18aaaSAndroid Build Coastguard WorkerExample usage:
25*c2e18aaaSAndroid Build Coastguard Workermerged_dict = generate_merged_module_info()
26*c2e18aaaSAndroid Build Coastguard Worker"""
27*c2e18aaaSAndroid Build Coastguard Worker
28*c2e18aaaSAndroid Build Coastguard Workerimport glob
29*c2e18aaaSAndroid Build Coastguard Workerimport logging
30*c2e18aaaSAndroid Build Coastguard Workerimport os
31*c2e18aaaSAndroid Build Coastguard Workerimport sys
32*c2e18aaaSAndroid Build Coastguard Worker
33*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen import constant
34*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen.lib import common_util
35*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen.lib import errors
36*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen.lib import project_config
37*c2e18aaaSAndroid Build Coastguard Worker
38*c2e18aaaSAndroid Build Coastguard Workerfrom atest import atest_utils
39*c2e18aaaSAndroid Build Coastguard Worker
40*c2e18aaaSAndroid Build Coastguard Worker_MERGE_NEEDED_ITEMS = [
41*c2e18aaaSAndroid Build Coastguard Worker    constant.KEY_CLASS,
42*c2e18aaaSAndroid Build Coastguard Worker    constant.KEY_PATH,
43*c2e18aaaSAndroid Build Coastguard Worker    constant.KEY_INSTALLED,
44*c2e18aaaSAndroid Build Coastguard Worker    constant.KEY_DEPENDENCIES,
45*c2e18aaaSAndroid Build Coastguard Worker    constant.KEY_SRCS,
46*c2e18aaaSAndroid Build Coastguard Worker    constant.KEY_SRCJARS,
47*c2e18aaaSAndroid Build Coastguard Worker    constant.KEY_CLASSES_JAR,
48*c2e18aaaSAndroid Build Coastguard Worker    constant.KEY_TAG,
49*c2e18aaaSAndroid Build Coastguard Worker    constant.KEY_COMPATIBILITY,
50*c2e18aaaSAndroid Build Coastguard Worker    constant.KEY_AUTO_TEST_CONFIG,
51*c2e18aaaSAndroid Build Coastguard Worker    constant.KEY_MODULE_NAME,
52*c2e18aaaSAndroid Build Coastguard Worker    constant.KEY_TEST_CONFIG
53*c2e18aaaSAndroid Build Coastguard Worker]
54*c2e18aaaSAndroid Build Coastguard Worker_INTELLIJ_PROJECT_FILE_EXT = '*.iml'
55*c2e18aaaSAndroid Build Coastguard Worker_LAUNCH_PROJECT_QUERY = (
56*c2e18aaaSAndroid Build Coastguard Worker    'There exists an IntelliJ project file: %s. Do you want '
57*c2e18aaaSAndroid Build Coastguard Worker    'to launch it (yes/No)?')
58*c2e18aaaSAndroid Build Coastguard Worker_BUILD_BP_JSON_ENV_ON = {
59*c2e18aaaSAndroid Build Coastguard Worker    constant.GEN_JAVA_DEPS: 'true',
60*c2e18aaaSAndroid Build Coastguard Worker    constant.GEN_CC_DEPS: 'true',
61*c2e18aaaSAndroid Build Coastguard Worker    constant.GEN_COMPDB: 'true',
62*c2e18aaaSAndroid Build Coastguard Worker    constant.GEN_RUST: 'true'
63*c2e18aaaSAndroid Build Coastguard Worker}
64*c2e18aaaSAndroid Build Coastguard Worker_GEN_JSON_FAILED = (
65*c2e18aaaSAndroid Build Coastguard Worker    'Generate new {0} failed, AIDEGen will proceed and reuse the old {1}.')
66*c2e18aaaSAndroid Build Coastguard Worker_TARGET = 'nothing'
67*c2e18aaaSAndroid Build Coastguard Worker_LINKFILE_WARNING = (
68*c2e18aaaSAndroid Build Coastguard Worker    'File {} does not exist and we can not make a symbolic link for it.')
69*c2e18aaaSAndroid Build Coastguard Worker_RUST_PROJECT_JSON = 'out/soong/rust-project.json'
70*c2e18aaaSAndroid Build Coastguard Worker
71*c2e18aaaSAndroid Build Coastguard Worker
72*c2e18aaaSAndroid Build Coastguard Worker# Generators are slightly more inefficient when all the values have to be
73*c2e18aaaSAndroid Build Coastguard Worker# traversed most of the time.
74*c2e18aaaSAndroid Build Coastguard Worker# pylint: disable=use-a-generator
75*c2e18aaaSAndroid Build Coastguard Worker# pylint: disable=dangerous-default-value
76*c2e18aaaSAndroid Build Coastguard Worker@common_util.back_to_cwd
77*c2e18aaaSAndroid Build Coastguard Worker@common_util.time_logged
78*c2e18aaaSAndroid Build Coastguard Workerdef generate_merged_module_info(env_on=_BUILD_BP_JSON_ENV_ON):
79*c2e18aaaSAndroid Build Coastguard Worker    """Generate a merged dictionary.
80*c2e18aaaSAndroid Build Coastguard Worker
81*c2e18aaaSAndroid Build Coastguard Worker    Linked functions:
82*c2e18aaaSAndroid Build Coastguard Worker        _build_bp_info(module_info, project, skip_build)
83*c2e18aaaSAndroid Build Coastguard Worker        _get_soong_build_json_dict()
84*c2e18aaaSAndroid Build Coastguard Worker        _merge_dict(mk_dict, bp_dict)
85*c2e18aaaSAndroid Build Coastguard Worker
86*c2e18aaaSAndroid Build Coastguard Worker    Args:
87*c2e18aaaSAndroid Build Coastguard Worker        env_on: A dictionary of environment settings to be turned on, the
88*c2e18aaaSAndroid Build Coastguard Worker                default value is _BUILD_BP_JSON_ENV_ON.
89*c2e18aaaSAndroid Build Coastguard Worker
90*c2e18aaaSAndroid Build Coastguard Worker    Returns:
91*c2e18aaaSAndroid Build Coastguard Worker        A merged dictionary from module-info.json and module_bp_java_deps.json.
92*c2e18aaaSAndroid Build Coastguard Worker    """
93*c2e18aaaSAndroid Build Coastguard Worker    config = project_config.ProjectConfig.get_instance()
94*c2e18aaaSAndroid Build Coastguard Worker    module_info = config.atest_module_info
95*c2e18aaaSAndroid Build Coastguard Worker    projects = config.targets
96*c2e18aaaSAndroid Build Coastguard Worker    verbose = True
97*c2e18aaaSAndroid Build Coastguard Worker    skip_build = config.is_skip_build
98*c2e18aaaSAndroid Build Coastguard Worker    main_project = projects[0] if projects else None
99*c2e18aaaSAndroid Build Coastguard Worker    _build_bp_info(
100*c2e18aaaSAndroid Build Coastguard Worker        module_info, main_project, skip_build, env_on)
101*c2e18aaaSAndroid Build Coastguard Worker    json_path = common_util.get_blueprint_json_path(
102*c2e18aaaSAndroid Build Coastguard Worker        constant.BLUEPRINT_JAVA_JSONFILE_NAME)
103*c2e18aaaSAndroid Build Coastguard Worker    bp_dict = common_util.get_json_dict(json_path)
104*c2e18aaaSAndroid Build Coastguard Worker    return _merge_dict(module_info.name_to_module_info, bp_dict)
105*c2e18aaaSAndroid Build Coastguard Worker
106*c2e18aaaSAndroid Build Coastguard Worker
107*c2e18aaaSAndroid Build Coastguard Workerdef _build_bp_info(module_info, main_project=None,
108*c2e18aaaSAndroid Build Coastguard Worker                   skip_build=False, env_on=_BUILD_BP_JSON_ENV_ON):
109*c2e18aaaSAndroid Build Coastguard Worker    """Make nothing to create module_bp_java_deps.json, module_bp_cc_deps.json.
110*c2e18aaaSAndroid Build Coastguard Worker
111*c2e18aaaSAndroid Build Coastguard Worker    Use atest build method to build the target 'nothing' by setting env config
112*c2e18aaaSAndroid Build Coastguard Worker    SOONG_COLLECT_JAVA_DEPS to true to trigger the process of collecting
113*c2e18aaaSAndroid Build Coastguard Worker    dependencies and generate module_bp_java_deps.json etc.
114*c2e18aaaSAndroid Build Coastguard Worker
115*c2e18aaaSAndroid Build Coastguard Worker    Args:
116*c2e18aaaSAndroid Build Coastguard Worker        module_info: A ModuleInfo instance contains data of module-info.json.
117*c2e18aaaSAndroid Build Coastguard Worker        main_project: A string of the main project name.
118*c2e18aaaSAndroid Build Coastguard Worker        skip_build: A boolean, if true, skip building if
119*c2e18aaaSAndroid Build Coastguard Worker                    get_blueprint_json_path(file_name) file exists, otherwise
120*c2e18aaaSAndroid Build Coastguard Worker                    build it.
121*c2e18aaaSAndroid Build Coastguard Worker        env_on: A dictionary of environment settings to be turned on, the
122*c2e18aaaSAndroid Build Coastguard Worker                default value is _BUILD_BP_JSON_ENV_ON.
123*c2e18aaaSAndroid Build Coastguard Worker
124*c2e18aaaSAndroid Build Coastguard Worker    Build results:
125*c2e18aaaSAndroid Build Coastguard Worker        1. Build successfully return.
126*c2e18aaaSAndroid Build Coastguard Worker        2. Build failed:
127*c2e18aaaSAndroid Build Coastguard Worker           1) There's no project file, raise BuildFailureError.
128*c2e18aaaSAndroid Build Coastguard Worker           2) There exists a project file, ask users if they want to
129*c2e18aaaSAndroid Build Coastguard Worker              launch IDE with the old project file.
130*c2e18aaaSAndroid Build Coastguard Worker              a) If the answer is yes, return.
131*c2e18aaaSAndroid Build Coastguard Worker              b) If the answer is not yes, sys.exit(1)
132*c2e18aaaSAndroid Build Coastguard Worker    """
133*c2e18aaaSAndroid Build Coastguard Worker    file_paths = _get_generated_json_files(env_on)
134*c2e18aaaSAndroid Build Coastguard Worker    files_exist = all([os.path.isfile(fpath) for fpath in file_paths])
135*c2e18aaaSAndroid Build Coastguard Worker    files = '\n'.join(file_paths)
136*c2e18aaaSAndroid Build Coastguard Worker    if skip_build and files_exist:
137*c2e18aaaSAndroid Build Coastguard Worker        logging.info('Files:\n%s exist, skipping build.', files)
138*c2e18aaaSAndroid Build Coastguard Worker        return
139*c2e18aaaSAndroid Build Coastguard Worker    original_file_mtimes = {f: None for f in file_paths}
140*c2e18aaaSAndroid Build Coastguard Worker    if files_exist:
141*c2e18aaaSAndroid Build Coastguard Worker        original_file_mtimes = {f: os.path.getmtime(f) for f in file_paths}
142*c2e18aaaSAndroid Build Coastguard Worker
143*c2e18aaaSAndroid Build Coastguard Worker    logging.warning(
144*c2e18aaaSAndroid Build Coastguard Worker        '\nGenerate files:\n %s by atest build method.', files)
145*c2e18aaaSAndroid Build Coastguard Worker    atest_utils.update_build_env(env_on)
146*c2e18aaaSAndroid Build Coastguard Worker    build_with_on_cmd = atest_utils.build([_TARGET])
147*c2e18aaaSAndroid Build Coastguard Worker
148*c2e18aaaSAndroid Build Coastguard Worker    # For Android Rust projects, we need to create a symbolic link to the file
149*c2e18aaaSAndroid Build Coastguard Worker    # out/soong/rust-project.json to launch the rust projects in IDEs.
150*c2e18aaaSAndroid Build Coastguard Worker    _generate_rust_project_link()
151*c2e18aaaSAndroid Build Coastguard Worker
152*c2e18aaaSAndroid Build Coastguard Worker    if build_with_on_cmd:
153*c2e18aaaSAndroid Build Coastguard Worker        logging.info('Generate blueprint json successfully.')
154*c2e18aaaSAndroid Build Coastguard Worker    else:
155*c2e18aaaSAndroid Build Coastguard Worker        if not all([_is_new_json_file_generated(
156*c2e18aaaSAndroid Build Coastguard Worker                f, original_file_mtimes[f]) for f in file_paths]):
157*c2e18aaaSAndroid Build Coastguard Worker            if files_exist:
158*c2e18aaaSAndroid Build Coastguard Worker                _show_files_reuse_message(file_paths)
159*c2e18aaaSAndroid Build Coastguard Worker            else:
160*c2e18aaaSAndroid Build Coastguard Worker                _show_build_failed_message(module_info, main_project)
161*c2e18aaaSAndroid Build Coastguard Worker
162*c2e18aaaSAndroid Build Coastguard Worker
163*c2e18aaaSAndroid Build Coastguard Workerdef _get_generated_json_files(env_on=_BUILD_BP_JSON_ENV_ON):
164*c2e18aaaSAndroid Build Coastguard Worker    """Gets the absolute paths of the files which is going to be generated.
165*c2e18aaaSAndroid Build Coastguard Worker
166*c2e18aaaSAndroid Build Coastguard Worker    Determine the files which will be generated by the environment on dictionary
167*c2e18aaaSAndroid Build Coastguard Worker    and the default blueprint json files' dictionary.
168*c2e18aaaSAndroid Build Coastguard Worker    The generation of json files depends on env_on. If the env_on looks like,
169*c2e18aaaSAndroid Build Coastguard Worker    _BUILD_BP_JSON_ENV_ON = {
170*c2e18aaaSAndroid Build Coastguard Worker        'SOONG_COLLECT_JAVA_DEPS': 'true',
171*c2e18aaaSAndroid Build Coastguard Worker        'SOONG_COLLECT_CC_DEPS': 'true',
172*c2e18aaaSAndroid Build Coastguard Worker        'SOONG_GEN_COMPDB': 'true',
173*c2e18aaaSAndroid Build Coastguard Worker        'SOONG_GEN_RUST_PROJECT': 'true'
174*c2e18aaaSAndroid Build Coastguard Worker    }
175*c2e18aaaSAndroid Build Coastguard Worker    We want to generate 4 files: module_bp_java_deps.json,
176*c2e18aaaSAndroid Build Coastguard Worker    module_bp_cc_deps.json, compile_commands.json and rust-project.json. And in
177*c2e18aaaSAndroid Build Coastguard Worker    get_blueprint_json_files_relative_dict function, there are 4 json files
178*c2e18aaaSAndroid Build Coastguard Worker    by default and return a result list of the absolute paths of the existent
179*c2e18aaaSAndroid Build Coastguard Worker    files.
180*c2e18aaaSAndroid Build Coastguard Worker
181*c2e18aaaSAndroid Build Coastguard Worker    Args:
182*c2e18aaaSAndroid Build Coastguard Worker        env_on: A dictionary of environment settings to be turned on, the
183*c2e18aaaSAndroid Build Coastguard Worker                default value is _BUILD_BP_JSON_ENV_ON.
184*c2e18aaaSAndroid Build Coastguard Worker
185*c2e18aaaSAndroid Build Coastguard Worker    Returns:
186*c2e18aaaSAndroid Build Coastguard Worker        A list of the absolute paths of the files which is going to be
187*c2e18aaaSAndroid Build Coastguard Worker        generated.
188*c2e18aaaSAndroid Build Coastguard Worker    """
189*c2e18aaaSAndroid Build Coastguard Worker    json_files_dict = common_util.get_blueprint_json_files_relative_dict()
190*c2e18aaaSAndroid Build Coastguard Worker    file_paths = []
191*c2e18aaaSAndroid Build Coastguard Worker    for key in env_on:
192*c2e18aaaSAndroid Build Coastguard Worker        if not env_on[key] == 'true' or key not in json_files_dict:
193*c2e18aaaSAndroid Build Coastguard Worker            continue
194*c2e18aaaSAndroid Build Coastguard Worker        file_paths.append(json_files_dict[key])
195*c2e18aaaSAndroid Build Coastguard Worker    return file_paths
196*c2e18aaaSAndroid Build Coastguard Worker
197*c2e18aaaSAndroid Build Coastguard Worker
198*c2e18aaaSAndroid Build Coastguard Workerdef _show_files_reuse_message(file_paths):
199*c2e18aaaSAndroid Build Coastguard Worker    """Shows the message of build failure but files existing and reusing them.
200*c2e18aaaSAndroid Build Coastguard Worker
201*c2e18aaaSAndroid Build Coastguard Worker    Args:
202*c2e18aaaSAndroid Build Coastguard Worker        file_paths: A list of absolute file paths to be checked.
203*c2e18aaaSAndroid Build Coastguard Worker    """
204*c2e18aaaSAndroid Build Coastguard Worker    failed_or_file = ' or '.join(file_paths)
205*c2e18aaaSAndroid Build Coastguard Worker    failed_and_file = ' and '.join(file_paths)
206*c2e18aaaSAndroid Build Coastguard Worker    message = _GEN_JSON_FAILED.format(failed_or_file, failed_and_file)
207*c2e18aaaSAndroid Build Coastguard Worker    print(constant.WARN_MSG.format(
208*c2e18aaaSAndroid Build Coastguard Worker        common_util.COLORED_INFO('Warning:'), message))
209*c2e18aaaSAndroid Build Coastguard Worker
210*c2e18aaaSAndroid Build Coastguard Worker
211*c2e18aaaSAndroid Build Coastguard Workerdef _show_build_failed_message(module_info, main_project=None):
212*c2e18aaaSAndroid Build Coastguard Worker    """Show build failed message.
213*c2e18aaaSAndroid Build Coastguard Worker
214*c2e18aaaSAndroid Build Coastguard Worker    Args:
215*c2e18aaaSAndroid Build Coastguard Worker        module_info: A ModuleInfo instance contains data of module-info.json.
216*c2e18aaaSAndroid Build Coastguard Worker        main_project: A string of the main project name.
217*c2e18aaaSAndroid Build Coastguard Worker    """
218*c2e18aaaSAndroid Build Coastguard Worker    if main_project:
219*c2e18aaaSAndroid Build Coastguard Worker        _, main_project_path = common_util.get_related_paths(
220*c2e18aaaSAndroid Build Coastguard Worker            module_info, main_project)
221*c2e18aaaSAndroid Build Coastguard Worker        _build_failed_handle(main_project_path)
222*c2e18aaaSAndroid Build Coastguard Worker
223*c2e18aaaSAndroid Build Coastguard Worker
224*c2e18aaaSAndroid Build Coastguard Workerdef _is_new_json_file_generated(json_path, original_file_mtime):
225*c2e18aaaSAndroid Build Coastguard Worker    """Check the new file is generated or not.
226*c2e18aaaSAndroid Build Coastguard Worker
227*c2e18aaaSAndroid Build Coastguard Worker    Args:
228*c2e18aaaSAndroid Build Coastguard Worker        json_path: The path of the json file being to check.
229*c2e18aaaSAndroid Build Coastguard Worker        original_file_mtime: the original file modified time.
230*c2e18aaaSAndroid Build Coastguard Worker
231*c2e18aaaSAndroid Build Coastguard Worker    Returns:
232*c2e18aaaSAndroid Build Coastguard Worker        A boolean, True if the json_path file is new generated, otherwise False.
233*c2e18aaaSAndroid Build Coastguard Worker    """
234*c2e18aaaSAndroid Build Coastguard Worker    if not os.path.isfile(json_path):
235*c2e18aaaSAndroid Build Coastguard Worker        return False
236*c2e18aaaSAndroid Build Coastguard Worker    return original_file_mtime != os.path.getmtime(json_path)
237*c2e18aaaSAndroid Build Coastguard Worker
238*c2e18aaaSAndroid Build Coastguard Worker
239*c2e18aaaSAndroid Build Coastguard Workerdef _build_failed_handle(main_project_path):
240*c2e18aaaSAndroid Build Coastguard Worker    """Handle build failures.
241*c2e18aaaSAndroid Build Coastguard Worker
242*c2e18aaaSAndroid Build Coastguard Worker    Args:
243*c2e18aaaSAndroid Build Coastguard Worker        main_project_path: The main project directory.
244*c2e18aaaSAndroid Build Coastguard Worker
245*c2e18aaaSAndroid Build Coastguard Worker    Handle results:
246*c2e18aaaSAndroid Build Coastguard Worker        1) There's no project file, raise BuildFailureError.
247*c2e18aaaSAndroid Build Coastguard Worker        2) There exists a project file, ask users if they want to
248*c2e18aaaSAndroid Build Coastguard Worker           launch IDE with the old project file.
249*c2e18aaaSAndroid Build Coastguard Worker           a) If the answer is yes, return.
250*c2e18aaaSAndroid Build Coastguard Worker           b) If the answer is not yes, sys.exit(1)
251*c2e18aaaSAndroid Build Coastguard Worker    """
252*c2e18aaaSAndroid Build Coastguard Worker    project_file = glob.glob(
253*c2e18aaaSAndroid Build Coastguard Worker        os.path.join(main_project_path, _INTELLIJ_PROJECT_FILE_EXT))
254*c2e18aaaSAndroid Build Coastguard Worker    if project_file:
255*c2e18aaaSAndroid Build Coastguard Worker        query = _LAUNCH_PROJECT_QUERY % project_file[0]
256*c2e18aaaSAndroid Build Coastguard Worker        input_data = input(query)
257*c2e18aaaSAndroid Build Coastguard Worker        if not input_data.lower() in ['yes', 'y']:
258*c2e18aaaSAndroid Build Coastguard Worker            sys.exit(1)
259*c2e18aaaSAndroid Build Coastguard Worker    else:
260*c2e18aaaSAndroid Build Coastguard Worker        raise errors.BuildFailureError(
261*c2e18aaaSAndroid Build Coastguard Worker            'Failed to generate %s.' % common_util.get_blueprint_json_path(
262*c2e18aaaSAndroid Build Coastguard Worker                constant.BLUEPRINT_JAVA_JSONFILE_NAME))
263*c2e18aaaSAndroid Build Coastguard Worker
264*c2e18aaaSAndroid Build Coastguard Worker
265*c2e18aaaSAndroid Build Coastguard Workerdef _merge_module_keys(m_dict, b_dict):
266*c2e18aaaSAndroid Build Coastguard Worker    """Merge a module's dictionary into another module's dictionary.
267*c2e18aaaSAndroid Build Coastguard Worker
268*c2e18aaaSAndroid Build Coastguard Worker    Merge b_dict module data into m_dict.
269*c2e18aaaSAndroid Build Coastguard Worker
270*c2e18aaaSAndroid Build Coastguard Worker    Args:
271*c2e18aaaSAndroid Build Coastguard Worker        m_dict: The module dictionary is going to merge b_dict into.
272*c2e18aaaSAndroid Build Coastguard Worker        b_dict: Soong build system module dictionary.
273*c2e18aaaSAndroid Build Coastguard Worker    """
274*c2e18aaaSAndroid Build Coastguard Worker    for key, b_modules in b_dict.items():
275*c2e18aaaSAndroid Build Coastguard Worker        m_dict[key] = sorted(list(set(m_dict.get(key, []) + b_modules)))
276*c2e18aaaSAndroid Build Coastguard Worker
277*c2e18aaaSAndroid Build Coastguard Worker
278*c2e18aaaSAndroid Build Coastguard Workerdef _copy_needed_items_from(mk_dict):
279*c2e18aaaSAndroid Build Coastguard Worker    """Shallow copy needed items from Make build system module info dictionary.
280*c2e18aaaSAndroid Build Coastguard Worker
281*c2e18aaaSAndroid Build Coastguard Worker    Args:
282*c2e18aaaSAndroid Build Coastguard Worker        mk_dict: Make build system dictionary is going to be copied.
283*c2e18aaaSAndroid Build Coastguard Worker
284*c2e18aaaSAndroid Build Coastguard Worker    Returns:
285*c2e18aaaSAndroid Build Coastguard Worker        A merged dictionary.
286*c2e18aaaSAndroid Build Coastguard Worker    """
287*c2e18aaaSAndroid Build Coastguard Worker    merged_dict = {}
288*c2e18aaaSAndroid Build Coastguard Worker    for module in mk_dict.keys():
289*c2e18aaaSAndroid Build Coastguard Worker        merged_dict[module] = {}
290*c2e18aaaSAndroid Build Coastguard Worker        for key in mk_dict[module].keys():
291*c2e18aaaSAndroid Build Coastguard Worker            if key in _MERGE_NEEDED_ITEMS and mk_dict[module][key] != []:
292*c2e18aaaSAndroid Build Coastguard Worker                merged_dict[module][key] = mk_dict[module][key]
293*c2e18aaaSAndroid Build Coastguard Worker    return merged_dict
294*c2e18aaaSAndroid Build Coastguard Worker
295*c2e18aaaSAndroid Build Coastguard Worker
296*c2e18aaaSAndroid Build Coastguard Workerdef _merge_dict(mk_dict, bp_dict):
297*c2e18aaaSAndroid Build Coastguard Worker    """Merge two dictionaries.
298*c2e18aaaSAndroid Build Coastguard Worker
299*c2e18aaaSAndroid Build Coastguard Worker    Linked function:
300*c2e18aaaSAndroid Build Coastguard Worker        _merge_module_keys(m_dict, b_dict)
301*c2e18aaaSAndroid Build Coastguard Worker
302*c2e18aaaSAndroid Build Coastguard Worker    Args:
303*c2e18aaaSAndroid Build Coastguard Worker        mk_dict: Make build system module info dictionary.
304*c2e18aaaSAndroid Build Coastguard Worker        bp_dict: Soong build system module info dictionary.
305*c2e18aaaSAndroid Build Coastguard Worker
306*c2e18aaaSAndroid Build Coastguard Worker    Returns:
307*c2e18aaaSAndroid Build Coastguard Worker        A merged dictionary.
308*c2e18aaaSAndroid Build Coastguard Worker    """
309*c2e18aaaSAndroid Build Coastguard Worker    merged_dict = _copy_needed_items_from(mk_dict)
310*c2e18aaaSAndroid Build Coastguard Worker    for module in bp_dict.keys():
311*c2e18aaaSAndroid Build Coastguard Worker        if module not in merged_dict:
312*c2e18aaaSAndroid Build Coastguard Worker            merged_dict[module] = {}
313*c2e18aaaSAndroid Build Coastguard Worker        _merge_module_keys(merged_dict[module], bp_dict[module])
314*c2e18aaaSAndroid Build Coastguard Worker    return merged_dict
315*c2e18aaaSAndroid Build Coastguard Worker
316*c2e18aaaSAndroid Build Coastguard Worker
317*c2e18aaaSAndroid Build Coastguard Workerdef _generate_rust_project_link():
318*c2e18aaaSAndroid Build Coastguard Worker    """Generates out/soong/rust-project.json symbolic link in Android root."""
319*c2e18aaaSAndroid Build Coastguard Worker    root_dir = common_util.get_android_root_dir()
320*c2e18aaaSAndroid Build Coastguard Worker    rust_project = os.path.join(
321*c2e18aaaSAndroid Build Coastguard Worker        root_dir, common_util.get_blueprint_json_path(
322*c2e18aaaSAndroid Build Coastguard Worker            constant.RUST_PROJECT_JSON))
323*c2e18aaaSAndroid Build Coastguard Worker    if not os.path.isfile(rust_project):
324*c2e18aaaSAndroid Build Coastguard Worker        message = _LINKFILE_WARNING.format(_RUST_PROJECT_JSON)
325*c2e18aaaSAndroid Build Coastguard Worker        print(constant.WARN_MSG.format(
326*c2e18aaaSAndroid Build Coastguard Worker            common_util.COLORED_INFO('Warning:'), message))
327*c2e18aaaSAndroid Build Coastguard Worker        return
328*c2e18aaaSAndroid Build Coastguard Worker    link_rust = os.path.join(root_dir, constant.RUST_PROJECT_JSON)
329*c2e18aaaSAndroid Build Coastguard Worker    if os.path.islink(link_rust):
330*c2e18aaaSAndroid Build Coastguard Worker        os.remove(link_rust)
331*c2e18aaaSAndroid Build Coastguard Worker    os.symlink(rust_project, link_rust)
332