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 ARGS_DIR 36from exceptions.ohos_exception import OHOSException 37from util.log_util import LogUtil 38from util.io_util import IoUtil 39from util.type_check_util import TypeCheckUtil 40from resolver.args_factory import ArgsFactory 41from containers.status import throw_exception 42 43 44class ModuleType(Enum): 45 46 BUILD = 0 47 SET = 1 48 ENV = 2 49 CLEAN = 3 50 TOOL = 4 51 52 53class ArgType(): 54 55 NONE = 0 56 BOOL = 1 57 INT = 2 58 STR = 3 59 LIST = 4 60 DICT = 5 61 SUBPARSERS = 6 62 63 @staticmethod 64 def get_type(value: str): 65 if value == 'bool': 66 return ArgType.BOOL 67 elif value == "int": 68 return ArgType.INT 69 elif value == 'str': 70 return ArgType.STR 71 elif value == "list": 72 return ArgType.LIST 73 elif value == 'dict': 74 return ArgType.DICT 75 elif value == 'subparsers': 76 return ArgType.SUBPARSERS 77 else: 78 return ArgType.NONE 79 80 81class BuildPhase(): 82 83 NONE = 0 84 PRE_BUILD = 1 85 PRE_LOAD = 2 86 LOAD = 3 87 PRE_TARGET_GENERATE = 4 88 TARGET_GENERATE = 5 89 POST_TARGET_GENERATE = 6 90 PRE_TARGET_COMPILATION = 7 91 TARGET_COMPILATION = 8 92 POST_TARGET_COMPILATION = 9 93 POST_BUILD = 10 94 95 @staticmethod 96 def get_type(value: str): 97 if value == 'prebuild': 98 return BuildPhase.PRE_BUILD 99 elif value == "preload": 100 return BuildPhase.PRE_LOAD 101 elif value == 'load': 102 return BuildPhase.LOAD 103 elif value == "preTargetGenerate": 104 return BuildPhase.PRE_TARGET_GENERATE 105 elif value == 'targetGenerate': 106 return BuildPhase.TARGET_GENERATE 107 elif value == 'postTargetGenerate': 108 return BuildPhase.POST_TARGET_GENERATE 109 elif value == 'preTargetCompilation': 110 return BuildPhase.PRE_TARGET_COMPILATION 111 elif value == 'targetCompilation': 112 return BuildPhase.TARGET_COMPILATION 113 elif value == 'postTargetCompilation': 114 return BuildPhase.POST_TARGET_COMPILATION 115 elif value == 'postbuild': 116 return BuildPhase.POST_BUILD 117 else: 118 return BuildPhase.NONE 119 120 121class CleanPhase(): 122 123 REGULAR = 0 124 DEEP = 1 125 NONE = 2 126 127 @staticmethod 128 def get_type(value: str): 129 if value == 'regular': 130 return CleanPhase.REGULAR 131 elif value == 'deep': 132 return CleanPhase.DEEP 133 else: 134 return CleanPhase.NONE 135 136 137class Arg(): 138 139 def __init__(self, name: str, helps: str, phase: str, 140 attribute: dict, argtype: ArgType, value, 141 resolve_function: str): 142 self._arg_name = name 143 self._arg_help = helps 144 self._arg_phase = phase 145 self._arg_attribute = attribute 146 self._arg_type = argtype 147 self._arg_value = value 148 self._resolve_function = resolve_function 149 150 @property 151 def arg_name(self): 152 return self._arg_name 153 154 @property 155 def arg_value(self): 156 return self._arg_value 157 158 @arg_value.setter 159 def arg_value(self, value): 160 self._arg_value = value 161 162 @property 163 def arg_help(self): 164 return self._arg_help 165 166 @property 167 def arg_attribute(self): 168 return self._arg_attribute 169 170 @property 171 def arg_phase(self): 172 return self._arg_phase 173 174 @property 175 def arg_type(self): 176 return self._arg_type 177 178 @property 179 def resolve_function(self): 180 return self._resolve_function 181 182 @resolve_function.setter 183 def resolve_function(self, value): 184 self._resolve_function = value 185 186 @staticmethod 187 @throw_exception 188 def create_instance_by_dict(data: dict): 189 arg_name = str(data['arg_name']).replace("-", "_")[2:] 190 arg_help = str(data['arg_help']) 191 arg_phase = BuildPhase.get_type(str(data['arg_phase'])) 192 arg_attibute = dict(data['arg_attribute']) 193 arg_type = ArgType.get_type(data['arg_type']) 194 arg_value = '' 195 if arg_type == ArgType.BOOL: 196 arg_value = data['argDefault'] 197 elif arg_type == ArgType.INT: 198 arg_value = int(data['argDefault']) 199 elif arg_type == ArgType.STR: 200 arg_value = data['argDefault'] 201 elif arg_type == ArgType.LIST: 202 arg_value = list(data['argDefault']) 203 elif arg_type == ArgType.DICT: 204 arg_value = dict(data['argDefault']) 205 elif arg_type == ArgType.SUBPARSERS: 206 arg_value = list(data['argDefault']) 207 else: 208 raise OHOSException('Unknown arg type "{}" for arg "{}"'.format( 209 arg_type, arg_name), "0003") 210 resolve_function = data['resolve_function'] 211 return Arg(arg_name, arg_help, arg_phase, arg_attibute, arg_type, arg_value, resolve_function) 212 213 @staticmethod 214 def get_help(module_type: ModuleType) -> str: 215 parser = argparse.ArgumentParser() 216 all_args = Arg.read_args_file(module_type) 217 218 for arg in all_args.values(): 219 arg = dict(arg) 220 ArgsFactory.genetic_add_option(parser, arg) 221 222 parser.usage = 'hb {} [option]'.format(module_type.name.lower()) 223 parser.parse_known_args(sys.argv[2:]) 224 225 return parser.format_help() 226 227 @staticmethod 228 def parse_all_args(module_type: ModuleType) -> dict: 229 args_dict = {} 230 parser = argparse.ArgumentParser() 231 all_args = Arg.read_args_file(module_type) 232 233 for arg in all_args.values(): 234 arg = dict(arg) 235 ArgsFactory.genetic_add_option(parser, arg) 236 oh_arg = Arg.create_instance_by_dict(arg) 237 args_dict[oh_arg.arg_name] = oh_arg 238 239 parser.usage = 'hb {} [option]'.format(module_type.name.lower()) 240 parser_args = parser.parse_known_args(sys.argv[2:]) 241 242 for oh_arg in args_dict.values(): 243 if isinstance(oh_arg, Arg): 244 assigned_value = parser_args[0].__dict__[oh_arg.arg_name] 245 if oh_arg.arg_type == ArgType.LIST: 246 convert_assigned_value = TypeCheckUtil.tile_list(assigned_value) 247 convert_assigned_value = list(set(convert_assigned_value)) 248 elif oh_arg.arg_type == ArgType.SUBPARSERS: 249 convert_assigned_value = TypeCheckUtil.tile_list(assigned_value) 250 if len(convert_assigned_value): 251 convert_assigned_value = list(set(convert_assigned_value)) 252 convert_assigned_value.extend(parser_args[1]) 253 convert_assigned_value.sort(key=sys.argv[2:].index) 254 elif oh_arg.arg_type == ArgType.BOOL: 255 if str(assigned_value).lower() == 'false': 256 convert_assigned_value = False 257 elif str(assigned_value).lower() == 'true' or assigned_value is None: 258 convert_assigned_value = True 259 else: 260 convert_assigned_value = assigned_value 261 262 if oh_arg.arg_attribute.get('deprecated', None) and oh_arg.arg_value != convert_assigned_value: 263 LogUtil.hb_warning( 264 'compile option "{}" will be deprecated, \ 265 please consider use other options'.format(oh_arg.arg_name)) 266 oh_arg.arg_value = convert_assigned_value 267 Arg.write_args_file( 268 oh_arg.arg_name, oh_arg.arg_value, module_type) 269 270 return args_dict 271 272 @staticmethod 273 @throw_exception 274 def write_args_file(key: str, value, module_type: ModuleType): 275 args_file_path = '' 276 if module_type == ModuleType.BUILD: 277 args_file_path = CURRENT_BUILD_ARGS 278 elif module_type == ModuleType.SET: 279 args_file_path = CURRENT_SET_ARGS 280 elif module_type == ModuleType.CLEAN: 281 args_file_path = CURRENT_CLEAN_ARGS 282 elif module_type == ModuleType.ENV: 283 args_file_path = CURRENT_ENV_ARGS 284 elif module_type == ModuleType.TOOL: 285 args_file_path = CURRENT_TOOL_ARGS 286 else: 287 raise OHOSException( 288 'You are trying to write args file, but there is no corresponding module "{}" args file' 289 .format(module_type), "0002") 290 args_file = Arg.read_args_file(module_type) 291 args_file[key]["argDefault"] = value 292 IoUtil.dump_json_file(args_file_path, args_file) 293 294 @staticmethod 295 @throw_exception 296 def read_args_file(module_type: ModuleType): 297 args_file_path = '' 298 default_file_path = '' 299 if module_type == ModuleType.BUILD: 300 args_file_path = CURRENT_BUILD_ARGS 301 default_file_path = DEFAULT_BUILD_ARGS 302 elif module_type == ModuleType.SET: 303 args_file_path = CURRENT_SET_ARGS 304 default_file_path = DEFAULT_SET_ARGS 305 elif module_type == ModuleType.CLEAN: 306 args_file_path = CURRENT_CLEAN_ARGS 307 default_file_path = DEFAULT_CLEAN_ARGS 308 elif module_type == ModuleType.ENV: 309 args_file_path = CURRENT_ENV_ARGS 310 default_file_path = DEFAULT_ENV_ARGS 311 elif module_type == ModuleType.TOOL: 312 args_file_path = CURRENT_TOOL_ARGS 313 default_file_path = DEFAULT_TOOL_ARGS 314 else: 315 raise OHOSException( 316 'You are trying to read args file, but there is no corresponding module "{}" args file' 317 .format(module_type.name.lower()), "0018") 318 if not os.path.exists(CURRENT_ARGS_DIR): 319 os.makedirs(CURRENT_ARGS_DIR, exist_ok=True) 320 if not os.path.exists(args_file_path): 321 IoUtil.copy_file(src=default_file_path, dst=args_file_path) 322 return IoUtil.read_json_file(args_file_path) 323 324 @staticmethod 325 def clean_args_file(): 326 if os.path.exists(CURRENT_ARGS_DIR): 327 for file in os.listdir(CURRENT_ARGS_DIR): 328 if file.endswith('.json') and os.path.exists(os.path.join(CURRENT_ARGS_DIR, file)): 329 os.remove(os.path.join(CURRENT_ARGS_DIR, file)) 330