1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# Copyright (c) 2024 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 16 17import sys 18import os 19import argparse 20import shutil 21import json 22import time 23from hb.util.log_util import LogUtil 24import re 25 26 27def _get_public_external_deps(data, public_deps): 28 if not isinstance(data, dict): 29 return "" 30 for key, value in data.items(): 31 if not isinstance(value, dict): 32 continue 33 34 for key_1, value_1 in value.items(): 35 label = value_1.get("label") 36 if public_deps == label: 37 return key + ":" + key_1 38 39 return "" 40 41 42def _is_innerkit(data, part, module): 43 if not isinstance(data, dict): 44 return False 45 46 part_data = data.get(part) 47 if not isinstance(part_data, dict): 48 return False 49 50 if module in part_data: 51 return True 52 53 return False 54 55 56def _get_inner_kits_info(out_path): 57 jsondata = "" 58 json_path = os.path.join( 59 out_path + "/build_configs/parts_info/inner_kits_info.json" 60 ) 61 with open(json_path, "r") as f: 62 try: 63 jsondata = json.load(f) 64 except Exception as e: 65 print("--_get_inner_kits_info parse json error--", e) 66 return jsondata 67 68 69def _get_module_name(json_data): 70 part_data = json_data.get(part_name) 71 if isinstance(data_list, list) and len(json_data.get(json_key)) >= 1: 72 desc_list.extend(data_list) 73 else: 74 desc_list.append(json_data.get(json_key)) 75 76 77def _handle_one_layer_json(json_key, json_data, desc_list): 78 data_list = json_data.get(json_key) 79 if isinstance(data_list, list) and len(json_data.get(json_key)) >= 1: 80 desc_list.extend(data_list) 81 else: 82 desc_list.append(json_data.get(json_key)) 83 84 85def _handle_two_layer_json(json_key, json_data, desc_list): 86 value_depth = len(json_data.get(json_key)) 87 for i in range(value_depth): 88 _include_dirs = json_data.get(json_key)[i].get("include_dirs") 89 if _include_dirs: 90 desc_list.extend(_include_dirs) 91 92 93def _get_json_data(args, module): 94 json_path = os.path.join( 95 args.get("out_path"), 96 args.get("subsystem_name"), 97 args.get("part_name"), 98 "publicinfo", 99 module + ".json", 100 ) 101 with open(json_path, "r") as f: 102 try: 103 jsondata = json.load(f) 104 except Exception as e: 105 print("--_get_json_data parse json error--", e) 106 return jsondata 107 108 109def _handle_deps_data(json_data): 110 dep_list = [] 111 if json_data.get("public_deps"): 112 _handle_one_layer_json("public_deps", json_data, dep_list) 113 return dep_list 114 115 116def _handle_includes_data(json_data): 117 include_list = [] 118 if json_data.get("public_configs"): 119 _handle_two_layer_json("public_configs", json_data, include_list) 120 if json_data.get("all_dependent_configs"): 121 _handle_two_layer_json("all_dependent_configs", json_data, include_list) 122 return include_list 123 124 125def _get_static_lib_path(args, json_data): 126 label = json_data.get("label") 127 split_label = label.split("//")[1].split(":")[0] 128 real_static_lib_path = os.path.join( 129 args.get("out_path"), "obj", split_label, json_data.get("out_name") 130 ) 131 return real_static_lib_path 132 133 134def _copy_dir(src_path, target_path): 135 if not os.path.isdir(src_path): 136 return False 137 filelist_src = os.listdir(src_path) 138 for file in filelist_src: 139 path = os.path.join(os.path.abspath(src_path), file) 140 if os.path.isdir(path): 141 if file.startswith("."): 142 continue 143 path1 = os.path.join(target_path, file) 144 _copy_dir(path, path1) 145 else: 146 if not path.endswith(".h"): 147 continue 148 with open(path, "rb") as read_stream: 149 contents = read_stream.read() 150 if not os.path.exists(target_path): 151 os.makedirs(target_path) 152 path1 = os.path.join(target_path, file) 153 with os.fdopen( 154 os.open(path1, os.O_WRONLY | os.O_CREAT, mode=0o640), "wb" 155 ) as write_stream: 156 write_stream.write(contents) 157 return True 158 159 160def _copy_includes(args, module, includes: list): 161 includes_out_dir = os.path.join( 162 args.get("out_path"), 163 "component_package", 164 args.get("part_path"), 165 "innerapis", 166 module, 167 "includes", 168 ) 169 if not os.path.exists(includes_out_dir): 170 os.makedirs(includes_out_dir) 171 for include in includes: 172 splitInclude = include.split("//")[1] 173 realIncludePath = os.path.join(args.get("root_path"), splitInclude) 174 _copy_dir(realIncludePath, includes_out_dir) 175 print("_copy_includes has done ") 176 177 178def _copy_lib(args, json_data, module): 179 so_path = "" 180 if json_data.get("type") == "static_library": 181 so_path = _get_static_lib_path(args, json_data) 182 else: 183 so_path = os.path.join( 184 args.get("out_path"), 185 args.get("subsystem_name"), 186 args.get("part_name"), 187 json_data.get("out_name"), 188 ) 189 if os.path.isfile(so_path): 190 lib_out_dir = os.path.join( 191 args.get("out_path"), 192 "component_package", 193 args.get("part_path"), 194 "innerapis", 195 module, 196 "libs", 197 ) 198 if not os.path.exists(lib_out_dir): 199 os.makedirs(lib_out_dir) 200 shutil.copy(so_path, lib_out_dir) 201 return True 202 else: 203 return False 204 205 206def _copy_bundlejson(args): 207 bundlejson_out = os.path.join( 208 args.get("out_path"), "component_package", args.get("part_path") 209 ) 210 print("bundlejson_out : ", bundlejson_out) 211 if not os.path.exists(bundlejson_out): 212 os.makedirs(bundlejson_out) 213 bundlejson = os.path.join( 214 args.get("root_path"), args.get("part_path"), "bundle.json" 215 ) 216 if os.path.isfile(bundlejson): 217 with open(bundlejson, "r") as f: 218 bundle_data = json.load(f) 219 bundle_data["publishAs"] = "binary" 220 bundle_data["os"] = "linux" 221 bundle_data["buildArch"] = "x86" 222 dirs = dict() 223 dirs["./"] = [] 224 directory = bundlejson_out 225 for filename in os.listdir(directory): 226 filepath = os.path.join(directory, filename) 227 if os.path.isfile(filepath): 228 dirs["./"].append(filename) 229 else: 230 dirs[filename] = [filename + "/*"] 231 delete_list = [ 232 "LICENSE", 233 "README.md", 234 "README_zh.md", 235 "README_en.md", 236 "bundle.json", 237 ] 238 for delete_txt in delete_list: 239 if delete_txt in dirs["./"]: 240 dirs["./"].remove(delete_txt) 241 if dirs["./"] == []: 242 del dirs["./"] 243 bundle_data["dirs"] = dirs 244 bundle_data["version"] = str(bundle_data["version"]) 245 if bundle_data["version"] == "": 246 bundle_data["version"] = "1.0.0" 247 pattern = r"^(\d+)\.(\d+)(-[a-zA-Z]+)?$" # 正则表达式匹配a.b[-后缀]格式的字符串 248 match = re.match(pattern, bundle_data["version"]) 249 if match: 250 a = match.group(1) 251 b = match.group(2) 252 suffix = match.group(3) if match.group(3) else "" 253 bundle_data["version"] = f"{a}.{b}.0{suffix}" 254 with os.fdopen( 255 os.open( 256 os.path.join(bundlejson_out, "bundle.json"), 257 os.O_WRONLY | os.O_CREAT, 258 mode=0o640, 259 ), 260 "w", 261 encoding="utf-8", 262 ) as fd: 263 json.dump(bundle_data, fd, indent=4, ensure_ascii=False) 264 265 266def _copy_license(args): 267 license_out = os.path.join( 268 args.get("out_path"), "component_package", args.get("part_path") 269 ) 270 print("license_out : ", license_out) 271 if not os.path.exists(license_out): 272 os.makedirs(license_out) 273 license = os.path.join(args.get("root_path"), args.get("part_path"), "LICENSE") 274 if os.path.isfile(license): 275 shutil.copy(license, license_out) 276 277 278def _copy_readme(args): 279 readme_out = os.path.join( 280 args.get("out_path"), "component_package", args.get("part_path") 281 ) 282 print("readme_out : ", readme_out) 283 if not os.path.exists(readme_out): 284 os.makedirs(readme_out) 285 readme = os.path.join(args.get("root_path"), args.get("part_path"), "README.md") 286 if os.path.isfile(readme): 287 shutil.copy(readme, readme_out) 288 readme_zh = os.path.join( 289 args.get("root_path"), args.get("part_path"), "README_zh.md" 290 ) 291 if os.path.isfile(readme_zh): 292 shutil.copy(readme_zh, readme_out) 293 readme_en = os.path.join( 294 args.get("root_path"), args.get("part_path"), "README_en.md" 295 ) 296 if os.path.isfile(readme_en): 297 shutil.copy(readme_en, readme_out) 298 299 300def _generate_import(fp): 301 fp.write('import("//build/ohos.gni")\n') 302 303 304def _generate_configs(fp, module): 305 fp.write('\nconfig("' + module + '_configs") {\n') 306 fp.write(' visibility = [ ":*" ]\n') 307 fp.write(" include_dirs = [\n") 308 fp.write(' "includes"\n') 309 fp.write(" ]\n}\n") 310 311 312def _generate_prebuilt_shared_library(fp, type, module): 313 if type == "static_library": 314 fp.write('ohos_prebuilt_static_library("' + module + '") {\n') 315 else: 316 fp.write('ohos_prebuilt_shared_library("' + module + '") {\n') 317 318 319def _generate_public_configs(fp, module): 320 fp.write(' public_configs = [":' + module + '_configs"]\n') 321 322 323def _generate_public_deps(fp, deps: list, innerkit_json): 324 if not deps: 325 return 326 fp.write(" public_external_deps = [\n") 327 for dep in deps: 328 public_external_deps = _get_public_external_deps(innerkit_json, dep) 329 if len(public_external_deps) > 0: 330 fp.write(' "' + public_external_deps + '",\n') 331 fp.write(" ]\n") 332 333 334def _generate_other(fp, args, json_data, module): 335 so_name = json_data.get("out_name") 336 fp.write(' source = "libs/' + so_name + '"\n') 337 fp.write(' part_name = "' + args.get("part_name") + '"\n') 338 fp.write(' subsystem_name = "' + args.get("subsystem_name") + '"\n') 339 340 341def _generate_end(fp): 342 fp.write("}") 343 344 345def _generate_build_gn(args, module, json_data, deps: list, innerkit_json): 346 gn_path = os.path.join( 347 args.get("out_path"), 348 "component_package", 349 args.get("part_path"), 350 "innerapis", 351 module, 352 "BUILD.gn", 353 ) 354 fd = os.open(gn_path, os.O_WRONLY | os.O_CREAT, mode=0o640) 355 fp = os.fdopen(fd, "w") 356 _generate_import(fp) 357 _generate_configs(fp, module) 358 _generate_prebuilt_shared_library(fp, json_data.get("type"), module) 359 _generate_public_configs(fp, module) 360 _generate_public_deps(fp, deps, innerkit_json) 361 _generate_other(fp, args, json_data, module) 362 _generate_end(fp) 363 print("_generate_build_gn has done ") 364 fp.close() 365 366 367def _parse_module_list(args): 368 module_list = [] 369 publicinfoPath = os.path.join( 370 args.get("out_path"), 371 args.get("subsystem_name"), 372 args.get("part_name"), 373 "publicinfo", 374 ) 375 print("publicinfoPath", publicinfoPath) 376 if os.path.exists(publicinfoPath) is False: 377 return module_list 378 publicinfoDir = os.listdir(publicinfoPath) 379 for filename in publicinfoDir: 380 if filename.endswith(".json"): 381 module_name = filename.split(".json")[0] 382 module_list.append(module_name) 383 print("filename", filename) 384 print("module_list", module_list) 385 return module_list 386 387 388def _generate_component_package(args, innerkit_json): 389 modules = _parse_module_list(args) 390 if len(modules) == 0: 391 return 392 is_component_build = False 393 for module in modules: 394 if _is_innerkit(innerkit_json, args.get("part_name"), module) == False: 395 continue 396 json_data = _get_json_data(args, module) 397 lib_exists = _copy_lib(args, json_data, module) 398 if lib_exists is False: 399 continue 400 is_component_build = True 401 includes = _handle_includes_data(json_data) 402 deps = _handle_deps_data(json_data) 403 _copy_includes(args, module, includes) 404 _generate_build_gn(args, module, json_data, deps, innerkit_json) 405 if is_component_build: 406 _copy_bundlejson(args) 407 _copy_license(args) 408 _copy_readme(args) 409 410 411def _get_part_subsystem(out_path): 412 jsondata = "" 413 json_path = os.path.join(out_path + "/build_configs/parts_info/part_subsystem.json") 414 with open(json_path, "r") as f: 415 try: 416 jsondata = json.load(f) 417 except Exception as e: 418 print("--_get_part_subsystem parse json error--", e) 419 return jsondata 420 421 422def _get_parts_path_info(out_path): 423 jsondata = "" 424 json_path = os.path.join( 425 out_path + "/build_configs/parts_info/parts_path_info.json" 426 ) 427 with open(json_path, "r") as f: 428 try: 429 jsondata = json.load(f) 430 except Exception as e: 431 print("--_get_parts_path_info parse json error--", e) 432 return jsondata 433 434 435def _get_parts_path(json_data, part_name): 436 parts_path = None 437 if json_data.get(part_name) is not None: 438 parts_path = json_data[part_name] 439 return parts_path 440 441 442def generate_component_package(out_path, root_path): 443 start_time = time.time() 444 part_subsystem = _get_part_subsystem(out_path) 445 parts_path_info = _get_parts_path_info(out_path) 446 inner_kits_info = _get_inner_kits_info(out_path) 447 for key, value in part_subsystem.items(): 448 part_name = key 449 subsystem_name = value 450 part_path = _get_parts_path(parts_path_info, part_name) 451 if part_path is None: 452 continue 453 args = { 454 "subsystem_name": subsystem_name, 455 "part_name": part_name, 456 "out_path": out_path, 457 "root_path": root_path, 458 "part_path": part_path, 459 } 460 _generate_component_package(args, inner_kits_info) 461 end_time = time.time() 462 run_time = end_time - start_time 463 print("generate_component_package out_path", out_path) 464 print(f"生成二进制产物包耗时:{run_time}秒") 465