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 'COPYING', 35 'Copying' 36] 37 38 39def is_top_dir(current_dir: str): 40 return os.path.exists(os.path.join(current_dir, '.gn')) 41 42 43def find_license_recursively(current_dir: str): 44 if is_top_dir(current_dir): 45 return None 46 for file in LICENSE_CANDIDATES: 47 candidate = os.path.join(current_dir, file) 48 if os.path.isfile(os.path.join(current_dir, file)): 49 return os.path.join(candidate) 50 return find_license_recursively(os.path.dirname(current_dir)) 51 52 53def find_opensource_recursively(current_dir: str): 54 if is_top_dir(current_dir): 55 return None 56 candidate = os.path.join(current_dir, README_FILE_NAME) 57 if os.path.isfile(candidate): 58 return os.path.join(candidate) 59 return find_opensource_recursively(os.path.dirname(current_dir)) 60 61 62def get_license_from_readme(readme_path: str): 63 contents = read_json_file(readme_path) 64 if contents is None: 65 raise Exception("Error: failed to read {}.".format(readme_path)) 66 67 notice_file = contents[0].get('License File').strip() 68 notice_name = contents[0].get('Name').strip() 69 notice_version = contents[0].get('Version Number').strip() 70 if notice_file is None: 71 raise Exception("Error: value of notice file is empty in {}.".format( 72 readme_path)) 73 if notice_name is None: 74 raise Exception("Error: Name of notice file is empty in {}.".format( 75 readme_path)) 76 if notice_version is None: 77 raise Exception("Error: Version Number of notice file is empty in {}.".format( 78 readme_path)) 79 80 return os.path.join(os.path.dirname(readme_path), notice_file), notice_name, notice_version 81 82 83def do_collect_notice_files(options, depfiles: str): 84 module_notice_info_list = [] 85 module_notice_info = {} 86 notice_file = options.license_file 87 if notice_file: 88 opensource_file = find_opensource_recursively(os.path.abspath(options.module_source_dir)) 89 if opensource_file is not None and os.path.exists(opensource_file): 90 notice_file_info = get_license_from_readme(opensource_file) 91 module_notice_info['Software'] = "{}".format(notice_file_info[1]) 92 module_notice_info['Version'] = "{}".format(notice_file_info[2]) 93 else: 94 module_notice_info['Software'] = "" 95 module_notice_info['Version'] = "" 96 if notice_file is None: 97 readme_path = os.path.join(options.module_source_dir, 98 README_FILE_NAME) 99 if not os.path.exists(readme_path): 100 readme_path = find_opensource_recursively(os.path.abspath(options.module_source_dir)) 101 if readme_path is not None: 102 depfiles.append(readme_path) 103 notice_file_info = get_license_from_readme(readme_path) 104 notice_file = notice_file_info[0] 105 module_notice_info['Software'] = "{}".format(notice_file_info[1]) 106 module_notice_info['Version'] = "{}".format(notice_file_info[2]) 107 108 if notice_file is None: 109 notice_file = find_license_recursively(options.module_source_dir) 110 opensource_file = find_opensource_recursively(os.path.abspath(options.module_source_dir)) 111 if opensource_file is not None and os.path.exists(opensource_file): 112 notice_file_info = get_license_from_readme(opensource_file) 113 module_notice_info['Software'] = "{}".format(notice_file_info[1]) 114 module_notice_info['Version'] = "{}".format(notice_file_info[2]) 115 else: 116 module_notice_info['Software'] = "" 117 module_notice_info['Version'] = "" 118 119 if module_notice_info['Software']: 120 module_notice_info['Path'] = "/{}".format(options.module_source_dir[5:]) 121 module_notice_info_list.append(module_notice_info) 122 123 if notice_file: 124 for output in options.output: 125 notice_info_json = '{}.json'.format(output) 126 os.makedirs(os.path.dirname(output), exist_ok=True) 127 os.makedirs(os.path.dirname(notice_info_json), exist_ok=True) 128 129 notice_files = notice_file.split(',') 130 write_file_content(notice_files, options, output, notice_info_json, module_notice_info_list, depfiles) 131 132 133def write_file_content(notice_files, options, output, notice_info_json, module_notice_info_list, depfiles): 134 for notice_file in notice_files: 135 notice_file = notice_file.strip() 136 if not os.path.exists(notice_file): 137 notice_file = os.path.join(options.module_source_dir, notice_file) 138 if os.path.exists(notice_file): 139 if not os.path.exists(output): 140 build_utils.touch(output) 141 write_notice_to_output(notice_file, output) 142 write_json_file(notice_info_json, module_notice_info_list) 143 else: 144 build_utils.touch(output) 145 build_utils.touch(notice_info_json) 146 depfiles.append(notice_file) 147 148 149def write_notice_to_output(notice_file, output): 150 with os.fdopen(os.open(notice_file, os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR), 151 'r', encoding='utf-8', errors='ignore') as notice_data_flow: 152 license_content = notice_data_flow.read() 153 with os.fdopen(os.open(output, os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR), 154 'r', encoding='utf-8', errors='ignore') as output_data_flow: 155 output_file_content = output_data_flow.read() 156 if license_content not in output_file_content: 157 with os.fdopen(os.open(output, os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR), 158 'a', encoding='utf-8') as testfwk_info_file: 159 testfwk_info_file.write(f"{license_content}\n") 160 testfwk_info_file.close() 161 162 163def main(args): 164 args = build_utils.expand_file_args(args) 165 166 parser = argparse.ArgumentParser() 167 build_utils.add_depfile_option(parser) 168 169 parser.add_argument('--license-file', required=False) 170 parser.add_argument('--output', action='append', required=False) 171 parser.add_argument('--sources', action='append', required=False) 172 parser.add_argument('--sdk-install-info-file', required=False) 173 parser.add_argument('--label', required=False) 174 parser.add_argument('--sdk-notice-dir', required=False) 175 parser.add_argument('--module-source-dir', 176 help='source directory of this module', 177 required=True) 178 179 options = parser.parse_args() 180 depfiles = [] 181 182 if options.sdk_install_info_file: 183 install_dir = '' 184 sdk_install_info = read_json_file(options.sdk_install_info_file) 185 for item in sdk_install_info: 186 if options.label == item.get('label'): 187 install_dir = item.get('install_dir') 188 break 189 if options.sources and install_dir: 190 for src in options.sources: 191 extend_output = os.path.join(options.sdk_notice_dir, install_dir, 192 '{}.{}'.format(os.path.basename(src), 'txt')) 193 options.output.append(extend_output) 194 195 do_collect_notice_files(options, depfiles) 196 if options.license_file: 197 depfiles.append(options.license_file) 198 build_utils.write_depfile(options.depfile, options.output[0], depfiles) 199 200 201if __name__ == '__main__': 202 sys.exit(main(sys.argv[1:])) 203