1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# Copyright (c) 2021 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import sys 17import argparse 18import os 19import shutil 20import stat 21 22sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) 23from scripts.util.file_utils import read_json_file, write_json_file # noqa: E402 24from scripts.util import build_utils # noqa: E402 25 26README_FILE_NAME = 'README.OpenSource' 27LICENSE_CANDIDATES = [ 28 'LICENSE', 29 'License', 30 'NOTICE', 31 'Notice', 32 'COPYRIGHT', 33 'Copyright' 34] 35 36 37def is_top_dir(current_dir: str): 38 return os.path.exists(os.path.join(current_dir, '.gn')) 39 40 41def find_license_recursively(current_dir: str, default_license: str): 42 if is_top_dir(current_dir): 43 return default_license 44 for file in ['LICENSE', 'NOTICE', 'License', 'Copyright']: 45 candidate = os.path.join(current_dir, file) 46 if os.path.isfile(os.path.join(current_dir, file)): 47 return os.path.join(candidate) 48 return find_license_recursively(os.path.dirname(current_dir), 49 default_license) 50 51 52def find_opensource_recursively(current_dir: str): 53 if is_top_dir(current_dir): 54 return None 55 candidate = os.path.join(current_dir, README_FILE_NAME) 56 if os.path.isfile(candidate): 57 return os.path.join(candidate) 58 return find_opensource_recursively(os.path.dirname(current_dir)) 59 60 61def get_license_from_readme(readme_path: str): 62 contents = read_json_file(readme_path) 63 if contents is None: 64 raise Exception("Error: failed to read {}.".format(readme_path)) 65 66 notice_file = contents[0].get('License File').strip() 67 notice_name = contents[0].get('Name').strip() 68 notice_version = contents[0].get('Version Number').strip() 69 if notice_file is None: 70 raise Exception("Error: value of notice file is empty in {}.".format( 71 readme_path)) 72 if notice_name is None: 73 raise Exception("Error: Name of notice file is empty in {}.".format( 74 readme_path)) 75 if notice_version is None: 76 raise Exception("Error: Version Number of notice file is empty in {}.".format( 77 readme_path)) 78 79 return os.path.join(os.path.dirname(readme_path), notice_file), notice_name, notice_version 80 81 82def do_collect_notice_files(options, depfiles: str): 83 module_notice_info_list = [] 84 module_notice_info = {} 85 notice_file = options.license_file 86 if notice_file: 87 opensource_file = find_opensource_recursively(os.path.abspath(options.module_source_dir)) 88 if opensource_file is not None and os.path.exists(opensource_file): 89 notice_file_info = get_license_from_readme(opensource_file) 90 module_notice_info['Software'] = "{} {}".format(notice_file_info[1], notice_file_info[2]) 91 else: 92 module_notice_info['Software'] = "" 93 if notice_file is None: 94 readme_path = os.path.join(options.module_source_dir, 95 README_FILE_NAME) 96 if not os.path.exists(readme_path): 97 readme_path = find_opensource_recursively(os.path.abspath(options.module_source_dir)) 98 if readme_path is not None: 99 depfiles.append(readme_path) 100 notice_file_info = get_license_from_readme(readme_path) 101 notice_file = notice_file_info[0] 102 module_notice_info['Software'] = "{} {}".format(notice_file_info[1], notice_file_info[2]) 103 104 if notice_file is None: 105 notice_file = find_license_recursively(options.module_source_dir, 106 options.default_license) 107 opensource_file = find_opensource_recursively(os.path.abspath(options.module_source_dir)) 108 if opensource_file is not None and os.path.exists(opensource_file): 109 notice_file_info = get_license_from_readme(opensource_file) 110 module_notice_info['Software'] = "{} {}".format(notice_file_info[1], notice_file_info[2]) 111 else: 112 module_notice_info['Software'] = "" 113 114 module_notice_info['Path'] = "/{}".format(options.module_source_dir[5:]) 115 module_notice_info_list.append(module_notice_info) 116 117 if notice_file: 118 for output in options.output: 119 notice_info_json = '{}.json'.format(output) 120 os.makedirs(os.path.dirname(output), exist_ok=True) 121 os.makedirs(os.path.dirname(notice_info_json), exist_ok=True) 122 123 notice_files = notice_file.split(',') 124 write_file_content(notice_files, options, output, notice_info_json, module_notice_info_list, depfiles) 125 126 127def write_file_content(notice_files, options, output, notice_info_json, module_notice_info_list, depfiles): 128 for notice_file in notice_files: 129 notice_file = notice_file.strip() 130 if options.module_source_dir not in notice_file: 131 notice_file = os.path.join(options.module_source_dir, notice_file) 132 if os.path.exists(notice_file): 133 if not os.path.exists(output): 134 build_utils.touch(output) 135 write_notice_to_output(notice_file, output) 136 write_json_file(notice_info_json, module_notice_info_list) 137 else: 138 build_utils.touch(output) 139 build_utils.touch(notice_info_json) 140 depfiles.append(notice_file) 141 142 143def write_notice_to_output(notice_file, output): 144 notice_data_flow = open(notice_file, "r+", encoding="utf-8", errors="ignore") 145 license_content = notice_data_flow.read() 146 notice_data_flow.close() 147 output_data_flow = open(output, "r+", encoding="utf-8", errors="ignore") 148 output_file_content = output_data_flow.read() 149 output_data_flow.close() 150 if license_content not in output_file_content: 151 with os.fdopen(os.open(output, os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR), 152 'a', encoding='utf-8') as testfwk_info_file: 153 testfwk_info_file.write(f"{license_content}\n") 154 testfwk_info_file.close() 155 156 157def main(args): 158 args = build_utils.expand_file_args(args) 159 160 parser = argparse.ArgumentParser() 161 build_utils.add_depfile_option(parser) 162 163 parser.add_argument('--license-file', required=False) 164 parser.add_argument('--default-license', required=True) 165 parser.add_argument('--output', action='append', required=False) 166 parser.add_argument('--sources', action='append', required=False) 167 parser.add_argument('--sdk-install-info-file', required=False) 168 parser.add_argument('--label', required=False) 169 parser.add_argument('--sdk-notice-dir', required=False) 170 parser.add_argument('--module-source-dir', 171 help='source directory of this module', 172 required=True) 173 174 options = parser.parse_args() 175 depfiles = [] 176 177 if options.sdk_install_info_file: 178 install_dir = '' 179 sdk_install_info = read_json_file(options.sdk_install_info_file) 180 for item in sdk_install_info: 181 if options.label == item.get('label'): 182 install_dir = item.get('install_dir') 183 break 184 if options.sources and install_dir: 185 for src in options.sources: 186 extend_output = os.path.join(options.sdk_notice_dir, install_dir, 187 '{}.{}'.format(os.path.basename(src), 'txt')) 188 options.output.append(extend_output) 189 190 do_collect_notice_files(options, depfiles) 191 if options.license_file: 192 depfiles.append(options.license_file) 193 build_utils.write_depfile(options.depfile, options.output[0], depfiles) 194 195 196if __name__ == '__main__': 197 sys.exit(main(sys.argv[1:])) 198