1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# Copyright (c) 2021-2023 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 argparse 17import json 18import os 19import sys 20 21from collections import OrderedDict 22from os.path import join 23from os.path import realpath 24 25 26DEBUG = False 27 28 29def read_json_file(input_file): 30 if not os.path.exists(input_file): 31 if DEBUG: 32 print("file '{}' doesn't exist.".format(input_file)) 33 return None 34 35 data = None 36 with open(input_file, 'r') as input_f: 37 data = json.load(input_f, object_pairs_hook=OrderedDict) 38 return data 39 40 41def write_json_file(output_file, content): 42 file_dir = os.path.dirname(os.path.abspath(output_file)) 43 if not os.path.exists(file_dir): 44 os.makedirs(file_dir, exist_ok=True) 45 with open(output_file, 'w') as output_f: 46 json.dump(content, output_f) 47 48 49def get_gn_build_content(plugins, plugin_so): 50 so_items = [] 51 items = [] 52 build_path = os.path.split(realpath(__file__))[0] 53 root_path = realpath(join(build_path, "..")) 54 ut_items = [] 55 mst_items = [] 56 for plugin_info in plugins: 57 for plugin, info in plugin_info.items(): 58 gn_path = realpath(join(root_path, info['path'], "BUILD.gn")) 59 if not os.path.exists(gn_path): 60 print('%s %s' % (gn_path, 'is not exist.')) 61 break 62 if 'loadType' in info: 63 if info['loadType'] == 'dynamic': 64 target = 'lib%s' % (plugin.lower()) 65 so_items.append('\"%s:%s\",\n' % (info['path'], target)) 66 else: 67 items.append('\"%s:%s\",\n' % (info['path'], info['name'])) 68 ut_items.append('\"%s:unittest\",\n' % (info['path'])) 69 mst_items.append('\"%s:moduletest\",\n' % (info['path'])) 70 dynamic_info = 'plugin_dynamic_deps = [\n%s\n]\n' % (''.join(so_items)) 71 static_info = ('plugin_static_deps = [\n%s\n]\n' % (''.join(items))) 72 ut_deps = ('plugin_ut_deps = [\n%s\n]\n' % (''.join(list(set(ut_items))))) 73 mst_deps = ('plugin_mst_deps = [\n%s\n]' % (''.join(list(set(mst_items))))) 74 return '%s%s%s%s' % (dynamic_info, static_info, ut_deps, mst_deps) 75 76 77def write_build_file(output_file, plugins, plugin_so, cnt_type): 78 build_info = "" 79 if cnt_type == "gn": 80 build_info = get_gn_build_content(plugins, plugin_so) 81 else: 82 return 83 out_dir = os.path.dirname(output_file) 84 if os.path.isdir(out_dir) is False: 85 os.makedirs(out_dir, exist_ok=True) 86 with open(output_file, 'w') as file_id: 87 if DEBUG: 88 print(build_info) 89 file_id.write(build_info) 90 91 92def write_config_file(output_file, plugins, pipelines, pipelinegroups, is_so): 93 items = [] 94 # plugins 95 items.append('plugins:%d \n' % (len(plugins))) 96 for plugin_info in plugins: 97 for plugin, info in plugin_info.items(): 98 items.append('%s[' % (plugin)) 99 if "threadtype" in info: 100 items.append('%s:%s' % 101 (info['threadtype'], info['threadname'])) 102 if info['threadtype'] == "pool": 103 items.append(':%d' % (info['threadnumber'])) 104 loadtime = 0 105 if "loadtime" in info: 106 loadtime = info['loadtime'] 107 load_type = "static" 108 if "loadType" in info: 109 load_type = info['loadType'] 110 items.append(']:%d %s\n' % (loadtime, load_type)) 111 if len(pipelines) > 0: 112 items.append('pipelines:%d\n' % (len(pipelines))) 113 for pipeline, plugin_list in pipelines.items(): 114 items.append('%s:' % (pipeline)) 115 for plugin in plugin_list: 116 items.append('%s ' % (plugin)) 117 items.append('\n') 118 if len(pipelinegroups) > 0: 119 items.append('pipelinegroups:%d\n' % (len(pipelinegroups))) 120 for pipelinegroup in pipelinegroups: 121 for plugin, pipeline_list in pipelinegroup.items(): 122 items.append('%s:' % (plugin)) 123 for pipeline in pipeline_list: 124 items.append('%s ' % (pipeline)) 125 items.append('\n') 126 config_info = ''.join(items) 127 out_dir = os.path.dirname(output_file) 128 if os.path.isdir(out_dir) is False: 129 os.makedirs(out_dir, exist_ok=True) 130 with open(output_file, 'w') as file_id: 131 file_id.write(config_info) 132 133 134def check_plugin_config(config_data): 135 if "plugins" not in config_data: 136 return False 137 if "rules" not in config_data: 138 return False 139 return True 140 141 142class ArgsPara(): 143 def __init__(self, target_os, product, platform, arch, ram, rom): 144 self.target_os = target_os 145 self.product = product 146 self.platform = platform 147 self.arch = arch 148 self.ram = self.get_memory_size(ram) 149 self.rom = self.get_memory_size(rom) 150 151 152 def get_memory_size(self, memory_detail): 153 # get memory 154 if isinstance(memory_detail, int) is True: 155 return memory_detail 156 if memory_detail.isdigit() is True: 157 return int(memory_detail) 158 size_str = memory_detail[0:-1] 159 size_unit = memory_detail[-1].lower() 160 if size_str.isdigit() is False: 161 return -1 162 size_int = int(size_str) 163 if size_unit == "k": 164 return 1024 * size_int 165 if size_unit == "m": 166 return 1024 * 1024 * size_int 167 if size_unit == "g": 168 return 1024 * 1024 * 1024 * size_int 169 return -1 170 171 172 def is_less(self, args_para): 173 if self.target_os != "double"and args_para.target_os != "double": 174 if self.target_os != args_para.target_os: 175 return False 176 if self.product != args_para.product: 177 return False 178 if self.platform != args_para.platform: 179 return False 180 if self.arch != args_para.arch: 181 return False 182 if self.ram > args_para.ram: 183 return False 184 if self.rom > args_para.rom: 185 return False 186 return True 187 188 189 def set_para(self, name, value): 190 if name == "target_os": 191 self.target_os = value 192 if name == "product": 193 self.product = value 194 if name == "platform": 195 self.platform = value 196 if name == "arch": 197 self.arch = value 198 if name == "ram": 199 self.ram = self.get_memory_size(value) 200 if name == "rom": 201 self.rom = self.get_memory_size(value) 202 return "" 203 204 205def is_build_rule(rule_list, args_para): 206 args_list = ["target_os", "product", "platform", "arch", "ram", "rom"] 207 for rule in rule_list: 208 config_args = ArgsPara(args_para.target_os, 209 args_para.product, 210 args_para.platform, 211 args_para.arch, 212 args_para.ram, 213 args_para.rom) 214 for arg in args_list: 215 if arg in rule: 216 config_args.set_para(arg, rule[arg]) 217 if config_args.is_less(args_para) is True: 218 return True 219 return False 220 221 222def add_plugin(plugins, loadorder, threads, config_plugins): 223 thread_list = {} 224 for name, value in threads.items(): 225 if name == "singledthread": 226 for plugin, thread_name in value.items(): 227 if plugin not in config_plugins: 228 raise Exception("[{}] not exist in plugins".format(plugin)) 229 thread_list.update({plugin: {'threadtype': 'thread', 230 'threadname': thread_name}}) 231 if name == "sharedthread": 232 for thread_name, plugin_list in value.items(): 233 for plugin in plugin_list: 234 if plugin not in config_plugins: 235 raise Exception("[{}] not in plugins".format(plugin)) 236 thread_list.update({plugin: {'threadtype': 'thread', 237 'threadname': thread_name}}) 238 if name == "threadpool": 239 number = 4 240 if "number" in value: 241 number = value['number'] 242 if "poolinfo" not in value: 243 raise Exception("[{}] not exist in threadpool".format(value)) 244 poolinfo = value['poolinfo'] 245 threadpool_name = "pool" 246 if "poolname" in poolinfo: 247 threadpool_name = poolinfo['poolname'] 248 if "plugins" not in poolinfo: 249 raise Exception("[{}] not exist in poolinfo".format(poolinfo)) 250 251 for plugin in poolinfo['plugins']: 252 if plugin not in config_plugins: 253 raise Exception("[{}] notexist in plugins".format(plugin)) 254 thread_list.update({plugin: {'threadtype': 'pool', 255 'threadname': threadpool_name, 256 'threadnumber': number}}) 257 for plugin, value in loadorder.items(): 258 plugin_info = {} 259 if plugin not in config_plugins: 260 raise Exception("[{}] not exist in plugins".format(plugin)) 261 plugin_info.update(value) 262 plugin_info.update(config_plugins[plugin]) 263 if plugin in thread_list: 264 plugin_info.update(thread_list[plugin]) 265 plugins.append({plugin: plugin_info}) 266 267 268def add_pipelines(pipelines, config_pipelines, config_plugins): 269 for name, value in config_pipelines.items(): 270 for plugin in value: 271 if plugin not in config_plugins: 272 raise Exception("[{}] not exist in pipeline".format(value)) 273 pipelines.update({name: value}) 274 275 276def add_pipeline_groups(pipelinegrps, cfg_pipelinegrps, pipelines, plugins): 277 for plugin, pipeline_list in cfg_pipelinegrps.items(): 278 found_plugin = False 279 for item in plugins: 280 if plugin in item: 281 found_plugin = True 282 break 283 if found_plugin is False: 284 raise Exception("[{}] not exist in plugins".format(plugin)) 285 for pipeline in pipeline_list: 286 if pipeline not in pipelines: 287 raise Exception("[{}] not exist in pipeline".format(pipelines)) 288 pipelinegrps.append({plugin: pipeline_list}) 289 290 291def generate_plugin(input_file, output_build_file, output_config_file, 292 plugin_so, build_file_type, args_para): 293 data = read_json_file(input_file) 294 if data is None: 295 raise Exception("file [{}] does not exist.".format(input_file)) 296 #parse plugins 297 #parse thread 298 if DEBUG: 299 print(data) 300 check_rslt = check_plugin_config(data) 301 if check_rslt is not True: 302 raise Exception("file [{}] content is error".format(input_file)) 303 plugins = [] 304 pipelines = {} 305 pipelinegroups = [] 306 config_plugins = data['plugins'] 307 for rule_item in data['rules']: 308 if 'rule' not in rule_item: 309 raise Exception("[{}] invalid, no rule item.".format(rule_item)) 310 if 'info' not in rule_item: 311 raise Exception("[{}] invalid, no info item.".format(rule_item)) 312 rule_list = rule_item['rule'] 313 check_rslt = is_build_rule(rule_list, args_para) 314 if check_rslt is False: 315 continue 316 info = rule_item['info'] 317 if 'loadorder' not in info: 318 raise Exception("[{}] invalid, no loadorder item.".format(info)) 319 threads = {} 320 if 'threads' in info: 321 threads = info['threads'] 322 add_plugin(plugins, info['loadorder'], threads, config_plugins) 323 if 'pipelines' in info: 324 add_pipelines(pipelines, info['pipelines'], config_plugins) 325 if 'pipelinegroups' in info: 326 add_pipeline_groups(pipelinegroups, info['pipelinegroups'], 327 pipelines, plugins) 328 break 329 if DEBUG: 330 print("xxxxxxxxx plugins xxxxxxxxxxxx") 331 print(plugins) 332 print("xxxxxxxxx pipelines xxxxxxxxxxxx") 333 print(pipelines) 334 print("xxxxxxxxx pipelinegroups xxxxxxxxxxxx") 335 print(pipelinegroups) 336 write_config_file(output_config_file, plugins, pipelines, 337 pipelinegroups, plugin_so) 338 write_build_file(output_build_file, plugins, plugin_so, build_file_type) 339 340 341def main(): 342 parser = argparse.ArgumentParser() 343 parser.add_argument('--input-file', help='plugin build config json', 344 required=True) 345 parser.add_argument('--plugin-config-file', help='plugin config json file', 346 required=True) 347 parser.add_argument('--plugin-build-file', help='plugin config json file', 348 required=True) 349 parser.add_argument('--target_os', help='target os', required=True) 350 parser.add_argument('--double_framework', help='double os framework', 351 required=True) 352 parser.add_argument('--target_platform', help='product type', 353 required=True) 354 parser.add_argument('--target_cpu', help='arm or arm64', required=True) 355 parser.add_argument('--plugin_so', help='build library', required=True) 356 parser.add_argument('--plugin_target_platform', help='hisi,qcom, mtk,etc.', 357 required=True) 358 parser.add_argument('--plugin_target_ram', help='ram', required=True) 359 parser.add_argument('--plugin_target_rom', help='rom', required=True) 360 parser.add_argument('--build-file-type', help='build file type', 361 required=False, default='gn') 362 args = parser.parse_args() 363 target_os = args.target_os 364 365 if args.double_framework == "true": 366 target_os = "double" 367 plugin_so = False 368 if args.plugin_so == "true": 369 plugin_so = True 370 args_para = ArgsPara(target_os, 371 args.target_platform, 372 args.plugin_target_platform, 373 args.target_cpu, 374 args.plugin_target_ram, 375 args.plugin_target_rom) 376 if args_para.rom == -1 or args_para.ram == -1: 377 raise Exception("input ram=%s,rom=%s invalid". 378 format(args.plugin_target_ram, args.plugin_target_rom)) 379 generate_plugin(args.input_file, args.plugin_build_file, 380 args.plugin_config_file, plugin_so, 381 args.build_file_type, args_para) 382 return 0 383 384 385if __name__ == '__main__': 386 sys.exit(main()) 387