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 70 71class ArgType(): 72 73 NONE = 0 74 BOOL = 1 75 INT = 2 76 STR = 3 77 LIST = 4 78 DICT = 5 79 SUBPARSERS = 6 80 81 @staticmethod 82 def get_type(value: str): 83 if value == 'bool': 84 return ArgType.BOOL 85 elif value == "int": 86 return ArgType.INT 87 elif value == 'str': 88 return ArgType.STR 89 elif value == "list": 90 return ArgType.LIST 91 elif value == 'dict': 92 return ArgType.DICT 93 elif value == 'subparsers': 94 return ArgType.SUBPARSERS 95 else: 96 return ArgType.NONE 97 98 99class BuildPhase(): 100 101 NONE = 0 102 PRE_BUILD = 1 103 PRE_LOAD = 2 104 LOAD = 3 105 PRE_TARGET_GENERATE = 4 106 TARGET_GENERATE = 5 107 POST_TARGET_GENERATE = 6 108 PRE_TARGET_COMPILATION = 7 109 TARGET_COMPILATION = 8 110 POST_TARGET_COMPILATION = 9 111 POST_BUILD = 10 112 HPM_DOWNLOAD = 11 113 INDEP_COMPILATION = 12 114 115 @staticmethod 116 def get_type(value: str): 117 if value == 'prebuild': 118 return BuildPhase.PRE_BUILD 119 elif value == "preload": 120 return BuildPhase.PRE_LOAD 121 elif value == 'load': 122 return BuildPhase.LOAD 123 elif value == "preTargetGenerate": 124 return BuildPhase.PRE_TARGET_GENERATE 125 elif value == 'targetGenerate': 126 return BuildPhase.TARGET_GENERATE 127 elif value == 'postTargetGenerate': 128 return BuildPhase.POST_TARGET_GENERATE 129 elif value == 'preTargetCompilation': 130 return BuildPhase.PRE_TARGET_COMPILATION 131 elif value == 'targetCompilation': 132 return BuildPhase.TARGET_COMPILATION 133 elif value == 'postTargetCompilation': 134 return BuildPhase.POST_TARGET_COMPILATION 135 elif value == 'postbuild': 136 return BuildPhase.POST_BUILD 137 elif value == 'hpmDownload': 138 return BuildPhase.HPM_DOWNLOAD 139 elif value == 'indepCompilation': 140 return BuildPhase.INDEP_COMPILATION 141 else: 142 return BuildPhase.NONE 143 144 145class CleanPhase(): 146 147 REGULAR = 0 148 DEEP = 1 149 NONE = 2 150 151 @staticmethod 152 def get_type(value: str): 153 if value == 'regular': 154 return CleanPhase.REGULAR 155 elif value == 'deep': 156 return CleanPhase.DEEP 157 else: 158 return CleanPhase.NONE 159 160 161class Arg(): 162 163 def __init__(self, name: str, helps: str, phase: str, 164 attribute: dict, argtype: ArgType, value, 165 resolve_function: str): 166 self._arg_name = name 167 self._arg_help = helps 168 self._arg_phase = phase 169 self._arg_attribute = attribute 170 self._arg_type = argtype 171 self._arg_value = value 172 self._resolve_function = resolve_function 173 174 @property 175 def arg_name(self): 176 return self._arg_name 177 178 @property 179 def arg_value(self): 180 return self._arg_value 181 182 @property 183 def arg_help(self): 184 return self._arg_help 185 186 @property 187 def arg_attribute(self): 188 return self._arg_attribute 189 190 @property 191 def arg_phase(self): 192 return self._arg_phase 193 194 @property 195 def arg_type(self): 196 return self._arg_type 197 198 @property 199 def resolve_function(self): 200 return self._resolve_function 201 202 @staticmethod 203 @throw_exception 204 def create_instance_by_dict(data: dict): 205 arg_name = str(data['arg_name']).replace("-", "_")[2:] 206 arg_help = str(data['arg_help']) 207 arg_phase = data['arg_phase'] 208 if (isinstance(arg_phase, list)): 209 arg_phase = [BuildPhase.get_type(str(phase_item)) for phase_item in arg_phase] 210 else: 211 arg_phase = BuildPhase.get_type(str(data['arg_phase'])) 212 arg_attibute = dict(data['arg_attribute']) 213 arg_type = ArgType.get_type(data['arg_type']) 214 arg_value = '' 215 if arg_type == ArgType.BOOL: 216 arg_value = data['argDefault'] 217 elif arg_type == ArgType.INT: 218 arg_value = int(data['argDefault']) 219 elif arg_type == ArgType.STR: 220 arg_value = data['argDefault'] 221 elif arg_type == ArgType.LIST: 222 arg_value = list(data['argDefault']) 223 elif arg_type == ArgType.DICT: 224 arg_value = dict(data['argDefault']) 225 elif arg_type == ArgType.SUBPARSERS: 226 arg_value = list(data['argDefault']) 227 else: 228 raise OHOSException('Unknown arg type "{}" for arg "{}"'.format( 229 arg_type, arg_name), "0003") 230 resolve_function = data['resolve_function'] 231 return Arg(arg_name, arg_help, arg_phase, arg_attibute, arg_type, arg_value, resolve_function) 232 233 @staticmethod 234 def get_help(module_type: ModuleType) -> str: 235 parser = argparse.ArgumentParser() 236 all_args = Arg.read_args_file(module_type) 237 238 for arg in all_args.values(): 239 arg = dict(arg) 240 ArgsFactory.genetic_add_option(parser, arg) 241 if module_type == ModuleType.INDEP_BUILD: 242 ArgsFactory.genetic_add_option(parser, {'arg_name': '-i', 'argDefault': '', 243 'arg_help': "Default:''. Help:specify independent build, run 'hb build {part_name} -i'", 244 'arg_phase': 'prebuild', 'arg_type': 'str', 'arg_attribute': {}, 245 'resolve_function': '', 'testFunction': ''}) 246 ArgsFactory.genetic_add_option(parser, {'arg_name': '-t', 'argDefault': '', 247 'arg_help': "Default:''. Help:specify build test module, run 'hb build {part_name} -t'", 248 'arg_phase': 'prebuild', 'arg_type': 'str', 'arg_attribute': {}, 249 'resolve_function': '', 'testFunction': ''}) 250 251 parser.usage = 'hb {} [option]'.format(module_type.name.lower()) 252 parser.parse_known_args(sys.argv[2:]) 253 254 return parser.format_help() 255 256 @staticmethod 257 def parse_all_args(module_type: ModuleType) -> dict: 258 args_dict = {} 259 parser = argparse.ArgumentParser() 260 all_args = Arg.read_args_file(module_type) 261 262 for arg in all_args.values(): 263 arg = dict(arg) 264 ArgsFactory.genetic_add_option(parser, arg) 265 oh_arg = Arg.create_instance_by_dict(arg) 266 args_dict[oh_arg.arg_name] = oh_arg 267 268 parser.usage = 'hb {} [option]'.format(module_type.name.lower()) 269 parser_args = parser.parse_known_args(sys.argv[2:]) 270 271 for oh_arg in args_dict.values(): 272 if isinstance(oh_arg, Arg): 273 assigned_value = parser_args[0].__dict__[oh_arg.arg_name] 274 if oh_arg.arg_type == ArgType.LIST: 275 convert_assigned_value = TypeCheckUtil.tile_list(assigned_value) 276 convert_assigned_value = list(set(convert_assigned_value)) 277 elif oh_arg.arg_type == ArgType.SUBPARSERS: 278 convert_assigned_value = TypeCheckUtil.tile_list(assigned_value) 279 if len(convert_assigned_value): 280 convert_assigned_value = list(set(convert_assigned_value)) 281 convert_assigned_value.extend(parser_args[1]) 282 convert_assigned_value.sort(key=sys.argv[2:].index) 283 elif oh_arg.arg_type == ArgType.BOOL: 284 if str(assigned_value).lower() == 'false': 285 convert_assigned_value = False 286 elif str(assigned_value).lower() == 'true' or assigned_value is None: 287 convert_assigned_value = True 288 else: 289 convert_assigned_value = assigned_value 290 291 if oh_arg.arg_attribute.get('deprecated', None) and oh_arg.arg_value != convert_assigned_value: 292 LogUtil.hb_warning( 293 'compile option "{}" will be deprecated, \ 294 please consider use other options'.format(oh_arg.arg_name)) 295 oh_arg.arg_value = convert_assigned_value 296 Arg.write_args_file( 297 oh_arg.arg_name, oh_arg.arg_value, module_type) 298 299 return args_dict 300 301 @arg_value.setter 302 def arg_value(self, value): 303 self._arg_value = value 304 305 @resolve_function.setter 306 def resolve_function(self, value): 307 self._resolve_function = value 308 309 @staticmethod 310 @throw_exception 311 def write_args_file(key: str, value, module_type: ModuleType): 312 args_file_path = '' 313 if module_type == ModuleType.BUILD: 314 args_file_path = CURRENT_BUILD_ARGS 315 elif module_type == ModuleType.SET: 316 args_file_path = CURRENT_SET_ARGS 317 elif module_type == ModuleType.CLEAN: 318 args_file_path = CURRENT_CLEAN_ARGS 319 elif module_type == ModuleType.ENV: 320 args_file_path = CURRENT_ENV_ARGS 321 elif module_type == ModuleType.TOOL: 322 args_file_path = CURRENT_TOOL_ARGS 323 elif module_type == ModuleType.INDEP_BUILD: 324 args_file_path = CURRENT_INDEP_BUILD_ARGS 325 elif module_type == ModuleType.INSTALL: 326 args_file_path = CURRENT_INSTALL_ARGS 327 elif module_type == ModuleType.PACKAGE: 328 args_file_path = CURRENT_PACKAGE_ARGS 329 elif module_type == ModuleType.PUBLISH: 330 args_file_path = CURRENT_PUBLISH_ARGS 331 elif module_type == ModuleType.UPDATE: 332 args_file_path = CURRENT_UPDATE_ARGS 333 elif module_type == ModuleType.PUSH: 334 args_file_path = CURRENT_PUSH_ARGS 335 else: 336 raise OHOSException( 337 'You are trying to write args file, but there is no corresponding module "{}" args file' 338 .format(module_type), "0002") 339 args_file = Arg.read_args_file(module_type) 340 args_file[key]["argDefault"] = value 341 IoUtil.dump_json_file(args_file_path, args_file) 342 343 @staticmethod 344 @throw_exception 345 def read_args_file(module_type: ModuleType): 346 args_file_path = '' 347 default_file_path = '' 348 if module_type == ModuleType.BUILD: 349 args_file_path = CURRENT_BUILD_ARGS 350 default_file_path = DEFAULT_BUILD_ARGS 351 elif module_type == ModuleType.SET: 352 args_file_path = CURRENT_SET_ARGS 353 default_file_path = DEFAULT_SET_ARGS 354 elif module_type == ModuleType.CLEAN: 355 args_file_path = CURRENT_CLEAN_ARGS 356 default_file_path = DEFAULT_CLEAN_ARGS 357 elif module_type == ModuleType.ENV: 358 args_file_path = CURRENT_ENV_ARGS 359 default_file_path = DEFAULT_ENV_ARGS 360 elif module_type == ModuleType.TOOL: 361 args_file_path = CURRENT_TOOL_ARGS 362 default_file_path = DEFAULT_TOOL_ARGS 363 elif module_type == ModuleType.INDEP_BUILD: 364 args_file_path = CURRENT_INDEP_BUILD_ARGS 365 default_file_path = DEFAULT_INDEP_BUILD_ARGS 366 elif module_type == ModuleType.INSTALL: 367 args_file_path = CURRENT_INSTALL_ARGS 368 default_file_path = DEFAULT_INSTALL_ARGS 369 elif module_type == ModuleType.PACKAGE: 370 args_file_path = CURRENT_PACKAGE_ARGS 371 default_file_path = DEFAULT_PACKAGE_ARGS 372 elif module_type == ModuleType.PUBLISH: 373 args_file_path = CURRENT_PUBLISH_ARGS 374 default_file_path = DEFAULT_PUBLISH_ARGS 375 elif module_type == ModuleType.UPDATE: 376 args_file_path = CURRENT_UPDATE_ARGS 377 default_file_path = DEFAULT_UPDATE_ARGS 378 elif module_type == ModuleType.PUSH: 379 args_file_path = CURRENT_PUSH_ARGS 380 default_file_path = DEFAULT_PUSH_ARGS 381 else: 382 raise OHOSException( 383 'You are trying to read args file, but there is no corresponding module "{}" args file' 384 .format(module_type.name.lower()), "0018") 385 if not os.path.exists(CURRENT_ARGS_DIR): 386 os.makedirs(CURRENT_ARGS_DIR, exist_ok=True) 387 if not os.path.exists(args_file_path): 388 IoUtil.copy_file(src=default_file_path, dst=args_file_path) 389 return IoUtil.read_json_file(args_file_path) 390 391 @staticmethod 392 def clean_args_file(): 393 if os.path.exists(CURRENT_ARGS_DIR): 394 for file in os.listdir(CURRENT_ARGS_DIR): 395 if file.endswith('.json') and os.path.exists(os.path.join(CURRENT_ARGS_DIR, file)): 396 os.remove(os.path.join(CURRENT_ARGS_DIR, file)) 397 398 @staticmethod 399 def clean_args_file_by_type(module_type: ModuleType): 400 args_file_path = '' 401 if module_type == ModuleType.INSTALL: 402 args_file_path = CURRENT_INSTALL_ARGS 403 elif module_type == ModuleType.PACKAGE: 404 args_file_path = CURRENT_PACKAGE_ARGS 405 elif module_type == ModuleType.UPDATE: 406 args_file_path = CURRENT_UPDATE_ARGS 407 elif module_type == ModuleType.ENV: 408 args_file_path = CURRENT_ENV_ARGS 409 elif module_type == ModuleType.INDEP_BUILD: 410 args_file_path = CURRENT_INDEP_BUILD_ARGS 411 elif module_type == ModuleType.PUSH: 412 args_file_path = CURRENT_PUSH_ARGS 413 if os.path.exists(args_file_path): 414 os.remove(args_file_path) 415