• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# Copyright (c) 2023 Huawei Device Co., Ltd.
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import os
17import sys
18
19from containers.status import throw_exception
20from util.log_util import LogUtil
21from resources.config import Config
22from exceptions.ohos_exception import OHOSException
23from scripts.util.file_utils import read_json_file, write_json_file, write_file  # noqa: E402, E501  pylint: disable=C0413, E0611
24from . import load_bundle_file
25
26IMPORT_LIST = """
27# import("//build/ohos.gni")
28# import("//build/ohos_var.gni")
29import("//build/ohos/ohos_part.gni")
30import("//build/ohos/ohos_kits.gni")
31import("//build/ohos/ohos_test.gni")
32"""
33
34PART_TEMPLATE = """
35ohos_part("{}") {{
36  subsystem_name = "{}"
37  module_list = [
38    {}
39  ]
40  origin_name = "{}"
41  variant = "{}"
42}}"""
43
44INNER_KITS_TEMPLATE = """
45ohos_inner_kits("{0}_inner_kits") {{
46  sdk_libs = [
47{1}
48  ]
49  part_name = "{2}"
50  origin_name = "{3}"
51  variant = "{4}"
52}}"""
53
54SYSTEM_KITS_TEMPLATE = """
55ohos_system_kits("{0}_system_kits") {{
56  sdk_libs = [
57{1}
58  ]
59  part_name = "{0}"
60  origin_name = "{2}"
61  variant = "{3}"
62}}"""
63
64TEST_TEMPLATE = """
65ohos_part_test("{0}_test") {{
66  testonly = true
67  test_packages = [
68    {1}
69  ]
70  deps = [":{0}"]
71  part_name = "{0}"
72  subsystem_name = "{2}"
73}}"""
74
75
76def _normalize(label, path):
77    if not label.startswith('//'):
78        label = '//{}/{}'.format(path, label)
79    return label
80
81
82@throw_exception
83def get_syscap_from_bundle(bundle_file):
84    if not os.path.exists(bundle_file):
85        raise OHOSException(
86            "config file '{}' doesn't exist.".format(bundle_file), "2014")
87    bundle_config = read_json_file(bundle_file)
88    if bundle_config is None:
89        raise OHOSException(
90            "read file '{}' failed.".format(bundle_file), "2014")
91    part_name = bundle_config.get('component').get('name')
92    part_syscap = bundle_config.get('component').get('syscap')
93    return part_name, part_syscap
94
95
96def read_build_file(ohos_build_file):
97    if not os.path.exists(ohos_build_file):
98        raise OHOSException(
99            "config file '{}' doesn't exist.".format(ohos_build_file), "2014")
100    subsystem_config = read_json_file(ohos_build_file)
101    if subsystem_config is None:
102        raise OHOSException(
103            "read file '{}' failed.".format(ohos_build_file), "2014")
104    return subsystem_config
105
106
107class PartObject(object):
108    """"part object info, description part variant."""
109
110    def __init__(self, part_name, variant_name, part_config, toolchain,
111                 subsystem_name, target_arch, overrided_components):
112        self._origin_name = part_name
113        if variant_name != 'phone':
114            _real_name = '{}_{}'.format(part_name, variant_name)
115        else:
116            _real_name = part_name
117        self._part_name = _real_name
118        self._variant_name = variant_name
119        self._subsystem_name = subsystem_name
120        self._feature_list = []
121        self._toolchain = toolchain
122        self._inner_kits_info = {}
123        self._kits = []
124        self._target_arch = target_arch
125        self._system_capabilities = []
126        self._overrided_components = overrided_components
127        self._parsing_config(self._part_name, part_config, subsystem_name)
128
129    @classmethod
130    def _parsing_kits_lib(cls, kit_lib, is_inner_kits=False):
131        lib_config = []
132        lib_type = kit_lib.get('type')
133        if lib_type is None:
134            lib_type = 'so' if is_inner_kits else 'jar'
135        label = kit_lib.get('name')
136        if label is None:
137            raise Exception("kits lib config incorrect, required for name.")
138        lib_config.append('      type = "{}"'.format(lib_type))
139        lib_config.append('      name = "{}"'.format(label))
140        if lib_type == 'so' and 'header' in kit_lib:
141            header = kit_lib.get('header')
142            header_files = header.get('header_files')
143            lib_config.append('      header = {')
144            lib_config.append('        header_files = [')
145            for h_file in header_files:
146                lib_config.append('          "{}",'.format(h_file))
147            lib_config.append('        ]')
148            header_base = header.get('header_base')
149            lib_config.append('        header_base = "{}"'.format(header_base))
150            lib_config.append('      }')
151        if is_inner_kits is False and 'javadoc' in kit_lib:
152            javadoc_val = kit_lib.get('javadoc')
153            lib_config.append('      javadoc = {')
154            resource_dir = javadoc_val.get('resource_dir')
155            lib_config.append(
156                '        resource_dir = "{}"'.format(resource_dir))
157            lib_config.append('      }')
158        return lib_config
159
160    def _overrided_part_name(self):
161        overrided_components = self._overrided_components
162        full_part_name = f"{self._subsystem_name}:{self._origin_name}"
163        overrided_map = overrided_components.get(full_part_name)
164        if overrided_map:
165            # origin_name is same as part_name in variant phone
166            overrided_origin_name = overrided_map.get("partName")
167            overrided_part_name = overrided_origin_name
168        else:
169            overrided_part_name = self._part_name
170            overrided_origin_name = self._origin_name
171
172        return overrided_part_name, overrided_origin_name
173
174    @throw_exception
175    def _parsing_inner_kits(self, part_name, inner_kits_info, build_gn_content,
176                            target_arch):
177        inner_kits_libs_gn = []
178        for inner_kits_lib in inner_kits_info:
179            inner_kits_libs_gn.append('    {')
180            inner_kits_libs_gn.extend(
181                self._parsing_kits_lib(inner_kits_lib, True))
182            inner_kits_libs_gn.append('    },')
183
184        overrided_part_name, overrided_origin_name = self._overrided_part_name()
185
186        inner_kits_libs_gn_line = '\n'.join(inner_kits_libs_gn)
187        inner_kits_def = INNER_KITS_TEMPLATE.format(part_name,
188                                                    inner_kits_libs_gn_line,
189                                                    overrided_part_name,
190                                                    overrided_origin_name,
191                                                    self._variant_name)
192        build_gn_content.append(inner_kits_def)
193        # output inner kits info to resolve external deps
194        _libs_info = {}
195        for inner_kits_lib in inner_kits_info:
196            info = {'part_name': part_name}
197            label = inner_kits_lib.get('name')
198            lib_name = label.split(':')[1]
199            info['label'] = label
200            info['name'] = lib_name
201            if inner_kits_lib.get('visibility') is not None:
202                info['visibility'] = inner_kits_lib.get('visibility')
203            lib_type = inner_kits_lib.get('type')
204            if lib_type is None:
205                lib_type = 'so'
206            info['type'] = lib_type
207            prebuilt = inner_kits_lib.get('prebuilt_enable')
208            if prebuilt:
209                info['prebuilt_enable'] = prebuilt
210                prebuilt_source_libs = inner_kits_lib.get('prebuilt_source')
211                prebuilt_source = prebuilt_source_libs.get(target_arch)
212                info['prebuilt_source'] = prebuilt_source
213            else:
214                info['prebuilt_enable'] = False
215            # header files
216            if lib_type == 'so':
217                header = inner_kits_lib.get('header')
218                if header is None:
219                    raise OHOSException(
220                        "header not configuration, part_name = '{}'".format(
221                            part_name), "2014")
222                header_base = header.get('header_base')
223                if header_base is None:
224                    raise OHOSException(
225                        "header base not configuration, part_name = '{}'".
226                        format(part_name), "2014")
227                info['header_base'] = header_base
228                info['header_files'] = header.get('header_files')
229            _libs_info[lib_name] = info
230        self._inner_kits_info = _libs_info
231
232    def _parsing_system_kits(self, part_name, system_kits_info,
233                             build_gn_content):
234        system_kits_libs_gn = []
235        kits = []
236        for _kits_lib in system_kits_info:
237            system_kits_libs_gn.append('    {')
238            system_kits_libs_gn.extend(self._parsing_kits_lib(
239                _kits_lib, False))
240            kits.append('"{}"'.format(_kits_lib.get('name')))
241            system_kits_libs_gn.append('    },')
242        _kits_libs_gn_line = '\n'.join(system_kits_libs_gn)
243        system_kits_def = SYSTEM_KITS_TEMPLATE.format(part_name,
244                                                      _kits_libs_gn_line,
245                                                      self._origin_name,
246                                                      self._variant_name)
247        build_gn_content.append(system_kits_def)
248        self._kits = kits
249
250    def _parsing_config(self, part_name, part_config, subsystem_name):
251        self._part_target_list = []
252        build_gn_content = []
253        build_gn_content.append(IMPORT_LIST)
254
255        # ohos part
256        if 'module_list' not in part_config:
257            raise OHOSException(
258                "ohos.build incorrect, part name: '{}'".format(part_name), "2014")
259        module_list = part_config.get('module_list')
260        if len(module_list) == 0:
261            module_list_line = ''
262        else:
263            module_list_line = '"{}",'.format('",\n    "'.join(module_list))
264        parts_definition = PART_TEMPLATE.format(part_name, subsystem_name,
265                                                module_list_line,
266                                                self._origin_name,
267                                                self._variant_name)
268        build_gn_content.append(parts_definition)
269
270        # part inner kits
271        if part_config.get('inner_kits'):
272            self._part_target_list.append('inner_kits')
273            inner_kits_info = part_config.get('inner_kits')
274            self._parsing_inner_kits(part_name, inner_kits_info,
275                                     build_gn_content, self._target_arch)
276        # part system kits
277        if part_config.get('system_kits'):
278            self._part_target_list.append('system_kits')
279            system_kits_info = part_config.get('system_kits')
280            self._parsing_system_kits(part_name, system_kits_info,
281                                      build_gn_content)
282        # part test list
283        if part_config.get('test_list'):
284            self._part_target_list.append('test')
285            test_list = part_config.get('test_list')
286            test_list_line = '"{}",'.format('",\n    "'.join(test_list))
287            test_def = TEST_TEMPLATE.format(part_name, test_list_line,
288                                            subsystem_name)
289            build_gn_content.append(test_def)
290        self._build_gn_content = build_gn_content
291        # feature
292        if part_config.get('feature_list'):
293            self._feature_list = part_config.get('feature_list')
294            # check feature
295            for _feature_name in self._feature_list:
296                if not _feature_name.startswith('{}_'.format(
297                        self._origin_name)):
298                    raise OHOSException(
299                        "part feature list config incorrect,"
300                        " part_name='{}', feature_name='{}'".format(
301                            self._origin_name, _feature_name), "2014")
302
303        # system_capabilities is a list attribute of a part in ohos.build
304        if part_config.get('system_capabilities'):
305            self._system_capabilities = part_config.get('system_capabilities')
306
307    def part_name(self):
308        """part name."""
309        return self._part_name
310
311    def part_variant(self):
312        """part variant."""
313        return self._variant_name
314
315    def toolchain(self):
316        """current part variant toolchain."""
317        return self._toolchain
318
319    def part_inner_kits(self):
320        """part inner kits."""
321        return self._inner_kits_info
322
323    def part_kits(self):
324        """part kits."""
325        return self._kits
326
327    def write_build_gn(self, config_output_dir):
328        """output build gn."""
329        part_gn_file = os.path.join(config_output_dir, self._part_name,
330                                    'BUILD.gn')
331        write_file(part_gn_file, '\n'.join(self._build_gn_content))
332
333    def get_target_label(self, config_output_relpath):
334        """target label."""
335        if config_output_relpath.startswith('/'):
336            raise OHOSException(
337                "args config output relative path is incorrect.", "2003")
338        if self._toolchain == '':
339            return "//{0}/{1}:{1}".format(config_output_relpath,
340                                          self._part_name)
341        else:
342            return "//{0}/{1}:{1}({2})".format(config_output_relpath,
343                                               self._part_name,
344                                               self._toolchain)
345
346    def part_group_targets(self, config_output_relpath):
347        """part group target."""
348        if config_output_relpath.startswith('/'):
349            raise OHOSException(
350                "args config output relative path is incorrect.", "2003")
351        _labels = {}
352        _labels['part'] = self.get_target_label(config_output_relpath)
353        for group_label in self._part_target_list:
354            if group_label == 'phony':
355                _labels[group_label] = "//{0}/{1}:{1}_{2}".format(
356                    config_output_relpath, self._part_name, group_label)
357                continue
358            if self._toolchain == '':
359                _labels[group_label] = "//{0}/{1}:{1}_{2}".format(
360                    config_output_relpath, self._part_name, group_label)
361            else:
362                _labels[group_label] = "//{0}/{1}:{1}_{2}({3})".format(
363                    config_output_relpath, self._part_name, group_label,
364                    self._toolchain)
365        return _labels
366
367    def part_info(self):
368        """part info."""
369        _info = {}
370        _info['part_name'] = self._part_name
371        _info['origin_part_name'] = self._origin_name
372        _info['toolchain_label'] = self._toolchain
373        _info['variant_name'] = self._variant_name
374        _info['subsystem_name'] = self._subsystem_name
375        _info['system_capabilities'] = self._system_capabilities
376
377        if self._feature_list:
378            _info['feature_list'] = self._feature_list
379        if self._variant_name != 'phone':
380            toolchain_name = self._toolchain.split(':')[1]
381            _build_out_dir = toolchain_name
382        else:
383            _build_out_dir = '.'
384        _info['build_out_dir'] = _build_out_dir
385        return _info
386
387
388class LoadBuildConfig(object):
389    """load build config file and parse configuration info."""
390
391    def __init__(self, source_root_dir, subsystem_build_info,
392                 config_output_dir, variant_toolchains, subsystem_name,
393                 target_arch, ignored_subsystems, exclusion_modules_config_file,
394                 load_test_config, overrided_components, bundle_subsystem_allow_list):
395        self._source_root_dir = source_root_dir
396        self._build_info = subsystem_build_info
397        self._config_output_relpath = config_output_dir
398        self._is_load = False
399        self._parts_variants = {}
400        self._part_list = {}
401        self._part_targets_label = {}
402        self._variant_toolchains = variant_toolchains
403        self._subsystem_name = subsystem_name
404        self._target_arch = target_arch
405        self._ignored_subsystems = ignored_subsystems
406        self._parts_info_dict = {}
407        self._phony_targets = {}
408        self._parts_path_dict = {}
409        self._part_hisysevent_config = {}
410        self._parts_module_list = {}
411        self._parts_deps = {}
412        self._exclusion_modules_config_file = exclusion_modules_config_file
413        self._load_test_config = load_test_config
414        self._overrided_components = overrided_components
415        self._bundle_subsystem_allow_list = bundle_subsystem_allow_list
416
417    @throw_exception
418    def _parsing_config(self, parts_config):
419        _parts_info_dict = {}
420        _parts_deps = {}
421        _variant_phony_targets = {}
422        for part_name, value in parts_config.items():
423            if 'variants' in value:
424                variants = value.get('variants')
425                if len(variants) == 0:
426                    variants = ['phone']
427            else:
428                variants = ['phone']
429            _build_target = {}
430            _targets_label = {}
431            _parts_info = []
432            for variant in variants:
433                toolchain = self._variant_toolchains.get(variant)
434                if toolchain is None:
435                    continue
436                part_obj = PartObject(part_name, variant, value, toolchain,
437                                      self._subsystem_name, self._target_arch, self._overrided_components)
438                real_part_name = part_obj.part_name()
439                self._part_list[real_part_name] = part_obj
440
441                subsystem_config_dir = os.path.join(
442                    self._config_output_relpath, self._subsystem_name)
443                part_obj.write_build_gn(
444                    os.path.join(self._source_root_dir, subsystem_config_dir))
445
446                _target_label = part_obj.get_target_label(subsystem_config_dir)
447                _build_target[variant] = _target_label
448                _targets_label[real_part_name] = part_obj.part_group_targets(
449                    subsystem_config_dir)
450                _parts_info.append(part_obj.part_info())
451                if variant != 'phone':
452                    _variant_phony_targets[real_part_name] = _target_label
453            self._part_targets_label.update(_targets_label)
454            self._parts_variants[part_name] = _build_target
455            if 'hisysevent_config' in value:
456                _config_files = value.get('hisysevent_config')
457                for _config_file in _config_files:
458                    if not _config_file.startswith('//'):
459                        raise OHOSException(
460                            "part '{}' hisysevent config incorrest.".format(
461                                part_name), "2014")
462                self._part_hisysevent_config[part_name] = _config_files
463            _parts_info_dict[part_name] = _parts_info
464            _parts_deps[part_name] = value.get('part_deps')
465        self._parts_info_dict = _parts_info_dict
466        self._phony_targets = _variant_phony_targets
467        self._parts_deps = _parts_deps
468
469    def _merge_build_config(self):
470        _build_files = self._build_info.get('build_files')
471        is_thirdparty_subsystem = False
472        if _build_files[0].startswith(self._source_root_dir + 'third_party'):
473            is_thirdparty_subsystem = True
474        subsystem_name = None
475        parts_info = {}
476        parts_path_dict = {}
477        for _build_file in _build_files:
478            if _build_file.endswith('bundle.json'):
479                bundle_part_obj = load_bundle_file.BundlePartObj(
480                    _build_file, self._exclusion_modules_config_file,
481                    self._load_test_config)
482                _parts_config = bundle_part_obj.to_ohos_build()
483            else:
484                _parts_config = read_build_file(_build_file)
485
486            _subsystem_name = _parts_config.get('subsystem')
487            if not is_thirdparty_subsystem and subsystem_name and _subsystem_name != subsystem_name:
488                raise OHOSException(
489                    "subsystem name config incorrect in '{}'.".format(
490                        _build_file), "2014")
491            if _subsystem_name != self._subsystem_name:
492                is_allow = False
493                for file_path in self._bundle_subsystem_allow_list:
494                    if _build_file.endswith(file_path):
495                        is_allow = True
496                        break
497                if is_allow:
498                    print("warning: subsystem name config incorrect in '{}', build file subsystem name is {},"
499                        "configured subsystem name is {}.".format(
500                        _build_file, _subsystem_name, self._subsystem_name))
501                else:
502                    raise OHOSException("subsystem name config incorrect in '{}', build file subsystem name is {},"
503                        "configured subsystem name is {}.".format(
504                        _build_file, _subsystem_name, self._subsystem_name), 2014)
505
506            subsystem_name = _subsystem_name
507            _curr_parts_info = _parts_config.get('parts')
508            for _pname in _curr_parts_info.keys():
509                parts_path_dict[_pname] = os.path.relpath(
510                    os.path.dirname(_build_file), self._source_root_dir)
511            parts_info.update(_curr_parts_info)
512        subsystem_config = {}
513        subsystem_config['subsystem'] = subsystem_name
514        subsystem_config['parts'] = parts_info
515        return subsystem_config, parts_path_dict
516
517    def parse_syscap_info(self):
518        _build_files = self._build_info.get('build_files')
519        subsystem_syscap = []
520        for _build_file in _build_files:
521            if _build_file.endswith('bundle.json'):
522                part_name, part_syscap = get_syscap_from_bundle(_build_file)
523                subsystem_syscap.append(
524                    {'component': part_name, 'syscap': part_syscap})
525        return subsystem_syscap
526
527    def parse(self):
528        """parse part info from build config file."""
529        if self._is_load:
530            return
531        subsystem_config, parts_path_dict = self._merge_build_config()
532        parts_config = subsystem_config.get('parts')
533        self._parts_module_list.update(parts_config)
534        self._parsing_config(parts_config)
535        self._parts_path_dict = parts_path_dict
536        self._is_load = True
537
538    def parts_variants(self):
539        """parts varinats info."""
540        self.parse()
541        return self._parts_variants
542
543    def parts_inner_kits_info(self):
544        """parts inner kits info."""
545        self.parse()
546        _parts_inner_kits = {}
547        for part_obj in self._part_list.values():
548            _parts_inner_kits[
549                part_obj.part_name()] = part_obj.part_inner_kits()
550        return _parts_inner_kits
551
552    def parts_build_targets(self):
553        """parts build target label."""
554        self.parse()
555        return self._part_targets_label
556
557    def parts_name_list(self):
558        """parts name list."""
559        self.parse()
560        return list(self._part_list.keys())
561
562    def parts_info(self):
563        """parts info."""
564        self.parse()
565        return self._parts_info_dict
566
567    def parts_phony_target(self):
568        """parts phony target info"""
569        self.parse()
570        return self._phony_targets
571
572    def parts_kits_info(self):
573        """parts kits info."""
574        self.parse()
575        _parts_kits = {}
576        for part_obj in self._part_list.values():
577            _parts_kits[part_obj.part_name()] = part_obj.part_kits()
578        return _parts_kits
579
580    def parts_path_info(self):
581        """parts to path info."""
582        self.parse()
583        return self._parts_path_dict
584
585    def parts_hisysevent_config(self):
586        self.parse()
587        return self._part_hisysevent_config
588
589    def parts_modules_info(self):
590        self.parse()
591        return self._parts_module_list
592
593    def parts_deps(self):
594        self.parse()
595        return self._parts_deps
596
597    def parts_info_filter(self, save_part):
598        if save_part is None:
599            raise Exception
600        self._parts_variants = {
601            key: value for key, value in self._parts_variants.items() if key in save_part}
602        self._part_list = {
603            key: value for key, value in self._part_list.items() if key in save_part}
604        self._part_targets_label = {
605            key: value for key, value in self._part_targets_label.items() if key in save_part}
606        self._parts_info_dict = {
607            key: value for key, value in self._parts_info_dict.items() if key in save_part}
608        self._phony_targets = {
609            key: value for key, value in self._phony_targets.items() if key in save_part}
610        self._parts_path_dict = {
611            key: value for key, value in self._parts_path_dict.items() if key in save_part}
612        self._part_hisysevent_config = {
613            key: value for key, value in self._part_hisysevent_config.items() if key in save_part}
614        self._parts_module_list = {
615            key: value for key, value in self._parts_module_list.items() if key in save_part}
616        self._parts_deps = {
617            key: value for key, value in self._parts_deps.items() if key in save_part}
618
619
620def compare_subsystem_and_component(subsystem_name, components_name, subsystem_compoents_whitelist_info,
621                                    part_subsystem_component_info, parts_config_path, subsystem_components_list):
622    name = ""
623    message = ""
624    if components_name in list(subsystem_compoents_whitelist_info.keys()):
625        return
626    overrided_components_name = '{}_{}'.format(components_name, 'override')
627    if components_name in list(part_subsystem_component_info.keys()) \
628        or overrided_components_name in list(part_subsystem_component_info.keys()):
629        if subsystem_name in list(part_subsystem_component_info.values()):
630            return
631        if subsystem_name == components_name:
632            return
633        name = subsystem_name
634        message = "find subsystem {} failed, please check it in {}.".format(subsystem_name, parts_config_path)
635    else:
636        name = components_name
637        message = "find component {} failed, please check it in {}.".format(components_name, parts_config_path)
638    if name in subsystem_components_list:
639        print(f"Warning: {message}")
640    else:
641        raise Exception(message)
642
643
644def check_subsystem_and_component(parts_info_output_path, skip_partlist_check):
645    config = Config()
646    parts_config_path = os.path.join(config.root_path, "out/preloader", config.product,
647                                     "parts.json")
648    part_subsystem_file = os.path.join(parts_info_output_path,
649                                       "part_subsystem.json")
650    part_subsystem_component_info = read_json_file(part_subsystem_file)
651
652    subsystem_compoents_whitelist_file = os.path.join(config.root_path,
653                                                      "build/subsystem_compoents_whitelist.json")
654    subsystem_compoents_whitelist_info = read_json_file(subsystem_compoents_whitelist_file)
655
656    compile_standard_whitelist_file = os.path.join(config.root_path, "out/preloader", config.product,
657                                                   "compile_standard_whitelist.json")
658    compile_standard_whitelist_info = read_json_file(compile_standard_whitelist_file)
659    subsystem_components_list = compile_standard_whitelist_info.get("subsystem_components", [])
660
661    if os.path.isfile(parts_config_path):
662        parts_config_info = read_json_file(parts_config_path)
663        parts_info = parts_config_info.get("parts")
664
665        for subsystem_part in parts_info:
666            subsystem_part_list = subsystem_part.split(':')
667            subsystem_name = subsystem_part_list[0]
668            components_name = subsystem_part_list[1]
669
670            if subsystem_name is None or components_name is None:
671                print("Warning: subsystem_name or components_name is empty, please check it in {}.".format(parts_config_path))
672                continue
673            if not skip_partlist_check:
674                compare_subsystem_and_component(subsystem_name, components_name, subsystem_compoents_whitelist_info,
675                                                part_subsystem_component_info, parts_config_path, subsystem_components_list)
676
677def _output_all_components_info(parts_config_dict, parts_info_output_path):
678    if 'parts_inner_kits_info' not in parts_config_dict:
679        return
680    parts_inner_kits_info = parts_config_dict.get('parts_inner_kits_info')
681    if 'parts_info' not in parts_config_dict:
682        return
683    parts_info = parts_config_dict.get('parts_info')
684    if 'parts_path_info' not in parts_config_dict:
685        return
686    parts_path_info = parts_config_dict.get('parts_path_info')
687
688    components = {}
689
690    for name, val in parts_inner_kits_info.items():
691        component = {}
692        component["innerapis"] = []
693        component["variants"] = []
694        if name in parts_path_info:
695            component["path"] = parts_path_info[name]
696        else:
697            print("Warning: component %s has no path info." % name)
698
699        if name in parts_info:
700            for item in parts_info[name]:
701                component["subsystem"] = item.get("subsystem_name")
702                break
703        else:
704            print("Warning: component %s has no subsystem info." % name)
705
706        if val:
707            for k, v in val.items():
708                innerapi = {"name": k, "label": v["label"]}
709                if "visibility" in v:
710                    innerapi["visibility"] = v["visibility"]
711                component["innerapis"].append(innerapi)
712
713        components[name] = component
714
715    _component_file = os.path.join(parts_info_output_path,
716                                        "components.json")
717    write_json_file(_component_file, components)
718
719def _output_parts_info(parts_config_dict,
720                       config_output_path, skip_partlist_check):
721    parts_info_output_path = os.path.join(config_output_path, "parts_info")
722    # parts_info.json
723    if 'parts_info' in parts_config_dict:
724        parts_info = parts_config_dict.get('parts_info')
725        parts_info_file = os.path.join(parts_info_output_path,
726                                       "parts_info.json")
727        write_json_file(parts_info_file, parts_info)
728        LogUtil.hb_info("generate parts info to '{}'".format(parts_info_file), mode=Config.log_mode)
729        _part_subsystem_dict = {}
730        for key, value in parts_info.items():
731            for _info in value:
732                _sub_name = _info.get('subsystem_name')
733                _part_subsystem_dict[key] = _sub_name
734                break
735        _part_subsystem_file = os.path.join(parts_info_output_path,
736                                            "part_subsystem.json")
737        write_json_file(_part_subsystem_file, _part_subsystem_dict)
738        LogUtil.hb_info(
739            "generate part-subsystem of parts-info to '{}'".format(
740                _part_subsystem_file), mode=Config.log_mode)
741
742    check_subsystem_and_component(parts_info_output_path, skip_partlist_check)
743
744    # subsystem_parts.json
745    if 'subsystem_parts' in parts_config_dict:
746        subsystem_parts = parts_config_dict.get('subsystem_parts')
747        subsystem_parts_file = os.path.join(parts_info_output_path,
748                                            "subsystem_parts.json")
749        write_json_file(subsystem_parts_file, subsystem_parts)
750        LogUtil.hb_info(
751            "generate ubsystem-parts of parts-info to '{}'".format(
752                subsystem_parts_file), mode=Config.log_mode)
753
754        # adapter mini system
755        for _sub_name, _p_list in subsystem_parts.items():
756            _output_info = {}
757            _output_info['parts'] = _p_list
758            _sub_info_output_file = os.path.join(config_output_path,
759                                                 'mini_adapter',
760                                                 '{}.json'.format(_sub_name))
761            write_json_file(_sub_info_output_file, _output_info)
762        LogUtil.hb_info(
763            "generate mini adapter info to '{}/mini_adapter/'".format(
764                config_output_path), mode=Config.log_mode)
765
766    # parts_variants.json
767    if 'parts_variants' in parts_config_dict:
768        parts_variants = parts_config_dict.get('parts_variants')
769        parts_variants_info_file = os.path.join(parts_info_output_path,
770                                                "parts_variants.json")
771        write_json_file(parts_variants_info_file, parts_variants)
772        LogUtil.hb_info("generate parts variants info to '{}'".format(
773            parts_variants_info_file), mode=Config.log_mode)
774
775    # inner_kits_info.json
776    if 'parts_inner_kits_info' in parts_config_dict:
777        parts_inner_kits_info = parts_config_dict.get('parts_inner_kits_info')
778        parts_inner_kits_info_file = os.path.join(parts_info_output_path,
779                                                  "inner_kits_info.json")
780        write_json_file(parts_inner_kits_info_file, parts_inner_kits_info)
781        LogUtil.hb_info("generate parts inner kits info to '{}'".format(
782            parts_inner_kits_info_file), mode=Config.log_mode)
783
784    # parts_targets.json
785    if 'parts_targets' in parts_config_dict:
786        parts_targets = parts_config_dict.get('parts_targets')
787        parts_targets_info_file = os.path.join(parts_info_output_path,
788                                               "parts_targets.json")
789        write_json_file(parts_targets_info_file, parts_targets)
790        LogUtil.hb_info("generate parts targets info to '{}'".format(
791            parts_targets_info_file), mode=Config.log_mode)
792
793    # phony_targets.json
794    if 'phony_target' in parts_config_dict:
795        phony_target = parts_config_dict.get('phony_target')
796        phony_target_info_file = os.path.join(parts_info_output_path,
797                                              "phony_target.json")
798        write_json_file(phony_target_info_file, phony_target)
799        LogUtil.hb_info("generate phony targets info to '{}'".format(
800            phony_target_info_file), mode=Config.log_mode)
801
802    # paths_path_info.json
803    if 'parts_path_info' in parts_config_dict:
804        parts_path_info = parts_config_dict.get('parts_path_info')
805        parts_path_info_file = os.path.join(parts_info_output_path,
806                                            'parts_path_info.json')
807        write_json_file(parts_path_info_file, parts_path_info)
808        LogUtil.hb_info(
809            "generate parts path info to '{}'".format(parts_path_info_file), mode=Config.log_mode)
810        path_to_parts = {}
811        for _key, _val in parts_path_info.items():
812            _p_list = path_to_parts.get(_val, [])
813            _p_list.append(_key)
814            path_to_parts[_val] = _p_list
815        path_to_parts_file = os.path.join(parts_info_output_path,
816                                          'path_to_parts.json')
817        write_json_file(path_to_parts_file, path_to_parts)
818        LogUtil.hb_info(
819            "generate path to parts to '{}'".format(path_to_parts_file), mode=Config.log_mode)
820
821    # hisysevent_config
822    if 'hisysevent_config' in parts_config_dict:
823        hisysevent_config = parts_config_dict.get('hisysevent_config')
824        hisysevent_info_file = os.path.join(parts_info_output_path,
825                                            'hisysevent_configs.json')
826        write_json_file(hisysevent_info_file, hisysevent_config)
827        LogUtil.hb_info(
828            "generate hisysevent info to '{}'".format(hisysevent_info_file), mode=Config.log_mode)
829
830    # _parts_modules_info
831    if 'parts_modules_info' in parts_config_dict:
832        parts_modules_info = parts_config_dict.get('parts_modules_info')
833        _output_info = {}
834        _all_p_info = []
835        for key, value in parts_modules_info.items():
836            _p_info = {}
837            _p_info['part_name'] = key
838            _module_list = value.get('module_list')
839            _p_info['module_list'] = _module_list
840            _all_p_info.append(_p_info)
841        _output_info['parts'] = _all_p_info
842        parts_modules_info_file = os.path.join(parts_info_output_path,
843                                               'parts_modules_info.json')
844        write_json_file(parts_modules_info_file, _output_info)
845        LogUtil.hb_info("generate parts modules info to '{}'".format(
846            parts_modules_info_file), mode=Config.log_mode)
847
848    # parts_deps
849    if 'parts_deps' in parts_config_dict:
850        parts_deps_info = parts_config_dict.get('parts_deps')
851        parts_deps_info_file = os.path.join(parts_info_output_path,
852                                            'parts_deps.json')
853        write_json_file(parts_deps_info_file, parts_deps_info)
854        LogUtil.hb_info(
855            "generate parts deps info to '{}'".format(parts_deps_info_file), mode=Config.log_mode)
856
857    _output_all_components_info(parts_config_dict, parts_info_output_path)
858
859def get_parts_info(source_root_dir,
860                   config_output_relpath,
861                   subsystem_info,
862                   variant_toolchains,
863                   target_arch,
864                   ignored_subsystems,
865                   exclusion_modules_config_file,
866                   load_test_config,
867                   overrided_components,
868                   bundle_subsystem_allow_list,
869                   skip_partlist_check,
870                   build_xts=False):
871    """parts info,
872    get info from build config file.
873    """
874    parts_variants = {}
875    parts_inner_kits_info = {}
876    parts_kits_info = {}
877    parts_targets = {}
878    parts_info = {}
879    subsystem_parts = {}
880    _phony_target = {}
881    _parts_path_info = {}
882    _parts_hisysevent_config = {}
883    _parts_modules_info = {}
884    _parts_deps = {}
885    system_syscap = []
886    for subsystem_name, build_config_info in subsystem_info.items():
887        if not len(build_config_info.get("build_files")):
888            continue
889        build_loader = LoadBuildConfig(source_root_dir, build_config_info,
890                                       config_output_relpath,
891                                       variant_toolchains, subsystem_name,
892                                       target_arch, ignored_subsystems,
893                                       exclusion_modules_config_file,
894                                       load_test_config, overrided_components,
895                                       bundle_subsystem_allow_list)
896        # xts subsystem special handling, device_attest and
897        # device_attest_lite parts need to be compiled into the version image, other parts are not.
898        # parts_modules_info needs to be parse before filting.
899        if subsystem_name == 'xts' and build_xts is False:
900            xts_device_attest_name = ['device_attest_lite', 'device_attest']
901            build_loader.parse()
902            build_loader.parts_info_filter(xts_device_attest_name)
903        _parts_variants = build_loader.parts_variants()
904        parts_variants.update(_parts_variants)
905        _inner_kits_info = build_loader.parts_inner_kits_info()
906        parts_inner_kits_info.update(_inner_kits_info)
907        parts_kits_info.update(build_loader.parts_kits_info())
908        _parts_targets = build_loader.parts_build_targets()
909        parts_targets.update(_parts_targets)
910        subsystem_parts[subsystem_name] = build_loader.parts_name_list()
911        parts_info.update(build_loader.parts_info())
912        _phony_target.update(build_loader.parts_phony_target())
913        _parts_path_info.update(build_loader.parts_path_info())
914        _parts_hisysevent_config.update(build_loader.parts_hisysevent_config())
915        _parts_modules_info.update(build_loader.parts_modules_info())
916        _parts_deps.update(build_loader.parts_deps())
917        system_syscap.extend(build_loader.parse_syscap_info())
918    LogUtil.hb_info(
919        "generate all parts build gn file to '{}/{}'".format(
920            source_root_dir, config_output_relpath), mode=Config.log_mode)
921    parts_config_dict = {}
922    parts_config_dict['parts_info'] = parts_info
923    parts_config_dict['subsystem_parts'] = subsystem_parts
924    parts_config_dict['parts_variants'] = parts_variants
925    parts_config_dict['parts_inner_kits_info'] = parts_inner_kits_info
926    parts_config_dict['parts_kits_info'] = parts_kits_info
927    parts_config_dict['parts_targets'] = parts_targets
928    parts_config_dict['phony_target'] = _phony_target
929    parts_config_dict['parts_path_info'] = _parts_path_info
930    parts_config_dict['hisysevent_config'] = _parts_hisysevent_config
931    parts_config_dict['parts_modules_info'] = _parts_modules_info
932    parts_config_dict['parts_deps'] = _parts_deps
933    _output_parts_info(parts_config_dict,
934                       os.path.join(source_root_dir, config_output_relpath), skip_partlist_check)
935    parts_config_dict['syscap_info'] = system_syscap
936    LogUtil.hb_info('all parts scan completed')
937    return parts_config_dict
938