1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3 4# 5# Copyright (c) 2023 Huawei Device Co., Ltd. 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19import os 20import argparse 21import sys 22 23from enum import Enum 24from resources.global_var import CURRENT_ARGS_DIR 25from resources.global_var import CURRENT_BUILD_ARGS 26from resources.global_var import DEFAULT_BUILD_ARGS 27from resources.global_var import CURRENT_SET_ARGS 28from resources.global_var import DEFAULT_SET_ARGS 29from resources.global_var import CURRENT_CLEAN_ARGS 30from resources.global_var import DEFAULT_CLEAN_ARGS 31from resources.global_var import DEFAULT_ENV_ARGS 32from resources.global_var import CURRENT_ENV_ARGS 33from resources.global_var import DEFAULT_TOOL_ARGS 34from resources.global_var import CURRENT_TOOL_ARGS 35from resources.global_var import DEFAULT_INDEP_BUILD_ARGS 36from resources.global_var import CURRENT_INDEP_BUILD_ARGS 37from resources.global_var import DEFAULT_INSTALL_ARGS 38from resources.global_var import CURRENT_INSTALL_ARGS 39from resources.global_var import DEFAULT_PACKAGE_ARGS 40from resources.global_var import CURRENT_PACKAGE_ARGS 41from resources.global_var import DEFAULT_PUBLISH_ARGS 42from resources.global_var import CURRENT_PUBLISH_ARGS 43from resources.global_var import DEFAULT_UPDATE_ARGS 44from resources.global_var import CURRENT_UPDATE_ARGS 45from resources.global_var import DEFAULT_PUSH_ARGS 46from resources.global_var import CURRENT_PUSH_ARGS 47from resources.global_var import ARGS_DIR 48from exceptions.ohos_exception import OHOSException 49from util.log_util import LogUtil 50from util.io_util import IoUtil 51from util.type_check_util import TypeCheckUtil 52from resolver.args_factory import ArgsFactory 53from containers.status import throw_exception 54 55 56class ModuleType(Enum): 57 58 BUILD = 0 59 SET = 1 60 ENV = 2 61 CLEAN = 3 62 TOOL = 4 63 INDEP_BUILD = 5 64 INSTALL = 6 65 PACKAGE = 7 66 PUBLISH = 8 67 UPDATE = 9 68 PUSH = 10 69 70class ArgType(): 71 72 NONE = 0 73 BOOL = 1 74 INT = 2 75 STR = 3 76 LIST = 4 77 DICT = 5 78 SUBPARSERS = 6 79 80 @staticmethod 81 def get_type(value: str): 82 if value == 'bool': 83 return ArgType.BOOL 84 elif value == "int": 85 return ArgType.INT 86 elif value == 'str': 87 return ArgType.STR 88 elif value == "list": 89 return ArgType.LIST 90 elif value == 'dict': 91 return ArgType.DICT 92 elif value == 'subparsers': 93 return ArgType.SUBPARSERS 94 else: 95 return ArgType.NONE 96 97 98class BuildPhase(): 99 100 NONE = 0 101 PRE_BUILD = 1 102 PRE_LOAD = 2 103 LOAD = 3 104 PRE_TARGET_GENERATE = 4 105 TARGET_GENERATE = 5 106 POST_TARGET_GENERATE = 6 107 PRE_TARGET_COMPILATION = 7 108 TARGET_COMPILATION = 8 109 POST_TARGET_COMPILATION = 9 110 POST_BUILD = 10 111 112 @staticmethod 113 def get_type(value: str): 114 if value == 'prebuild': 115 return BuildPhase.PRE_BUILD 116 elif value == "preload": 117 return BuildPhase.PRE_LOAD 118 elif value == 'load': 119 return BuildPhase.LOAD 120 elif value == "preTargetGenerate": 121 return BuildPhase.PRE_TARGET_GENERATE 122 elif value == 'targetGenerate': 123 return BuildPhase.TARGET_GENERATE 124 elif value == 'postTargetGenerate': 125 return BuildPhase.POST_TARGET_GENERATE 126 elif value == 'preTargetCompilation': 127 return BuildPhase.PRE_TARGET_COMPILATION 128 elif value == 'targetCompilation': 129 return BuildPhase.TARGET_COMPILATION 130 elif value == 'postTargetCompilation': 131 return BuildPhase.POST_TARGET_COMPILATION 132 elif value == 'postbuild': 133 return BuildPhase.POST_BUILD 134 else: 135 return BuildPhase.NONE 136 137 138class CleanPhase(): 139 140 REGULAR = 0 141 DEEP = 1 142 NONE = 2 143 144 @staticmethod 145 def get_type(value: str): 146 if value == 'regular': 147 return CleanPhase.REGULAR 148 elif value == 'deep': 149 return CleanPhase.DEEP 150 else: 151 return CleanPhase.NONE 152 153 154class Arg(): 155 156 def __init__(self, name: str, helps: str, phase: str, 157 attribute: dict, argtype: ArgType, value, 158 resolve_function: str): 159 self._arg_name = name 160 self._arg_help = helps 161 self._arg_phase = phase 162 self._arg_attribute = attribute 163 self._arg_type = argtype 164 self._arg_value = value 165 self._resolve_function = resolve_function 166 167 @property 168 def arg_name(self): 169 return self._arg_name 170 171 @property 172 def arg_value(self): 173 return self._arg_value 174 175 @arg_value.setter 176 def arg_value(self, value): 177 self._arg_value = value 178 179 @property 180 def arg_help(self): 181 return self._arg_help 182 183 @property 184 def arg_attribute(self): 185 return self._arg_attribute 186 187 @property 188 def arg_phase(self): 189 return self._arg_phase 190 191 @property 192 def arg_type(self): 193 return self._arg_type 194 195 @property 196 def resolve_function(self): 197 return self._resolve_function 198 199 @resolve_function.setter 200 def resolve_function(self, value): 201 self._resolve_function = value 202 203 @staticmethod 204 @throw_exception 205 def create_instance_by_dict(data: dict): 206 arg_name = str(data['arg_name']).replace("-", "_")[2:] 207 arg_help = str(data['arg_help']) 208 arg_phase = BuildPhase.get_type(str(data['arg_phase'])) 209 arg_attibute = dict(data['arg_attribute']) 210 arg_type = ArgType.get_type(data['arg_type']) 211 arg_value = '' 212 if arg_type == ArgType.BOOL: 213 arg_value = data['argDefault'] 214 elif arg_type == ArgType.INT: 215 arg_value = int(data['argDefault']) 216 elif arg_type == ArgType.STR: 217 arg_value = data['argDefault'] 218 elif arg_type == ArgType.LIST: 219 arg_value = list(data['argDefault']) 220 elif arg_type == ArgType.DICT: 221 arg_value = dict(data['argDefault']) 222 elif arg_type == ArgType.SUBPARSERS: 223 arg_value = list(data['argDefault']) 224 else: 225 raise OHOSException('Unknown arg type "{}" for arg "{}"'.format( 226 arg_type, arg_name), "0003") 227 resolve_function = data['resolve_function'] 228 return Arg(arg_name, arg_help, arg_phase, arg_attibute, arg_type, arg_value, resolve_function) 229 230 @staticmethod 231 def get_help(module_type: ModuleType) -> str: 232 parser = argparse.ArgumentParser() 233 all_args = Arg.read_args_file(module_type) 234 235 for arg in all_args.values(): 236 arg = dict(arg) 237 ArgsFactory.genetic_add_option(parser, arg) 238 239 parser.usage = 'hb {} [option]'.format(module_type.name.lower()) 240 parser.parse_known_args(sys.argv[2:]) 241 242 return parser.format_help() 243 244 @staticmethod 245 def parse_all_args(module_type: ModuleType) -> dict: 246 args_dict = {} 247 parser = argparse.ArgumentParser() 248 all_args = Arg.read_args_file(module_type) 249 250 for arg in all_args.values(): 251 arg = dict(arg) 252 ArgsFactory.genetic_add_option(parser, arg) 253 oh_arg = Arg.create_instance_by_dict(arg) 254 args_dict[oh_arg.arg_name] = oh_arg 255 256 parser.usage = 'hb {} [option]'.format(module_type.name.lower()) 257 parser_args = parser.parse_known_args(sys.argv[2:]) 258 259 for oh_arg in args_dict.values(): 260 if isinstance(oh_arg, Arg): 261 assigned_value = parser_args[0].__dict__[oh_arg.arg_name] 262 if oh_arg.arg_type == ArgType.LIST: 263 convert_assigned_value = TypeCheckUtil.tile_list(assigned_value) 264 convert_assigned_value = list(set(convert_assigned_value)) 265 elif oh_arg.arg_type == ArgType.SUBPARSERS: 266 convert_assigned_value = TypeCheckUtil.tile_list(assigned_value) 267 if len(convert_assigned_value): 268 convert_assigned_value = list(set(convert_assigned_value)) 269 convert_assigned_value.extend(parser_args[1]) 270 convert_assigned_value.sort(key=sys.argv[2:].index) 271 elif oh_arg.arg_type == ArgType.BOOL: 272 if str(assigned_value).lower() == 'false': 273 convert_assigned_value = False 274 elif str(assigned_value).lower() == 'true' or assigned_value is None: 275 convert_assigned_value = True 276 else: 277 convert_assigned_value = assigned_value 278 279 if oh_arg.arg_attribute.get('deprecated', None) and oh_arg.arg_value != convert_assigned_value: 280 LogUtil.hb_warning( 281 'compile option "{}" will be deprecated, \ 282 please consider use other options'.format(oh_arg.arg_name)) 283 oh_arg.arg_value = convert_assigned_value 284 Arg.write_args_file( 285 oh_arg.arg_name, oh_arg.arg_value, module_type) 286 287 return args_dict 288 289 @staticmethod 290 @throw_exception 291 def write_args_file(key: str, value, module_type: ModuleType): 292 args_file_path = '' 293 if module_type == ModuleType.BUILD: 294 args_file_path = CURRENT_BUILD_ARGS 295 elif module_type == ModuleType.SET: 296 args_file_path = CURRENT_SET_ARGS 297 elif module_type == ModuleType.CLEAN: 298 args_file_path = CURRENT_CLEAN_ARGS 299 elif module_type == ModuleType.ENV: 300 args_file_path = CURRENT_ENV_ARGS 301 elif module_type == ModuleType.TOOL: 302 args_file_path = CURRENT_TOOL_ARGS 303 elif module_type == ModuleType.INDEP_BUILD: 304 args_file_path = CURRENT_INDEP_BUILD_ARGS 305 elif module_type == ModuleType.INSTALL: 306 args_file_path = CURRENT_INSTALL_ARGS 307 elif module_type == ModuleType.PACKAGE: 308 args_file_path = CURRENT_PACKAGE_ARGS 309 elif module_type == ModuleType.PUBLISH: 310 args_file_path = CURRENT_PUBLISH_ARGS 311 elif module_type == ModuleType.UPDATE: 312 args_file_path = CURRENT_UPDATE_ARGS 313 elif module_type == ModuleType.PUSH: 314 args_file_path = CURRENT_PUSH_ARGS 315 else: 316 raise OHOSException( 317 'You are trying to write args file, but there is no corresponding module "{}" args file' 318 .format(module_type), "0002") 319 args_file = Arg.read_args_file(module_type) 320 args_file[key]["argDefault"] = value 321 IoUtil.dump_json_file(args_file_path, args_file) 322 323 @staticmethod 324 @throw_exception 325 def read_args_file(module_type: ModuleType): 326 args_file_path = '' 327 default_file_path = '' 328 if module_type == ModuleType.BUILD: 329 args_file_path = CURRENT_BUILD_ARGS 330 default_file_path = DEFAULT_BUILD_ARGS 331 elif module_type == ModuleType.SET: 332 args_file_path = CURRENT_SET_ARGS 333 default_file_path = DEFAULT_SET_ARGS 334 elif module_type == ModuleType.CLEAN: 335 args_file_path = CURRENT_CLEAN_ARGS 336 default_file_path = DEFAULT_CLEAN_ARGS 337 elif module_type == ModuleType.ENV: 338 args_file_path = CURRENT_ENV_ARGS 339 default_file_path = DEFAULT_ENV_ARGS 340 elif module_type == ModuleType.TOOL: 341 args_file_path = CURRENT_TOOL_ARGS 342 default_file_path = DEFAULT_TOOL_ARGS 343 elif module_type == ModuleType.INDEP_BUILD: 344 args_file_path = CURRENT_INDEP_BUILD_ARGS 345 default_file_path = DEFAULT_INDEP_BUILD_ARGS 346 elif module_type == ModuleType.INSTALL: 347 args_file_path = CURRENT_INSTALL_ARGS 348 default_file_path = DEFAULT_INSTALL_ARGS 349 elif module_type == ModuleType.PACKAGE: 350 args_file_path = CURRENT_PACKAGE_ARGS 351 default_file_path = DEFAULT_PACKAGE_ARGS 352 elif module_type == ModuleType.PUBLISH: 353 args_file_path = CURRENT_PUBLISH_ARGS 354 default_file_path = DEFAULT_PUBLISH_ARGS 355 elif module_type == ModuleType.UPDATE: 356 args_file_path = CURRENT_UPDATE_ARGS 357 default_file_path = DEFAULT_UPDATE_ARGS 358 elif module_type == ModuleType.PUSH: 359 args_file_path = CURRENT_PUSH_ARGS 360 default_file_path = DEFAULT_PUSH_ARGS 361 else: 362 raise OHOSException( 363 'You are trying to read args file, but there is no corresponding module "{}" args file' 364 .format(module_type.name.lower()), "0018") 365 if not os.path.exists(CURRENT_ARGS_DIR): 366 os.makedirs(CURRENT_ARGS_DIR, exist_ok=True) 367 if not os.path.exists(args_file_path): 368 IoUtil.copy_file(src=default_file_path, dst=args_file_path) 369 return IoUtil.read_json_file(args_file_path) 370 371 @staticmethod 372 def clean_args_file(): 373 if os.path.exists(CURRENT_ARGS_DIR): 374 for file in os.listdir(CURRENT_ARGS_DIR): 375 if file.endswith('.json') and os.path.exists(os.path.join(CURRENT_ARGS_DIR, file)): 376 os.remove(os.path.join(CURRENT_ARGS_DIR, file)) 377 378 @staticmethod 379 def clean_args_file_by_type(module_type: ModuleType): 380 args_file_path = '' 381 if module_type == ModuleType.INSTALL: 382 args_file_path = CURRENT_INSTALL_ARGS 383 elif module_type == ModuleType.PACKAGE: 384 args_file_path = CURRENT_PACKAGE_ARGS 385 elif module_type == ModuleType.UPDATE: 386 args_file_path = CURRENT_UPDATE_ARGS 387 elif module_type == ModuleType.ENV: 388 args_file_path = CURRENT_ENV_ARGS 389 elif module_type == ModuleType.INDEP_BUILD: 390 args_file_path = CURRENT_INDEP_BUILD_ARGS 391 elif module_type == ModuleType.PUSH: 392 args_file_path = CURRENT_PUSH_ARGS 393 if os.path.exists(args_file_path): 394 os.remove(args_file_path) 395