• 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
19
20import sys
21import os
22import time
23import threading
24from enum import Enum
25
26from containers.status import throw_exception
27from exceptions.ohos_exception import OHOSException
28from services.interface.build_file_generator_interface import BuildFileGeneratorInterface
29from resources.config import Config
30from containers.arg import Arg, ModuleType
31from util.system_util import SystemUtil
32from util.io_util import IoUtil
33from util.log_util import LogUtil
34
35
36class CMDTYPE(Enum):
37    GEN = 1
38    PATH = 2
39    DESC = 3
40    LS = 4
41    REFS = 5
42    FORMAT = 6
43    CLEAN = 7
44
45
46class Gn(BuildFileGeneratorInterface):
47
48    def __init__(self):
49        super().__init__()
50        self.config = Config()
51        self._regist_gn_path()
52
53    def run(self):
54        self.execute_gn_cmd(CMDTYPE.GEN)
55
56    @throw_exception
57    def execute_gn_cmd(self, cmd_type: int, **kwargs):
58        if cmd_type == CMDTYPE.GEN:
59            return self._execute_gn_gen_cmd()
60        elif cmd_type == CMDTYPE.PATH:
61            return self._execute_gn_path_cmd(**kwargs)
62        elif cmd_type == CMDTYPE.DESC:
63            return self._execute_gn_desc_cmd(**kwargs)
64        elif cmd_type == CMDTYPE.LS:
65            return self._execute_gn_ls_cmd(**kwargs)
66        elif cmd_type == CMDTYPE.REFS:
67            return self._execute_gn_refs_cmd(**kwargs)
68        elif cmd_type == CMDTYPE.FORMAT:
69            return self._execute_gn_format_cmd(**kwargs)
70        elif cmd_type == CMDTYPE.CLEAN:
71            return self._execute_gn_clean_cmd(**kwargs)
72        else:
73            raise OHOSException(
74                'You are tring to use an unsupported gn cmd type "{}"'.format(cmd_type), '3001')
75
76    '''Description: Get gn excutable path and regist it
77    @parameter: none
78    @return: Status
79    '''
80
81    @throw_exception
82    def _regist_gn_path(self):
83        gn_path = os.path.join(self.config.root_path, 'prebuilts/build-tools/{}-x86/bin/gn'
84                .format(sys.platform))
85        if os.path.exists(gn_path):
86            self.exec = gn_path
87        else:
88            raise OHOSException(
89                'There is no gn executable file at {}'.format(gn_path), '0001')
90
91    '''Description: Convert all registed args into a list
92    @parameter: none
93    @return: list of all registed args
94    '''
95
96    def _convert_args(self) -> list:
97        args_list = []
98
99        for key, value in self.args_dict.items():
100            if isinstance(value, bool):
101                args_list.append('{}={}'.format(key, str(value).lower()))
102
103            elif isinstance(value, str):
104                args_list.append('{}="{}"'.format(key, value))
105
106            elif isinstance(value, int):
107                args_list.append('{}={}'.format(key, value))
108
109            elif isinstance(value, list):
110                args_list.append('{}="{}"'.format(key, "&&".join(value)))
111
112        return args_list
113
114    '''Description: Convert all registed flags into a list
115    @parameter: none
116    @return: list of all registed flags
117    '''
118
119    def _convert_flags(self) -> list:
120        flags_list = []
121
122        for key, value in self.flags_dict.items():
123            if key == 'gn_flags' and isinstance(value, list):
124                flags_list += value
125            elif value == '':
126                flags_list.append('{}'.format(key))
127            else:
128                flags_list.append('{}={}'.format(key, str(value)).lower())
129
130        return flags_list
131
132    '''Description: Option validity check
133    @parameter: "option": Option to be checked
134                "args_file": Option config file
135    @return: Inspection result(True|False)
136    '''
137
138    def _check_options_validity(self, option: str, args_file: dict):
139        support_sub_options = args_file.get(
140            "arg_attribute").get("support_sub_options")
141        option_name = option.lstrip('-')
142        option_value = ""
143        if '=' in option:
144            option_name, option_value = option.lstrip('-').split('=')
145        if option_name in support_sub_options:
146            sub_optional_list = support_sub_options.get(
147                option_name).get("arg_attribute").get("optional")
148            if sub_optional_list and option_value not in sub_optional_list:
149                if not len(option_value):
150                    raise OHOSException('ERROR argument "--{}": Invalid choice "{}". '
151                                        'choose from {}'.format(option_name, option_value, sub_optional_list), '3006')
152                else:
153                    raise OHOSException('ERROR argument "--{}": Invalid choice "{}". '
154                                        'choose from {}'.format(option_name, option_value, sub_optional_list), '3003')
155        else:
156            raise OHOSException('ERROR argument "{}": Invalid choice "{}". '
157                                'choose from {}'.format(args_file.get("arg_name"),
158                                                        option, list(support_sub_options.keys())), '3003')
159
160    '''Description: Execute 'gn gen' command using registed args
161    @parameter: kwargs TBD
162    @return: None
163    '''
164
165    @throw_exception
166    def _execute_gn_gen_cmd(self, **kwargs):
167        gn_gen_cmd = [self.exec, 'gen', '--json=gn_log.json',
168                      '--args={}'.format(' '.join(self._convert_args())),
169                      self.config.out_path] + self._convert_flags()
170        if self.config.os_level == 'mini' or self.config.os_level == 'small':
171            gn_gen_cmd.append(f'--script-executable={sys.executable}')
172        LogUtil.write_log(self.config.log_path, 'Excuting gn command: {} {} --args="{}" {}'.format(
173            self.exec, 'gen',
174            ' '.join(self._convert_args()).replace('"', "\\\""),
175            ' '.join(gn_gen_cmd[3:])),
176            'info')
177        if self.config.log_mode == 'silent':
178            def loading_animation(done_event):
179                frames = ["|", "/", "-", "\\"]
180                circle_times = 0
181                while not done_event.is_set():
182                    sys.stdout.write("\r" + "[OHOS INFO] GN parsing... " + frames[circle_times % len(frames)])
183                    sys.stdout.flush()
184                    time.sleep(0.1)
185                    circle_times += 1
186
187            def task(done_event):
188                SystemUtil.exec_command(gn_gen_cmd, self.config.log_path, log_mode=self.config.log_mode)
189                done_event.set()
190                sys.stdout.write("\n" + "[OHOS INFO] GN parsing Done\n")
191            done_event = threading.Event()
192            animation_thread = threading.Thread(target=loading_animation, args=(done_event,))
193            animation_thread.start()
194            task(done_event)
195            animation_thread.join()
196        else:
197            SystemUtil.exec_command(gn_gen_cmd, self.config.log_path)
198
199    '''Description: Execute 'gn path' command using registed args
200    @parameter: kwargs TBD
201    @return: None
202    '''
203
204    @throw_exception
205    def _execute_gn_path_cmd(self, **kwargs):
206        out_dir = kwargs.get("out_dir")
207        default_options = ['--all']
208        args_file = Arg.read_args_file(ModuleType.TOOL)['path']
209        if (os.path.exists(os.path.join(out_dir, "args.gn"))):
210            gn_path_cmd = [self.exec, 'path', out_dir]
211            for arg in kwargs.get('args_list'):
212                if arg.startswith('-'):
213                    self._check_options_validity(arg, args_file)
214                gn_path_cmd.append(arg)
215            gn_path_cmd.extend(default_options)
216            sort_index = gn_path_cmd.index
217            gn_path_cmd = list(set(gn_path_cmd))
218            gn_path_cmd.sort(key=sort_index)
219            SystemUtil.exec_command(gn_path_cmd)
220        else:
221            raise OHOSException(
222                '"{}" Not a build directory.'.format(out_dir), '3004')
223
224    '''Description: Execute 'gn desc' command using registed args
225    @parameter: kwargs TBD
226    @return: None
227    '''
228
229    @throw_exception
230    def _execute_gn_desc_cmd(self, **kwargs):
231        out_dir = kwargs.get("out_dir")
232        default_options = ['--tree', '--blame']
233        args_file = Arg.read_args_file(ModuleType.TOOL)['desc']
234        if (os.path.exists(os.path.join(out_dir, "args.gn"))):
235            gn_desc_cmd = [self.exec, 'desc', out_dir]
236            for arg in kwargs.get('args_list'):
237                if arg.startswith('-'):
238                    self._check_options_validity(arg, args_file)
239                gn_desc_cmd.append(arg)
240            gn_desc_cmd.extend(default_options)
241            sort_index = gn_desc_cmd.index
242            gn_desc_cmd = list(set(gn_desc_cmd))
243            gn_desc_cmd.sort(key=sort_index)
244            SystemUtil.exec_command(gn_desc_cmd)
245        else:
246            raise OHOSException(
247                '"{}" Not a build directory.'.format(out_dir), '3004')
248
249    '''Description: Execute 'gn ls' command using registed args
250    @parameter: kwargs TBD
251    @return: None
252    '''
253
254    @throw_exception
255    def _execute_gn_ls_cmd(self, **kwargs):
256        out_dir = kwargs.get("out_dir")
257        args_file = Arg.read_args_file(ModuleType.TOOL)['ls']
258        if (os.path.exists(os.path.join(out_dir, "args.gn"))):
259            gn_ls_cmd = [self.exec, 'ls', out_dir]
260            for arg in kwargs.get('args_list'):
261                if arg.startswith('-'):
262                    self._check_options_validity(arg, args_file)
263                gn_ls_cmd.append(arg)
264            SystemUtil.exec_command(gn_ls_cmd)
265        else:
266            raise OHOSException(
267                '"{}" Not a build directory.'.format(out_dir), '3004')
268
269    '''Description: Execute 'gn refs' command using registed args
270    @parameter: kwargs TBD
271    @return: None
272    '''
273
274    @throw_exception
275    def _execute_gn_refs_cmd(self, **kwargs):
276        out_dir = kwargs.get("out_dir")
277        args_file = Arg.read_args_file(ModuleType.TOOL)['refs']
278        if (os.path.exists(os.path.join(out_dir, "args.gn"))):
279            gn_refs_cmd = [self.exec, 'refs', out_dir]
280            for arg in kwargs.get('args_list'):
281                if arg.startswith('-'):
282                    self._check_options_validity(arg, args_file)
283                gn_refs_cmd.append(arg)
284            SystemUtil.exec_command(gn_refs_cmd)
285        else:
286            raise OHOSException(
287                '"{}" Not a build directory.'.format(out_dir), '3004')
288
289    '''Description: Execute 'gn format' command using registed args
290    @parameter: kwargs TBD
291    @return: None
292    '''
293
294    @throw_exception
295    def _execute_gn_format_cmd(self, **kwargs):
296        gn_format_cmd = [self.exec, 'format']
297        args_file = Arg.read_args_file(ModuleType.TOOL)['format']
298        for arg in kwargs.get("args_list"):
299            if (arg.endswith('.gn')):
300                if (os.path.exists(arg)):
301                    gn_format_cmd.append(arg)
302                else:
303                    raise OHOSException(
304                        "ERROR Couldn't read '{}'".format(arg), '3005')
305            else:
306                if arg.startswith('-'):
307                    self._check_options_validity(arg, args_file)
308                gn_format_cmd.append(arg)
309        SystemUtil.exec_command(gn_format_cmd)
310
311    '''Description: Execute 'gn clean' command using registed args
312    @parameter: kwargs TBD
313    @return: None
314    '''
315
316    @throw_exception
317    def _execute_gn_clean_cmd(self, **kwargs):
318        out_dir = kwargs.get("out_dir")
319        if (os.path.exists(os.path.join(out_dir, "args.gn"))):
320            gn_clean_cmd = [self.exec, 'clean', out_dir]
321            SystemUtil.exec_command(gn_clean_cmd)
322        else:
323            raise OHOSException('"{}" Not a build directory.'
324                                'Usage: "gn clean <out_dir>"'.format(out_dir), '3004')
325