• 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 = "{0}"
50  origin_name = "{2}"
51  variant = "{3}"
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):
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._parsing_config(self._part_name, part_config, subsystem_name)
127
128    @classmethod
129    def _parsing_kits_lib(cls, kit_lib, is_inner_kits=False):
130        lib_config = []
131        lib_type = kit_lib.get('type')
132        if lib_type is None:
133            lib_type = 'so' if is_inner_kits else 'jar'
134        label = kit_lib.get('name')
135        if label is None:
136            raise Exception("kits lib config incorrect, required for name.")
137        lib_config.append('      type = "{}"'.format(lib_type))
138        lib_config.append('      name = "{}"'.format(label))
139        if lib_type == 'so' and 'header' in kit_lib:
140            header = kit_lib.get('header')
141            header_files = header.get('header_files')
142            lib_config.append('      header = {')
143            lib_config.append('        header_files = [')
144            for h_file in header_files:
145                lib_config.append('          "{}",'.format(h_file))
146            lib_config.append('        ]')
147            header_base = header.get('header_base')
148            lib_config.append('        header_base = "{}"'.format(header_base))
149            lib_config.append('      }')
150        if is_inner_kits is False and 'javadoc' in kit_lib:
151            javadoc_val = kit_lib.get('javadoc')
152            lib_config.append('      javadoc = {')
153            resource_dir = javadoc_val.get('resource_dir')
154            lib_config.append(
155                '        resource_dir = "{}"'.format(resource_dir))
156            lib_config.append('      }')
157        return lib_config
158
159    @throw_exception
160    def _parsing_inner_kits(self, part_name, inner_kits_info, build_gn_content,
161                            target_arch):
162        inner_kits_libs_gn = []
163        for inner_kits_lib in inner_kits_info:
164            inner_kits_libs_gn.append('    {')
165            inner_kits_libs_gn.extend(
166                self._parsing_kits_lib(inner_kits_lib, True))
167            inner_kits_libs_gn.append('    },')
168
169        inner_kits_libs_gn_line = '\n'.join(inner_kits_libs_gn)
170        inner_kits_def = INNER_KITS_TEMPLATE.format(part_name,
171                                                    inner_kits_libs_gn_line,
172                                                    self._origin_name,
173                                                    self._variant_name)
174        build_gn_content.append(inner_kits_def)
175        # output inner kits info to resolve external deps
176        _libs_info = {}
177        for inner_kits_lib in inner_kits_info:
178            info = {'part_name': part_name}
179            label = inner_kits_lib.get('name')
180            lib_name = label.split(':')[1]
181            info['label'] = label
182            info['name'] = lib_name
183            lib_type = inner_kits_lib.get('type')
184            if lib_type is None:
185                lib_type = 'so'
186            info['type'] = lib_type
187            prebuilt = inner_kits_lib.get('prebuilt_enable')
188            if prebuilt:
189                info['prebuilt_enable'] = prebuilt
190                prebuilt_source_libs = inner_kits_lib.get('prebuilt_source')
191                prebuilt_source = prebuilt_source_libs.get(target_arch)
192                info['prebuilt_source'] = prebuilt_source
193            else:
194                info['prebuilt_enable'] = False
195            # header files
196            if lib_type == 'so':
197                header = inner_kits_lib.get('header')
198                if header is None:
199                    raise OHOSException(
200                        "header not configuration, part_name = '{}'".format(
201                            part_name), "2014")
202                header_base = header.get('header_base')
203                if header_base is None:
204                    raise OHOSException(
205                        "header base not configuration, part_name = '{}'".
206                        format(part_name), "2014")
207                info['header_base'] = header_base
208                info['header_files'] = header.get('header_files')
209            _libs_info[lib_name] = info
210        self._inner_kits_info = _libs_info
211
212    def _parsing_system_kits(self, part_name, system_kits_info,
213                             build_gn_content):
214        system_kits_libs_gn = []
215        kits = []
216        for _kits_lib in system_kits_info:
217            system_kits_libs_gn.append('    {')
218            system_kits_libs_gn.extend(self._parsing_kits_lib(
219                _kits_lib, False))
220            kits.append('"{}"'.format(_kits_lib.get('name')))
221            system_kits_libs_gn.append('    },')
222        _kits_libs_gn_line = '\n'.join(system_kits_libs_gn)
223        system_kits_def = SYSTEM_KITS_TEMPLATE.format(part_name,
224                                                      _kits_libs_gn_line,
225                                                      self._origin_name,
226                                                      self._variant_name)
227        build_gn_content.append(system_kits_def)
228        self._kits = kits
229
230    def _parsing_config(self, part_name, part_config, subsystem_name):
231        self._part_target_list = []
232        build_gn_content = []
233        build_gn_content.append(IMPORT_LIST)
234
235        # ohos part
236        if 'module_list' not in part_config:
237            raise OHOSException(
238                "ohos.build incorrect, part name: '{}'".format(part_name), "2014")
239        module_list = part_config.get('module_list')
240        if len(module_list) == 0:
241            module_list_line = ''
242        else:
243            module_list_line = '"{}",'.format('",\n    "'.join(module_list))
244        parts_definition = PART_TEMPLATE.format(part_name, subsystem_name,
245                                                module_list_line,
246                                                self._origin_name,
247                                                self._variant_name)
248        build_gn_content.append(parts_definition)
249
250        # part inner kits
251        if part_config.get('inner_kits'):
252            self._part_target_list.append('inner_kits')
253            inner_kits_info = part_config.get('inner_kits')
254            self._parsing_inner_kits(part_name, inner_kits_info,
255                                     build_gn_content, self._target_arch)
256        # part system kits
257        if part_config.get('system_kits'):
258            self._part_target_list.append('system_kits')
259            system_kits_info = part_config.get('system_kits')
260            self._parsing_system_kits(part_name, system_kits_info,
261                                      build_gn_content)
262        # part test list
263        if part_config.get('test_list'):
264            self._part_target_list.append('test')
265            test_list = part_config.get('test_list')
266            test_list_line = '"{}",'.format('",\n    "'.join(test_list))
267            test_def = TEST_TEMPLATE.format(part_name, test_list_line,
268                                            subsystem_name)
269            build_gn_content.append(test_def)
270        self._build_gn_content = build_gn_content
271        # feature
272        if part_config.get('feature_list'):
273            self._feature_list = part_config.get('feature_list')
274            # check feature
275            for _feature_name in self._feature_list:
276                if not _feature_name.startswith('{}_'.format(
277                        self._origin_name)):
278                    raise OHOSException(
279                        "part feature list config incorrect,"
280                        " part_name='{}', feature_name='{}'".format(
281                            self._origin_name, _feature_name), "2014")
282
283        # system_capabilities is a list attribute of a part in ohos.build
284        if part_config.get('system_capabilities'):
285            self._system_capabilities = part_config.get('system_capabilities')
286
287    def part_name(self):
288        """part name."""
289        return self._part_name
290
291    def part_variant(self):
292        """part variant."""
293        return self._variant_name
294
295    def toolchain(self):
296        """current part variant toolchain."""
297        return self._toolchain
298
299    def part_inner_kits(self):
300        """part inner kits."""
301        return self._inner_kits_info
302
303    def part_kits(self):
304        """part kits."""
305        return self._kits
306
307    def write_build_gn(self, config_output_dir):
308        """output build gn."""
309        part_gn_file = os.path.join(config_output_dir, self._part_name,
310                                    'BUILD.gn')
311        write_file(part_gn_file, '\n'.join(self._build_gn_content))
312
313    def get_target_label(self, config_output_relpath):
314        """target label."""
315        if config_output_relpath.startswith('/'):
316            raise OHOSException(
317                "args config output relative path is incorrect.", "2003")
318        if self._toolchain == '':
319            return "//{0}/{1}:{1}".format(config_output_relpath,
320                                          self._part_name)
321        else:
322            return "//{0}/{1}:{1}({2})".format(config_output_relpath,
323                                               self._part_name,
324                                               self._toolchain)
325
326    def part_group_targets(self, config_output_relpath):
327        """part group target."""
328        if config_output_relpath.startswith('/'):
329            raise OHOSException(
330                "args config output relative path is incorrect.", "2003")
331        _labels = {}
332        _labels['part'] = self.get_target_label(config_output_relpath)
333        for group_label in self._part_target_list:
334            if group_label == 'phony':
335                _labels[group_label] = "//{0}/{1}:{1}_{2}".format(
336                    config_output_relpath, self._part_name, group_label)
337                continue
338            if self._toolchain == '':
339                _labels[group_label] = "//{0}/{1}:{1}_{2}".format(
340                    config_output_relpath, self._part_name, group_label)
341            else:
342                _labels[group_label] = "//{0}/{1}:{1}_{2}({3})".format(
343                    config_output_relpath, self._part_name, group_label,
344                    self._toolchain)
345        return _labels
346
347    def part_info(self):
348        """part info."""
349        _info = {}
350        _info['part_name'] = self._part_name
351        _info['origin_part_name'] = self._origin_name
352        _info['toolchain_label'] = self._toolchain
353        _info['variant_name'] = self._variant_name
354        _info['subsystem_name'] = self._subsystem_name
355        _info['system_capabilities'] = self._system_capabilities
356
357        if self._feature_list:
358            _info['feature_list'] = self._feature_list
359        if self._variant_name != 'phone':
360            toolchain_name = self._toolchain.split(':')[1]
361            _build_out_dir = toolchain_name
362        else:
363            _build_out_dir = '.'
364        _info['build_out_dir'] = _build_out_dir
365        return _info
366
367
368class LoadBuildConfig(object):
369    """load build config file and parse configuration info."""
370
371    def __init__(self, source_root_dir, subsystem_build_info,
372                 config_output_dir, variant_toolchains, subsystem_name,
373                 target_arch, ignored_subsystems, exclusion_modules_config_file,
374                 load_test_config, overrided_components, bundle_subsystem_allow_list):
375        self._source_root_dir = source_root_dir
376        self._build_info = subsystem_build_info
377        self._config_output_relpath = config_output_dir
378        self._is_load = False
379        self._parts_variants = {}
380        self._part_list = {}
381        self._part_targets_label = {}
382        self._variant_toolchains = variant_toolchains
383        self._subsystem_name = subsystem_name
384        self._target_arch = target_arch
385        self._ignored_subsystems = ignored_subsystems
386        self._parts_info_dict = {}
387        self._phony_targets = {}
388        self._parts_path_dict = {}
389        self._part_hisysevent_config = {}
390        self._parts_module_list = {}
391        self._parts_deps = {}
392        self._exclusion_modules_config_file = exclusion_modules_config_file
393        self._load_test_config = load_test_config
394        self._overrided_components = overrided_components
395        self._bundle_subsystem_allow_list = bundle_subsystem_allow_list
396
397    @throw_exception
398    def _parsing_config(self, parts_config):
399        _parts_info_dict = {}
400        _parts_deps = {}
401        _variant_phony_targets = {}
402        for part_name, value in parts_config.items():
403            if 'variants' in value:
404                variants = value.get('variants')
405                if len(variants) == 0:
406                    variants = ['phone']
407            else:
408                variants = ['phone']
409            _build_target = {}
410            _targets_label = {}
411            _parts_info = []
412            for variant in variants:
413                toolchain = self._variant_toolchains.get(variant)
414                if toolchain is None:
415                    continue
416                part_obj = PartObject(part_name, variant, value, toolchain,
417                                      self._subsystem_name, self._target_arch)
418                real_part_name = part_obj.part_name()
419                self._part_list[real_part_name] = part_obj
420
421                subsystem_config_dir = os.path.join(
422                    self._config_output_relpath, self._subsystem_name)
423                part_obj.write_build_gn(
424                    os.path.join(self._source_root_dir, subsystem_config_dir))
425
426                _target_label = part_obj.get_target_label(subsystem_config_dir)
427                _build_target[variant] = _target_label
428                _targets_label[real_part_name] = part_obj.part_group_targets(
429                    subsystem_config_dir)
430                _parts_info.append(part_obj.part_info())
431                if variant != 'phone':
432                    _variant_phony_targets[real_part_name] = _target_label
433            self._part_targets_label.update(_targets_label)
434            self._parts_variants[part_name] = _build_target
435            if 'hisysevent_config' in value:
436                _config_files = value.get('hisysevent_config')
437                for _config_file in _config_files:
438                    if not _config_file.startswith('//'):
439                        raise OHOSException(
440                            "part '{}' hisysevent config incorrest.".format(
441                                part_name), "2014")
442                self._part_hisysevent_config[part_name] = _config_files
443            _parts_info_dict[part_name] = _parts_info
444            _parts_deps[part_name] = value.get('part_deps')
445        self._parts_info_dict = _parts_info_dict
446        self._phony_targets = _variant_phony_targets
447        self._parts_deps = _parts_deps
448
449    def _merge_build_config(self):
450        _build_files = self._build_info.get('build_files')
451        is_thirdparty_subsystem = False
452        if _build_files[0].startswith(self._source_root_dir + 'third_party'):
453            is_thirdparty_subsystem = True
454        subsystem_name = None
455        parts_info = {}
456        parts_path_dict = {}
457        for _build_file in _build_files:
458            if _build_file.endswith('bundle.json'):
459                bundle_part_obj = load_bundle_file.BundlePartObj(
460                    _build_file, self._exclusion_modules_config_file,
461                    self._load_test_config)
462                _parts_config = bundle_part_obj.to_ohos_build()
463            else:
464                _parts_config = read_build_file(_build_file)
465
466            _subsystem_name = _parts_config.get('subsystem')
467            if not is_thirdparty_subsystem and subsystem_name and _subsystem_name != subsystem_name:
468                raise OHOSException(
469                    "subsystem name config incorrect in '{}'.".format(
470                        _build_file), "2014")
471            if _subsystem_name != self._subsystem_name:
472                is_allow = False
473                for file_path in self._bundle_subsystem_allow_list:
474                    if _build_file.endswith(file_path):
475                        is_allow = True
476                        break
477                if is_allow:
478                    print("warning: subsystem name config incorrect in '{}', build file subsystem name is {},"
479                        "configured subsystem name is {}.".format(
480                        _build_file, _subsystem_name, self._subsystem_name))
481                else:
482                    raise OHOSException("subsystem name config incorrect in '{}', build file subsystem name is {},"
483                        "configured subsystem name is {}.".format(
484                        _build_file, _subsystem_name, self._subsystem_name), 2014)
485
486            subsystem_name = _subsystem_name
487            _curr_parts_info = _parts_config.get('parts')
488            for _pname in _curr_parts_info.keys():
489                parts_path_dict[_pname] = os.path.relpath(
490                    os.path.dirname(_build_file), self._source_root_dir)
491            parts_info.update(_curr_parts_info)
492        subsystem_config = {}
493        subsystem_config['subsystem'] = subsystem_name
494        subsystem_config['parts'] = parts_info
495        return subsystem_config, parts_path_dict
496
497    def parse_syscap_info(self):
498        _build_files = self._build_info.get('build_files')
499        subsystem_syscap = []
500        for _build_file in _build_files:
501            if _build_file.endswith('bundle.json'):
502                part_name, part_syscap = get_syscap_from_bundle(_build_file)
503                subsystem_syscap.append(
504                    {'component': part_name, 'syscap': part_syscap})
505        return subsystem_syscap
506
507    def parse(self):
508        """parse part info from build config file."""
509        if self._is_load:
510            return
511        subsystem_config, parts_path_dict = self._merge_build_config()
512        parts_config = subsystem_config.get('parts')
513        self._parts_module_list.update(parts_config)
514        self._parsing_config(parts_config)
515        self._parts_path_dict = parts_path_dict
516        self._is_load = True
517
518    def parts_variants(self):
519        """parts varinats info."""
520        self.parse()
521        return self._parts_variants
522
523    def parts_inner_kits_info(self):
524        """parts inner kits info."""
525        self.parse()
526        _parts_inner_kits = {}
527        for part_obj in self._part_list.values():
528            _parts_inner_kits[
529                part_obj.part_name()] = part_obj.part_inner_kits()
530        return _parts_inner_kits
531
532    def parts_build_targets(self):
533        """parts build target label."""
534        self.parse()
535        return self._part_targets_label
536
537    def parts_name_list(self):
538        """parts name list."""
539        self.parse()
540        return list(self._part_list.keys())
541
542    def parts_info(self):
543        """parts info."""
544        self.parse()
545        return self._parts_info_dict
546
547    def parts_phony_target(self):
548        """parts phony target info"""
549        self.parse()
550        return self._phony_targets
551
552    def parts_kits_info(self):
553        """parts kits info."""
554        self.parse()
555        _parts_kits = {}
556        for part_obj in self._part_list.values():
557            _parts_kits[part_obj.part_name()] = part_obj.part_kits()
558        return _parts_kits
559
560    def parts_path_info(self):
561        """parts to path info."""
562        self.parse()
563        return self._parts_path_dict
564
565    def parts_hisysevent_config(self):
566        self.parse()
567        return self._part_hisysevent_config
568
569    def parts_modules_info(self):
570        self.parse()
571        return self._parts_module_list
572
573    def parts_deps(self):
574        self.parse()
575        return self._parts_deps
576
577    def parts_info_filter(self, save_part):
578        if save_part is None:
579            raise Exception
580        self._parts_variants = {
581            key: value for key, value in self._parts_variants.items() if key in save_part}
582        self._part_list = {
583            key: value for key, value in self._part_list.items() if key in save_part}
584        self._part_targets_label = {
585            key: value for key, value in self._part_targets_label.items() if key in save_part}
586        self._parts_info_dict = {
587            key: value for key, value in self._parts_info_dict.items() if key in save_part}
588        self._phony_targets = {
589            key: value for key, value in self._phony_targets.items() if key in save_part}
590        self._parts_path_dict = {
591            key: value for key, value in self._parts_path_dict.items() if key in save_part}
592        self._part_hisysevent_config = {
593            key: value for key, value in self._part_hisysevent_config.items() if key in save_part}
594        self._parts_module_list = {
595            key: value for key, value in self._parts_module_list.items() if key in save_part}
596        self._parts_deps = {
597            key: value for key, value in self._parts_deps.items() if key in save_part}
598
599
600def compare_subsystem_and_component(subsystem_name, components_name, subsystem_compoents_whitelist_info,
601                                    part_subsystem_component_info, config_path, subsystem_components_list):
602    name = ""
603    message = ""
604    for component in components_name:
605        if component['component'] in list(subsystem_compoents_whitelist_info.keys()):
606            continue
607        overrided_components_name = '{}_{}'.format(component['component'], 'override')
608        if component['component'] in list(part_subsystem_component_info.keys()) \
609            or overrided_components_name in list(part_subsystem_component_info.keys()):
610            if subsystem_name in list(part_subsystem_component_info.values()):
611                continue
612            if subsystem_name == component['component']:
613                continue
614            name = subsystem_name
615            message = "find subsystem {} failed, please check it in {}.".format(subsystem_name, config_path)
616        else:
617            name = component['component']
618            message = "find component {} failed, please check it in {}.".format(component['component'], config_path)
619        if name in subsystem_components_list:
620            print(f"Warning: {message}")
621        else:
622            raise Exception(message)
623
624
625def check_subsystem_and_component(parts_info_output_path, skip_partlist_check):
626    config = Config()
627    config_path = os.path.join(config.product_config_path, 'config.json')
628    part_subsystem_file = os.path.join(parts_info_output_path,
629                                       "part_subsystem.json")
630    part_subsystem_component_info = read_json_file(part_subsystem_file)
631
632    subsystem_compoents_whitelist_file = os.path.join(config.root_path,
633                                                      "build/subsystem_compoents_whitelist.json")
634    subsystem_compoents_whitelist_info = read_json_file(subsystem_compoents_whitelist_file)
635
636    compile_standard_whitelist_file = os.path.join(config.root_path, "out/preloader", config.product,
637                                                   "compile_standard_whitelist.json")
638    compile_standard_whitelist_info = read_json_file(compile_standard_whitelist_file)
639    subsystem_components_list = compile_standard_whitelist_info.get("subsystem_components", [])
640
641    if os.path.isfile(config_path):
642        info = read_json_file(config_path)
643        subsystems_info = info['subsystems']
644        for subsystems_name in iter(subsystems_info):
645            subsystem_name = subsystems_name.get('subsystem')
646            components_name = subsystems_name.get('components')
647            if subsystem_name is None or components_name is None:
648                print("Warning: subsystem_name or components_name is empty, please check it in {}.".format(config_path))
649                continue
650            if not skip_partlist_check:
651                compare_subsystem_and_component(subsystem_name,components_name, subsystem_compoents_whitelist_info,
652                                                part_subsystem_component_info, config_path, subsystem_components_list)
653
654
655def _output_parts_info(parts_config_dict, config_output_path, skip_partlist_check):
656    parts_info_output_path = os.path.join(config_output_path, "parts_info")
657    # parts_info.json
658    if 'parts_info' in parts_config_dict:
659        parts_info = parts_config_dict.get('parts_info')
660        parts_info_file = os.path.join(parts_info_output_path,
661                                       "parts_info.json")
662        write_json_file(parts_info_file, parts_info)
663        LogUtil.hb_info("generate parts info to '{}'".format(parts_info_file))
664        _part_subsystem_dict = {}
665        for key, value in parts_info.items():
666            for _info in value:
667                _sub_name = _info.get('subsystem_name')
668                _part_subsystem_dict[key] = _sub_name
669                break
670        _part_subsystem_file = os.path.join(parts_info_output_path,
671                                            "part_subsystem.json")
672        write_json_file(_part_subsystem_file, _part_subsystem_dict)
673        LogUtil.hb_info(
674            "generate part-subsystem of parts-info to '{}'".format(_part_subsystem_file))
675
676    check_subsystem_and_component(parts_info_output_path, skip_partlist_check)
677
678    # subsystem_parts.json
679    if 'subsystem_parts' in parts_config_dict:
680        subsystem_parts = parts_config_dict.get('subsystem_parts')
681        subsystem_parts_file = os.path.join(parts_info_output_path,
682                                            "subsystem_parts.json")
683        write_json_file(subsystem_parts_file, subsystem_parts)
684        LogUtil.hb_info(
685            "generate ubsystem-parts of parts-info to '{}'".format(subsystem_parts_file))
686
687        # adapter mini system
688        for _sub_name, _p_list in subsystem_parts.items():
689            _output_info = {}
690            _output_info['parts'] = _p_list
691            _sub_info_output_file = os.path.join(config_output_path,
692                                                 'mini_adapter',
693                                                 '{}.json'.format(_sub_name))
694            write_json_file(_sub_info_output_file, _output_info)
695        LogUtil.hb_info(
696            "generate mini adapter info to '{}/mini_adapter/'".format(config_output_path))
697
698    # parts_variants.json
699    if 'parts_variants' in parts_config_dict:
700        parts_variants = parts_config_dict.get('parts_variants')
701        parts_variants_info_file = os.path.join(parts_info_output_path,
702                                                "parts_variants.json")
703        write_json_file(parts_variants_info_file, parts_variants)
704        LogUtil.hb_info("generate parts variants info to '{}'".format(
705            parts_variants_info_file))
706
707    # inner_kits_info.json
708    if 'parts_inner_kits_info' in parts_config_dict:
709        parts_inner_kits_info = parts_config_dict.get('parts_inner_kits_info')
710        parts_inner_kits_info_file = os.path.join(parts_info_output_path,
711                                                  "inner_kits_info.json")
712        write_json_file(parts_inner_kits_info_file, parts_inner_kits_info)
713        LogUtil.hb_info("generate parts inner kits info to '{}'".format(
714            parts_inner_kits_info_file))
715
716    # parts_targets.json
717    if 'parts_targets' in parts_config_dict:
718        parts_targets = parts_config_dict.get('parts_targets')
719        parts_targets_info_file = os.path.join(parts_info_output_path,
720                                               "parts_targets.json")
721        write_json_file(parts_targets_info_file, parts_targets)
722        LogUtil.hb_info("generate parts targets info to '{}'".format(
723            parts_targets_info_file))
724
725    # phony_targets.json
726    if 'phony_target' in parts_config_dict:
727        phony_target = parts_config_dict.get('phony_target')
728        phony_target_info_file = os.path.join(parts_info_output_path,
729                                              "phony_target.json")
730        write_json_file(phony_target_info_file, phony_target)
731        LogUtil.hb_info("generate phony targets info to '{}'".format(
732            phony_target_info_file))
733
734    # paths_path_info.json
735    if 'parts_path_info' in parts_config_dict:
736        parts_path_info = parts_config_dict.get('parts_path_info')
737        parts_path_info_file = os.path.join(parts_info_output_path,
738                                            'parts_path_info.json')
739        write_json_file(parts_path_info_file, parts_path_info)
740        LogUtil.hb_info(
741            "generate parts path info to '{}'".format(parts_path_info_file))
742        path_to_parts = {}
743        for _key, _val in parts_path_info.items():
744            _p_list = path_to_parts.get(_val, [])
745            _p_list.append(_key)
746            path_to_parts[_val] = _p_list
747        path_to_parts_file = os.path.join(parts_info_output_path,
748                                          'path_to_parts.json')
749        write_json_file(path_to_parts_file, path_to_parts)
750        LogUtil.hb_info(
751            "generate path to parts to '{}'".format(path_to_parts_file))
752
753    # hisysevent_config
754    if 'hisysevent_config' in parts_config_dict:
755        hisysevent_config = parts_config_dict.get('hisysevent_config')
756        hisysevent_info_file = os.path.join(parts_info_output_path,
757                                            'hisysevent_configs.json')
758        write_json_file(hisysevent_info_file, hisysevent_config)
759        LogUtil.hb_info(
760            "generate hisysevent info to '{}'".format(hisysevent_info_file))
761
762    # _parts_modules_info
763    if 'parts_modules_info' in parts_config_dict:
764        parts_modules_info = parts_config_dict.get('parts_modules_info')
765        _output_info = {}
766        _all_p_info = []
767        for key, value in parts_modules_info.items():
768            _p_info = {}
769            _p_info['part_name'] = key
770            _module_list = value.get('module_list')
771            _p_info['module_list'] = _module_list
772            _all_p_info.append(_p_info)
773        _output_info['parts'] = _all_p_info
774        parts_modules_info_file = os.path.join(parts_info_output_path,
775                                               'parts_modules_info.json')
776        write_json_file(parts_modules_info_file, _output_info)
777        LogUtil.hb_info("generate parts modules info to '{}'".format(
778            parts_modules_info_file))
779
780    # parts_deps
781    if 'parts_deps' in parts_config_dict:
782        parts_deps_info = parts_config_dict.get('parts_deps')
783        parts_deps_info_file = os.path.join(parts_info_output_path,
784                                            'parts_deps.json')
785        write_json_file(parts_deps_info_file, parts_deps_info)
786        LogUtil.hb_info(
787            "generate parts deps info to '{}'".format(parts_deps_info_file))
788
789
790def get_parts_info(source_root_dir,
791                   config_output_relpath,
792                   subsystem_info,
793                   variant_toolchains,
794                   target_arch,
795                   ignored_subsystems,
796                   exclusion_modules_config_file,
797                   load_test_config,
798                   overrided_components,
799                   bundle_subsystem_allow_list,
800                   skip_partlist_check,
801                   build_xts=False):
802    """parts info,
803    get info from build config file.
804    """
805    parts_variants = {}
806    parts_inner_kits_info = {}
807    parts_kits_info = {}
808    parts_targets = {}
809    parts_info = {}
810    subsystem_parts = {}
811    _phony_target = {}
812    _parts_path_info = {}
813    _parts_hisysevent_config = {}
814    _parts_modules_info = {}
815    _parts_deps = {}
816    system_syscap = []
817    for subsystem_name, build_config_info in subsystem_info.items():
818        if not len(build_config_info.get("build_files")):
819            continue
820        build_loader = LoadBuildConfig(source_root_dir, build_config_info,
821                                       config_output_relpath,
822                                       variant_toolchains, subsystem_name,
823                                       target_arch, ignored_subsystems,
824                                       exclusion_modules_config_file,
825                                       load_test_config, overrided_components,
826                                       bundle_subsystem_allow_list)
827        # xts subsystem special handling, device_attest and
828        # device_attest_lite parts need to be compiled into the version image, other parts are not.
829        # parts_modules_info needs to be parse before filting.
830        if subsystem_name == 'xts' and build_xts is False:
831            xts_device_attest_name = ['device_attest_lite', 'device_attest']
832            build_loader.parse()
833            build_loader.parts_info_filter(xts_device_attest_name)
834        _parts_variants = build_loader.parts_variants()
835        parts_variants.update(_parts_variants)
836        _inner_kits_info = build_loader.parts_inner_kits_info()
837        parts_inner_kits_info.update(_inner_kits_info)
838        parts_kits_info.update(build_loader.parts_kits_info())
839        _parts_targets = build_loader.parts_build_targets()
840        parts_targets.update(_parts_targets)
841        subsystem_parts[subsystem_name] = build_loader.parts_name_list()
842        parts_info.update(build_loader.parts_info())
843        _phony_target.update(build_loader.parts_phony_target())
844        _parts_path_info.update(build_loader.parts_path_info())
845        _parts_hisysevent_config.update(build_loader.parts_hisysevent_config())
846        _parts_modules_info.update(build_loader.parts_modules_info())
847        _parts_deps.update(build_loader.parts_deps())
848        system_syscap.extend(build_loader.parse_syscap_info())
849    LogUtil.hb_info(
850        "generate all parts build gn file to '{}/{}'".format(source_root_dir, config_output_relpath))
851    parts_config_dict = {}
852    parts_config_dict['parts_info'] = parts_info
853    parts_config_dict['subsystem_parts'] = subsystem_parts
854    parts_config_dict['parts_variants'] = parts_variants
855    parts_config_dict['parts_inner_kits_info'] = parts_inner_kits_info
856    parts_config_dict['parts_kits_info'] = parts_kits_info
857    parts_config_dict['parts_targets'] = parts_targets
858    parts_config_dict['phony_target'] = _phony_target
859    parts_config_dict['parts_path_info'] = _parts_path_info
860    parts_config_dict['hisysevent_config'] = _parts_hisysevent_config
861    parts_config_dict['parts_modules_info'] = _parts_modules_info
862    parts_config_dict['parts_deps'] = _parts_deps
863    _output_parts_info(parts_config_dict,
864                       os.path.join(source_root_dir, config_output_relpath), skip_partlist_check)
865    parts_config_dict['syscap_info'] = system_syscap
866    LogUtil.hb_info('all parts scan completed')
867    return parts_config_dict
868