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