• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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