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