15f9996aaSopenharmony_ci#!/usr/bin/env python
25f9996aaSopenharmony_ci# -*- coding: utf-8 -*-
35f9996aaSopenharmony_ci# Copyright (c) 2021 Huawei Device Co., Ltd.
45f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
55f9996aaSopenharmony_ci# you may not use this file except in compliance with the License.
65f9996aaSopenharmony_ci# You may obtain a copy of the License at
75f9996aaSopenharmony_ci#
85f9996aaSopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
95f9996aaSopenharmony_ci#
105f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software
115f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
125f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135f9996aaSopenharmony_ci# See the License for the specific language governing permissions and
145f9996aaSopenharmony_ci# limitations under the License.
155f9996aaSopenharmony_ci
165f9996aaSopenharmony_ciimport os
175f9996aaSopenharmony_ciimport sys
185f9996aaSopenharmony_ciimport argparse
195f9996aaSopenharmony_ci
205f9996aaSopenharmony_ci
215f9996aaSopenharmony_cisys.path.append(
225f9996aaSopenharmony_ci    os.path.dirname(os.path.dirname(os.path.dirname(
235f9996aaSopenharmony_ci        os.path.abspath(__file__)))))
245f9996aaSopenharmony_cifrom scripts.util.file_utils import read_json_file  # noqa: E402
255f9996aaSopenharmony_ci
265f9996aaSopenharmony_ci
275f9996aaSopenharmony_cidef check_third_party_deps(args, dep_part: str, parts_deps_info: dict, _tips_info: dict, third_deps_allow_list: list):
285f9996aaSopenharmony_ci    """check whether the three-party dependency is in the part declaration"""
295f9996aaSopenharmony_ci    if args.part_name == dep_part:
305f9996aaSopenharmony_ci        return
315f9996aaSopenharmony_ci    part_deps_info = parts_deps_info.get(args.part_name)
325f9996aaSopenharmony_ci    if not part_deps_info:
335f9996aaSopenharmony_ci        _warning_info = f"{_tips_info} {args.part_name}."
345f9996aaSopenharmony_ci    elif not part_deps_info.get('third_party') or \
355f9996aaSopenharmony_ci        not dep_part in part_deps_info.get('third_party'):
365f9996aaSopenharmony_ci        _warning_info = f"{_tips_info} {part_deps_info.get('build_config_file')}."
375f9996aaSopenharmony_ci    else:
385f9996aaSopenharmony_ci        _warning_info = ""
395f9996aaSopenharmony_ci
405f9996aaSopenharmony_ci    if _warning_info != "":
415f9996aaSopenharmony_ci        if args.target_path in third_deps_allow_list:
425f9996aaSopenharmony_ci            print(f"[0/0] WARNING: {_warning_info}")
435f9996aaSopenharmony_ci        else:
445f9996aaSopenharmony_ci            raise Exception(_warning_info)
455f9996aaSopenharmony_ci
465f9996aaSopenharmony_ci    return
475f9996aaSopenharmony_ci
485f9996aaSopenharmony_ci
495f9996aaSopenharmony_cidef load_part_info(depfiles: list):
505f9996aaSopenharmony_ci    """load part path info from parts_info"""
515f9996aaSopenharmony_ci    # load parts path info file
525f9996aaSopenharmony_ci    parts_path_file = 'build_configs/parts_info/parts_path_info.json'
535f9996aaSopenharmony_ci    parts_path_info = read_json_file(parts_path_file)
545f9996aaSopenharmony_ci    if parts_path_info is None:
555f9996aaSopenharmony_ci        raise Exception("read pre_build parts_path_info failed.")
565f9996aaSopenharmony_ci    depfiles.append(parts_path_file)
575f9996aaSopenharmony_ci
585f9996aaSopenharmony_ci    # load path to parts info file
595f9996aaSopenharmony_ci    path_parts_file = 'build_configs/parts_info/path_to_parts.json'
605f9996aaSopenharmony_ci    path_parts_info = read_json_file(path_parts_file)
615f9996aaSopenharmony_ci    if path_parts_info is None:
625f9996aaSopenharmony_ci        raise Exception("read pre_build path to parts failed.")
635f9996aaSopenharmony_ci    depfiles.append(path_parts_file)
645f9996aaSopenharmony_ci
655f9996aaSopenharmony_ci    return parts_path_info, path_parts_info
665f9996aaSopenharmony_ci
675f9996aaSopenharmony_ci
685f9996aaSopenharmony_cidef get_path_from_label(label: str):
695f9996aaSopenharmony_ci    """get part path from target label, the format is //path:module"""
705f9996aaSopenharmony_ci    return label.lstrip('//').split(':')[0]
715f9996aaSopenharmony_ci
725f9996aaSopenharmony_ci
735f9996aaSopenharmony_cidef get_path_from_module_list(cur_part_name: str, depfiles:list) -> str:
745f9996aaSopenharmony_ci    parts_module_lists = []
755f9996aaSopenharmony_ci    parts_modules_file = "build_configs/parts_info/parts_modules_info.json"
765f9996aaSopenharmony_ci    parts_modules_info = read_json_file(parts_modules_file)
775f9996aaSopenharmony_ci    if parts_modules_info is None:
785f9996aaSopenharmony_ci        raise Exception("read pre_build parts module info failed.")
795f9996aaSopenharmony_ci    depfiles.append(parts_modules_file)
805f9996aaSopenharmony_ci
815f9996aaSopenharmony_ci    for parts_module in parts_modules_info.get("parts"):
825f9996aaSopenharmony_ci        if parts_module.get("part_name") == cur_part_name:
835f9996aaSopenharmony_ci            parts_module_lists = parts_module["module_list"]
845f9996aaSopenharmony_ci            break
855f9996aaSopenharmony_ci    parts_path = [get_path_from_label(x) for x in parts_module_lists]
865f9996aaSopenharmony_ci
875f9996aaSopenharmony_ci    return parts_path
885f9996aaSopenharmony_ci
895f9996aaSopenharmony_ci
905f9996aaSopenharmony_cidef get_part_pattern(cur_part_name: str, parts_path_info: dict, path_parts_info: dict, depfiles: list) -> list:
915f9996aaSopenharmony_ci    """get all part path from part info"""
925f9996aaSopenharmony_ci    part_pattern = []
935f9996aaSopenharmony_ci    part_path = parts_path_info.get(cur_part_name)
945f9996aaSopenharmony_ci    if part_path is None:
955f9996aaSopenharmony_ci        return part_pattern
965f9996aaSopenharmony_ci
975f9996aaSopenharmony_ci    path_to_part = path_parts_info.get(part_path)
985f9996aaSopenharmony_ci    if len(path_to_part) == 1:
995f9996aaSopenharmony_ci        part_pattern.append(part_path)
1005f9996aaSopenharmony_ci    else:
1015f9996aaSopenharmony_ci        part_pattern.extend(get_path_from_module_list(cur_part_name, depfiles))
1025f9996aaSopenharmony_ci
1035f9996aaSopenharmony_ci    return part_pattern
1045f9996aaSopenharmony_ci
1055f9996aaSopenharmony_ci
1065f9996aaSopenharmony_cidef get_dep_part(dep_path: str, third_part_info: dict) -> str:
1075f9996aaSopenharmony_ci    """gets the part by the longest path match"""
1085f9996aaSopenharmony_ci    for part_info in third_part_info:
1095f9996aaSopenharmony_ci        path = part_info[0]
1105f9996aaSopenharmony_ci        part = part_info[1][0]
1115f9996aaSopenharmony_ci        if dep_path.find(path) != -1:
1125f9996aaSopenharmony_ci            return part
1135f9996aaSopenharmony_ci    return ""
1145f9996aaSopenharmony_ci
1155f9996aaSopenharmony_ci
1165f9996aaSopenharmony_cidef check_part_deps(args, part_pattern: str, path_parts_info: dict, compile_standard_allow_info: dict, depfiles: list):
1175f9996aaSopenharmony_ci    deps_allow_list = compile_standard_allow_info.get("deps_added_external_part_module", [])
1185f9996aaSopenharmony_ci    third_deps_allow_list = compile_standard_allow_info.get("third_deps_bundle_not_add", [])
1195f9996aaSopenharmony_ci    parts_deps_file = 'build_configs/parts_info/parts_deps.json'
1205f9996aaSopenharmony_ci    parts_deps_info = read_json_file(parts_deps_file)
1215f9996aaSopenharmony_ci    if parts_deps_info is None:
1225f9996aaSopenharmony_ci        raise Exception("read pre_build parts_deps failed.")
1235f9996aaSopenharmony_ci    depfiles.append(parts_deps_file)
1245f9996aaSopenharmony_ci
1255f9996aaSopenharmony_ci    parts_src_flag_file = "build_configs/parts_src_flag.json"
1265f9996aaSopenharmony_ci    parts_src_info = read_json_file(parts_src_flag_file)
1275f9996aaSopenharmony_ci    third_party_allow_list = os.path.join(args.source_root_dir, "out/products_ext/third_party_allow_list.json")
1285f9996aaSopenharmony_ci    if not os.path.exists(third_party_allow_list):
1295f9996aaSopenharmony_ci        third_party_allow_list = os.path.join(args.source_root_dir, "build/third_party_allow_list.json")
1305f9996aaSopenharmony_ci    third_party_allow_info = read_json_file(third_party_allow_list)
1315f9996aaSopenharmony_ci
1325f9996aaSopenharmony_ci    # filter third_party part info, sort by longest path match
1335f9996aaSopenharmony_ci    third_party_info = [x for x in path_parts_info.items() if x[0].find('third_party') != -1]
1345f9996aaSopenharmony_ci    third_party_info.reverse()
1355f9996aaSopenharmony_ci    for dep in args.deps:
1365f9996aaSopenharmony_ci        dep_path = get_path_from_label(dep)
1375f9996aaSopenharmony_ci        if dep_path.find('third_party/rust/crates') != -1:
1385f9996aaSopenharmony_ci            continue
1395f9996aaSopenharmony_ci        if dep_path.find('third_party') != -1:
1405f9996aaSopenharmony_ci            dep_part = get_dep_part(dep_path, third_party_info)
1415f9996aaSopenharmony_ci
1425f9996aaSopenharmony_ci            if dep_part not in parts_src_info and dep_part in third_party_allow_info:
1435f9996aaSopenharmony_ci                print(f"[0/0] WARNING: deps third_party '{dep_part}' not configured in part config json, "
1445f9996aaSopenharmony_ci                    f"target: '{args.target_path}', deps: '{dep}'")
1455f9996aaSopenharmony_ci            elif dep_part not in parts_src_info and dep_part not in third_party_allow_info:
1465f9996aaSopenharmony_ci                raise Exception(
1475f9996aaSopenharmony_ci                    f"deps third_party '{dep_part}' not configured in part config json, "
1485f9996aaSopenharmony_ci                    f"target: '{args.target_path}', deps: '{dep}'")
1495f9996aaSopenharmony_ci
1505f9996aaSopenharmony_ci            tips_info = "{} depend part {}, need set part deps {} info to".format(
1515f9996aaSopenharmony_ci                args.target_path, dep, dep_part)
1525f9996aaSopenharmony_ci            check_third_party_deps(args, dep_part, parts_deps_info, tips_info, third_deps_allow_list)
1535f9996aaSopenharmony_ci            continue
1545f9996aaSopenharmony_ci
1555f9996aaSopenharmony_ci        match_flag = False
1565f9996aaSopenharmony_ci        for pattern in part_pattern:
1575f9996aaSopenharmony_ci            if dep_path.startswith(pattern):
1585f9996aaSopenharmony_ci                match_flag = True
1595f9996aaSopenharmony_ci                break
1605f9996aaSopenharmony_ci        if match_flag is False:
1615f9996aaSopenharmony_ci            message = "deps validation part_name: '{}', target: '{}', dep: '{}' failed!!!".format(
1625f9996aaSopenharmony_ci                args.part_name, args.target_path, dep)
1635f9996aaSopenharmony_ci            if args.target_path in deps_allow_list:
1645f9996aaSopenharmony_ci                print(f"[0/0] WARNING:{message}")
1655f9996aaSopenharmony_ci            else:
1665f9996aaSopenharmony_ci                raise Exception(message)
1675f9996aaSopenharmony_ci
1685f9996aaSopenharmony_ci
1695f9996aaSopenharmony_cidef check(args) -> list:
1705f9996aaSopenharmony_ci    depfiles = []
1715f9996aaSopenharmony_ci    # ignore test related parts
1725f9996aaSopenharmony_ci    part_allow_set = {'libc-test', 'libc-test-lib', 'libc-gtest-lib'}
1735f9996aaSopenharmony_ci    if args.part_name in part_allow_set:
1745f9996aaSopenharmony_ci        return depfiles
1755f9996aaSopenharmony_ci
1765f9996aaSopenharmony_ci    compile_standard_allow_file = args.compile_standard_allow_file
1775f9996aaSopenharmony_ci    compile_standard_allow_info = read_json_file(compile_standard_allow_file)
1785f9996aaSopenharmony_ci    parts_path_info, path_parts_info = load_part_info(depfiles)
1795f9996aaSopenharmony_ci
1805f9996aaSopenharmony_ci    part_pattern = get_part_pattern(args.part_name, parts_path_info, path_parts_info, depfiles)
1815f9996aaSopenharmony_ci    if not part_pattern:
1825f9996aaSopenharmony_ci        gn_allow_list = compile_standard_allow_info.get("gn_part_or_subsystem_error", [])
1835f9996aaSopenharmony_ci        message = "part_name: '{}' path is not exist, please check target: '{}'".format(
1845f9996aaSopenharmony_ci            args.part_name, args.target_path)
1855f9996aaSopenharmony_ci        if args.target_path in gn_allow_list:
1865f9996aaSopenharmony_ci            print(f"[0/0] {message}")
1875f9996aaSopenharmony_ci            return depfiles
1885f9996aaSopenharmony_ci        else:
1895f9996aaSopenharmony_ci            raise Exception(message)
1905f9996aaSopenharmony_ci
1915f9996aaSopenharmony_ci    check_part_deps(args, part_pattern, path_parts_info, compile_standard_allow_info, depfiles)
1925f9996aaSopenharmony_ci
1935f9996aaSopenharmony_ci    return depfiles
1945f9996aaSopenharmony_ci
1955f9996aaSopenharmony_ci
1965f9996aaSopenharmony_cidef main():
1975f9996aaSopenharmony_ci    parser = argparse.ArgumentParser()
1985f9996aaSopenharmony_ci    parser.add_argument('--deps', nargs='*', required=True)
1995f9996aaSopenharmony_ci    parser.add_argument('--part-name', required=True)
2005f9996aaSopenharmony_ci    parser.add_argument('--target-path', required=True)
2015f9996aaSopenharmony_ci    parser.add_argument('--source-root-dir', required=True)
2025f9996aaSopenharmony_ci    args = parser.parse_args()
2035f9996aaSopenharmony_ci
2045f9996aaSopenharmony_ci    check(args)
2055f9996aaSopenharmony_ci
2065f9996aaSopenharmony_ci    return 0
2075f9996aaSopenharmony_ci
2085f9996aaSopenharmony_ci
2095f9996aaSopenharmony_ciif __name__ == '__main__':
2105f9996aaSopenharmony_ci    sys.exit(main())
211