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 sys
175f9996aaSopenharmony_ciimport argparse
185f9996aaSopenharmony_ciimport os
195f9996aaSopenharmony_ciimport shutil
205f9996aaSopenharmony_ciimport stat
215f9996aaSopenharmony_ci
225f9996aaSopenharmony_cisys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
235f9996aaSopenharmony_cifrom scripts.util.file_utils import read_json_file, write_json_file  # noqa: E402
245f9996aaSopenharmony_cifrom scripts.util import build_utils  # noqa: E402
255f9996aaSopenharmony_ci
265f9996aaSopenharmony_ciREADME_FILE_NAME = 'README.OpenSource'
275f9996aaSopenharmony_ciLICENSE_CANDIDATES = [
285f9996aaSopenharmony_ci    'LICENSE',
295f9996aaSopenharmony_ci    'License',
305f9996aaSopenharmony_ci    'NOTICE',
315f9996aaSopenharmony_ci    'Notice',
325f9996aaSopenharmony_ci    'COPYRIGHT',
335f9996aaSopenharmony_ci    'Copyright',
345f9996aaSopenharmony_ci    'COPYING',
355f9996aaSopenharmony_ci    'Copying'
365f9996aaSopenharmony_ci]
375f9996aaSopenharmony_ci
385f9996aaSopenharmony_ci
395f9996aaSopenharmony_cidef is_top_dir(current_dir: str):
405f9996aaSopenharmony_ci    return os.path.exists(os.path.join(current_dir, '.gn'))
415f9996aaSopenharmony_ci
425f9996aaSopenharmony_ci
435f9996aaSopenharmony_cidef find_other_files(license_file_path):
445f9996aaSopenharmony_ci    other_files = []
455f9996aaSopenharmony_ci    if os.path.isfile(license_file_path):
465f9996aaSopenharmony_ci        license_dir = os.path.dirname(license_file_path)
475f9996aaSopenharmony_ci        license_file = os.path.basename(license_file_path)
485f9996aaSopenharmony_ci        for file in LICENSE_CANDIDATES:
495f9996aaSopenharmony_ci            license_path = os.path.join(license_dir, file)
505f9996aaSopenharmony_ci            if os.path.isfile(license_path) and file != license_file and \
515f9996aaSopenharmony_ci                    license_path not in other_files:
525f9996aaSopenharmony_ci                other_files.append(license_path)
535f9996aaSopenharmony_ci    elif os.path.isdir(license_file_path):
545f9996aaSopenharmony_ci        for file in ['COPYRIGHT', 'Copyright', 'COPYING', 'Copying']:
555f9996aaSopenharmony_ci            license_file = os.path.join(license_file_path, file)
565f9996aaSopenharmony_ci            if os.path.isfile(license_file):
575f9996aaSopenharmony_ci                other_files.append(license_file)
585f9996aaSopenharmony_ci    return other_files
595f9996aaSopenharmony_ci
605f9996aaSopenharmony_ci
615f9996aaSopenharmony_cidef find_file_recursively(current_dir: str, target_files: list):
625f9996aaSopenharmony_ci    if is_top_dir(current_dir):
635f9996aaSopenharmony_ci        return None
645f9996aaSopenharmony_ci    for file in target_files:
655f9996aaSopenharmony_ci        candidate = os.path.join(current_dir, file)
665f9996aaSopenharmony_ci        if os.path.isfile(candidate):
675f9996aaSopenharmony_ci            return candidate
685f9996aaSopenharmony_ci    return find_file_recursively(os.path.dirname(current_dir), target_files)
695f9996aaSopenharmony_ci
705f9996aaSopenharmony_ci
715f9996aaSopenharmony_cidef find_license(current_dir: str):
725f9996aaSopenharmony_ci    return find_file_recursively(current_dir, LICENSE_CANDIDATES)
735f9996aaSopenharmony_ci
745f9996aaSopenharmony_ci
755f9996aaSopenharmony_cidef find_opensource(current_dir: str):
765f9996aaSopenharmony_ci    return find_file_recursively(current_dir, [README_FILE_NAME])
775f9996aaSopenharmony_ci
785f9996aaSopenharmony_ci
795f9996aaSopenharmony_cidef get_license_from_readme(readme_path: str):
805f9996aaSopenharmony_ci    contents = read_json_file(readme_path)
815f9996aaSopenharmony_ci    if contents is None:
825f9996aaSopenharmony_ci        raise Exception("Error: failed to read {}.".format(readme_path))
835f9996aaSopenharmony_ci
845f9996aaSopenharmony_ci    if len(contents) <= 1:
855f9996aaSopenharmony_ci        notice_file = contents[0].get('License File').strip()
865f9996aaSopenharmony_ci        notice_name = contents[0].get('Name').strip()
875f9996aaSopenharmony_ci        notice_version = contents[0].get('Version Number').strip()
885f9996aaSopenharmony_ci        if notice_file is None:
895f9996aaSopenharmony_ci            raise Exception("Error: value of notice file is empty in {}.".format(
905f9996aaSopenharmony_ci                readme_path))
915f9996aaSopenharmony_ci        if notice_name is None:
925f9996aaSopenharmony_ci            raise Exception("Error: Name of notice file is empty in {}.".format(
935f9996aaSopenharmony_ci                readme_path))
945f9996aaSopenharmony_ci        if notice_version is None:
955f9996aaSopenharmony_ci            raise Exception("Error: Version Number of notice file is empty in {}.".format(
965f9996aaSopenharmony_ci                readme_path))
975f9996aaSopenharmony_ci
985f9996aaSopenharmony_ci        return os.path.join(os.path.dirname(readme_path), notice_file), notice_name, notice_version
995f9996aaSopenharmony_ci    else:
1005f9996aaSopenharmony_ci        notice_files = []
1015f9996aaSopenharmony_ci        notice_names = []
1025f9996aaSopenharmony_ci        notice_versions = []
1035f9996aaSopenharmony_ci        for content in contents:
1045f9996aaSopenharmony_ci            notice_files.append(content.get('License File').strip())
1055f9996aaSopenharmony_ci            notice_names.append(content.get('Name').strip())
1065f9996aaSopenharmony_ci            notice_versions.append(content.get('Version Number').strip())
1075f9996aaSopenharmony_ci
1085f9996aaSopenharmony_ci        if notice_files is None:
1095f9996aaSopenharmony_ci            raise Exception("Error: value of notice file is empty in {}.".format(
1105f9996aaSopenharmony_ci                readme_path))
1115f9996aaSopenharmony_ci        if notice_names is None:
1125f9996aaSopenharmony_ci            raise Exception("Error: Name of notice file is empty in {}.".format(
1135f9996aaSopenharmony_ci                readme_path))
1145f9996aaSopenharmony_ci        if notice_versions is None:
1155f9996aaSopenharmony_ci            raise Exception("Error: Version Number of notice file is empty in {}.".format(
1165f9996aaSopenharmony_ci                readme_path))
1175f9996aaSopenharmony_ci
1185f9996aaSopenharmony_ci        return [os.path.join(os.path.dirname(readme_path), file) for file in notice_files], \
1195f9996aaSopenharmony_ci            notice_names, notice_versions
1205f9996aaSopenharmony_ci
1215f9996aaSopenharmony_ci
1225f9996aaSopenharmony_cidef add_path_to_module_notice(module_notice_info, module_notice_info_list, options):
1235f9996aaSopenharmony_ci    if isinstance(module_notice_info.get('Software', None), list):
1245f9996aaSopenharmony_ci        softwares = module_notice_info.get('Software')
1255f9996aaSopenharmony_ci        versions = module_notice_info.get('Version')
1265f9996aaSopenharmony_ci        for software, version in zip(softwares, versions):
1275f9996aaSopenharmony_ci            module_notice_info_list.append({'Software': software, 'Version': version})
1285f9996aaSopenharmony_ci        module_notice_info_list[-1]['Path'] = "/{}".format(options.module_source_dir[5:])
1295f9996aaSopenharmony_ci    else:
1305f9996aaSopenharmony_ci        if module_notice_info.get('Software', None):
1315f9996aaSopenharmony_ci            module_notice_info['Path'] = "/{}".format(options.module_source_dir[5:])
1325f9996aaSopenharmony_ci            module_notice_info_list.append(module_notice_info)
1335f9996aaSopenharmony_ci    if module_notice_info_list:
1345f9996aaSopenharmony_ci        for module_notice_info in module_notice_info_list:
1355f9996aaSopenharmony_ci            module_path = module_notice_info.get("Path", None)
1365f9996aaSopenharmony_ci            if module_path is not None:
1375f9996aaSopenharmony_ci                module_notice_info["Path"] = module_path.replace("../", "")
1385f9996aaSopenharmony_ci
1395f9996aaSopenharmony_ci
1405f9996aaSopenharmony_cidef do_collect_notice_files(options, depfiles: str):
1415f9996aaSopenharmony_ci    module_notice_info_list = []
1425f9996aaSopenharmony_ci    module_notice_info = {}
1435f9996aaSopenharmony_ci    notice_file = options.license_file
1445f9996aaSopenharmony_ci    other_files = []
1455f9996aaSopenharmony_ci    if notice_file:
1465f9996aaSopenharmony_ci        opensource_file = find_opensource(os.path.abspath(options.module_source_dir))
1475f9996aaSopenharmony_ci        if opensource_file is not None and os.path.exists(opensource_file):
1485f9996aaSopenharmony_ci            other_files.extend(find_other_files(opensource_file))
1495f9996aaSopenharmony_ci            notice_file_info = get_license_from_readme(opensource_file)
1505f9996aaSopenharmony_ci            module_notice_info['Software'] = notice_file_info[1]
1515f9996aaSopenharmony_ci            module_notice_info['Version'] = notice_file_info[2]
1525f9996aaSopenharmony_ci        else:
1535f9996aaSopenharmony_ci            module_notice_info['Software'] = ""
1545f9996aaSopenharmony_ci            module_notice_info['Version'] = ""
1555f9996aaSopenharmony_ci    if notice_file is None:
1565f9996aaSopenharmony_ci        readme_path = os.path.join(options.module_source_dir,
1575f9996aaSopenharmony_ci                                   README_FILE_NAME)
1585f9996aaSopenharmony_ci        if not os.path.exists(readme_path):
1595f9996aaSopenharmony_ci            readme_path = find_opensource(os.path.abspath(options.module_source_dir))
1605f9996aaSopenharmony_ci        other_files.extend(find_other_files(options.module_source_dir))
1615f9996aaSopenharmony_ci        if readme_path is not None:
1625f9996aaSopenharmony_ci            depfiles.append(readme_path)
1635f9996aaSopenharmony_ci            notice_file_info = get_license_from_readme(readme_path)
1645f9996aaSopenharmony_ci            notice_file = notice_file_info[0]
1655f9996aaSopenharmony_ci            if isinstance(notice_file, list):
1665f9996aaSopenharmony_ci                notice_file = ",".join(notice_file)
1675f9996aaSopenharmony_ci            module_notice_info['Software'] = notice_file_info[1]
1685f9996aaSopenharmony_ci            module_notice_info['Version'] = notice_file_info[2]
1695f9996aaSopenharmony_ci
1705f9996aaSopenharmony_ci    if notice_file is None:
1715f9996aaSopenharmony_ci        notice_file = find_license(options.module_source_dir)
1725f9996aaSopenharmony_ci        opensource_file = find_opensource(os.path.abspath(options.module_source_dir))
1735f9996aaSopenharmony_ci        if opensource_file is not None and os.path.exists(opensource_file):
1745f9996aaSopenharmony_ci            other_files.extend(find_other_files(opensource_file))
1755f9996aaSopenharmony_ci            notice_file_info = get_license_from_readme(opensource_file)
1765f9996aaSopenharmony_ci            module_notice_info['Software'] = notice_file_info[1]
1775f9996aaSopenharmony_ci            module_notice_info['Version'] = notice_file_info[2]
1785f9996aaSopenharmony_ci        else:
1795f9996aaSopenharmony_ci            module_notice_info['Software'] = ""
1805f9996aaSopenharmony_ci            module_notice_info['Version'] = ""
1815f9996aaSopenharmony_ci
1825f9996aaSopenharmony_ci    add_path_to_module_notice(module_notice_info, module_notice_info_list, options)
1835f9996aaSopenharmony_ci
1845f9996aaSopenharmony_ci    if notice_file:
1855f9996aaSopenharmony_ci        if other_files:
1865f9996aaSopenharmony_ci            notice_file = f"{notice_file},{','.join(other_files)}"
1875f9996aaSopenharmony_ci        for output in options.output:
1885f9996aaSopenharmony_ci            notice_info_json = '{}.json'.format(output)
1895f9996aaSopenharmony_ci            os.makedirs(os.path.dirname(output), exist_ok=True)
1905f9996aaSopenharmony_ci            os.makedirs(os.path.dirname(notice_info_json), exist_ok=True)
1915f9996aaSopenharmony_ci            notice_files = [file for file in notice_file.split(",") if file]
1925f9996aaSopenharmony_ci
1935f9996aaSopenharmony_ci            write_file_content(notice_files, options, output, notice_info_json, module_notice_info_list, depfiles)
1945f9996aaSopenharmony_ci
1955f9996aaSopenharmony_ci
1965f9996aaSopenharmony_cidef write_file_content(notice_files, options, output, notice_info_json, module_notice_info_list, depfiles):
1975f9996aaSopenharmony_ci    for notice_file in notice_files:
1985f9996aaSopenharmony_ci        notice_file = notice_file.strip()
1995f9996aaSopenharmony_ci        if not os.path.exists(notice_file):
2005f9996aaSopenharmony_ci            notice_file = os.path.join(options.module_source_dir, notice_file)
2015f9996aaSopenharmony_ci        if os.path.exists(notice_file):
2025f9996aaSopenharmony_ci            if not os.path.exists(output):
2035f9996aaSopenharmony_ci                build_utils.touch(output)
2045f9996aaSopenharmony_ci            write_notice_to_output(notice_file, output)
2055f9996aaSopenharmony_ci            write_json_file(notice_info_json, module_notice_info_list)
2065f9996aaSopenharmony_ci        else:
2075f9996aaSopenharmony_ci            build_utils.touch(output)
2085f9996aaSopenharmony_ci            build_utils.touch(notice_info_json)
2095f9996aaSopenharmony_ci        depfiles.append(notice_file)
2105f9996aaSopenharmony_ci
2115f9996aaSopenharmony_ci
2125f9996aaSopenharmony_cidef write_notice_to_output(notice_file, output):
2135f9996aaSopenharmony_ci    with os.fdopen(os.open(notice_file, os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR),
2145f9996aaSopenharmony_ci                   'r', encoding='utf-8', errors='ignore') as notice_data_flow:
2155f9996aaSopenharmony_ci        license_content = notice_data_flow.read()
2165f9996aaSopenharmony_ci    with os.fdopen(os.open(output, os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR),
2175f9996aaSopenharmony_ci                   'r', encoding='utf-8', errors='ignore') as output_data_flow:
2185f9996aaSopenharmony_ci        output_file_content = output_data_flow.read()
2195f9996aaSopenharmony_ci    if license_content not in output_file_content:
2205f9996aaSopenharmony_ci        with os.fdopen(os.open(output, os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR),
2215f9996aaSopenharmony_ci                       'a', encoding='utf-8') as testfwk_info_file:
2225f9996aaSopenharmony_ci            testfwk_info_file.write(f"{license_content}\n")
2235f9996aaSopenharmony_ci            testfwk_info_file.close()
2245f9996aaSopenharmony_ci
2255f9996aaSopenharmony_ci
2265f9996aaSopenharmony_cidef main(args):
2275f9996aaSopenharmony_ci    args = build_utils.expand_file_args(args)
2285f9996aaSopenharmony_ci
2295f9996aaSopenharmony_ci    parser = argparse.ArgumentParser()
2305f9996aaSopenharmony_ci    build_utils.add_depfile_option(parser)
2315f9996aaSopenharmony_ci
2325f9996aaSopenharmony_ci    parser.add_argument('--license-file', required=False)
2335f9996aaSopenharmony_ci    parser.add_argument('--output', action='append', required=False)
2345f9996aaSopenharmony_ci    parser.add_argument('--sources', action='append', required=False)
2355f9996aaSopenharmony_ci    parser.add_argument('--sdk-install-info-file', required=False)
2365f9996aaSopenharmony_ci    parser.add_argument('--label', required=False)
2375f9996aaSopenharmony_ci    parser.add_argument('--sdk-notice-dir', required=False)
2385f9996aaSopenharmony_ci    parser.add_argument('--module-source-dir',
2395f9996aaSopenharmony_ci                        help='source directory of this module',
2405f9996aaSopenharmony_ci                        required=True)
2415f9996aaSopenharmony_ci
2425f9996aaSopenharmony_ci    options = parser.parse_args()
2435f9996aaSopenharmony_ci    depfiles = []
2445f9996aaSopenharmony_ci
2455f9996aaSopenharmony_ci    if options.sdk_install_info_file:
2465f9996aaSopenharmony_ci        install_dir = ''
2475f9996aaSopenharmony_ci        sdk_install_info = read_json_file(options.sdk_install_info_file)
2485f9996aaSopenharmony_ci        for item in sdk_install_info:
2495f9996aaSopenharmony_ci            if options.label == item.get('label'):
2505f9996aaSopenharmony_ci                install_dir = item.get('install_dir')
2515f9996aaSopenharmony_ci                break
2525f9996aaSopenharmony_ci        if options.sources and install_dir:
2535f9996aaSopenharmony_ci            for src in options.sources:
2545f9996aaSopenharmony_ci                extend_output = os.path.join(options.sdk_notice_dir, install_dir,
2555f9996aaSopenharmony_ci                                             '{}.{}'.format(os.path.basename(src), 'txt'))
2565f9996aaSopenharmony_ci                options.output.append(extend_output)
2575f9996aaSopenharmony_ci
2585f9996aaSopenharmony_ci    do_collect_notice_files(options, depfiles)
2595f9996aaSopenharmony_ci    if options.license_file:
2605f9996aaSopenharmony_ci        depfiles.append(options.license_file)
2615f9996aaSopenharmony_ci    build_utils.write_depfile(options.depfile, options.output[0], depfiles)
2625f9996aaSopenharmony_ci
2635f9996aaSopenharmony_ci
2645f9996aaSopenharmony_ciif __name__ == '__main__':
2655f9996aaSopenharmony_ci    sys.exit(main(sys.argv[1:]))
2665f9996aaSopenharmony_ci
267