15f9996aaSopenharmony_ci#!/usr/bin/env python
25f9996aaSopenharmony_ci# -*- coding: utf-8 -*-
35f9996aaSopenharmony_ci# Copyright (c) 2021 Huawei Device Co., Ltd.
45f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
55f9996aaSopenharmony_ci# you may not use this file except in compliance with the License.
65f9996aaSopenharmony_ci# You may obtain a copy of the License at
75f9996aaSopenharmony_ci#
85f9996aaSopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
95f9996aaSopenharmony_ci#
105f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software
115f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
125f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135f9996aaSopenharmony_ci# See the License for the specific language governing permissions and
145f9996aaSopenharmony_ci# limitations under the License.
155f9996aaSopenharmony_ci
165f9996aaSopenharmony_ciimport argparse
175f9996aaSopenharmony_ciimport sys
185f9996aaSopenharmony_ciimport os
195f9996aaSopenharmony_ciimport pathlib
205f9996aaSopenharmony_ciimport re
215f9996aaSopenharmony_cifrom convert_permissions import convert_permissions
225f9996aaSopenharmony_ci
235f9996aaSopenharmony_cisys.path.append(
245f9996aaSopenharmony_ci    os.path.dirname(
255f9996aaSopenharmony_ci        os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
265f9996aaSopenharmony_cifrom scripts.util.file_utils import write_file, read_json_file, \
275f9996aaSopenharmony_ci    write_json_file  # noqa: E402
285f9996aaSopenharmony_cifrom scripts.util import build_utils  # noqa: E402
295f9996aaSopenharmony_ci
305f9996aaSopenharmony_ci# Import jinja2 from third_party/jinja2
315f9996aaSopenharmony_cisys.path.insert(1, os.path.join(os.path.abspath(
325f9996aaSopenharmony_ci                   os.path.join(os.path.dirname(__file__),
335f9996aaSopenharmony_ci                   '..', '..', '..')), 'third_party'))
345f9996aaSopenharmony_cifrom jinja2 import Template  # noqa: E402  # pylint: disable=F0401
355f9996aaSopenharmony_ci
365f9996aaSopenharmony_ciKEYS = ['target_os', 'install_dir', 'module_label', 'build_only']
375f9996aaSopenharmony_ci
385f9996aaSopenharmony_ci
395f9996aaSopenharmony_ciclass SdkTargets:
405f9996aaSopenharmony_ci
415f9996aaSopenharmony_ci    def __init__(self, os_type):
425f9996aaSopenharmony_ci        self.os_type = os_type
435f9996aaSopenharmony_ci        self.targets = []
445f9996aaSopenharmony_ci
455f9996aaSopenharmony_ci    def add_target(self, target):
465f9996aaSopenharmony_ci        if target not in self.targets:
475f9996aaSopenharmony_ci            self.targets.append(target)
485f9996aaSopenharmony_ci
495f9996aaSopenharmony_ci    def get_targets(self):
505f9996aaSopenharmony_ci        return self.targets
515f9996aaSopenharmony_ci
525f9996aaSopenharmony_ci
535f9996aaSopenharmony_cidef check_keys(keys):
545f9996aaSopenharmony_ci    for key in keys:
555f9996aaSopenharmony_ci        if key not in KEYS:
565f9996aaSopenharmony_ci            raise Exception(
575f9996aaSopenharmony_ci                'Error: failed to parse ohos sdk description file, missing {}.'
585f9996aaSopenharmony_ci                .format(key))
595f9996aaSopenharmony_ci
605f9996aaSopenharmony_ci
615f9996aaSopenharmony_cidef get_sdk_type(path_name: str):
625f9996aaSopenharmony_ci    p = pathlib.Path(path_name)
635f9996aaSopenharmony_ci    if path_name.startswith('/'):
645f9996aaSopenharmony_ci        top_dir = p.parts[1]
655f9996aaSopenharmony_ci    else:
665f9996aaSopenharmony_ci        top_dir = p.parts[0]
675f9996aaSopenharmony_ci    return top_dir
685f9996aaSopenharmony_ci
695f9996aaSopenharmony_ci
705f9996aaSopenharmony_cidef add_target(item: dict, target: str, sdk_systems: list):
715f9996aaSopenharmony_ci    for _os in sdk_systems:
725f9996aaSopenharmony_ci        if _os == 'linux' or _os == 'Linux':
735f9996aaSopenharmony_ci            item.get('targets').get('linux').add_target('"%s",' % target)
745f9996aaSopenharmony_ci        elif _os == 'windows' or _os == 'Windows':
755f9996aaSopenharmony_ci            item.get('targets').get('windows').add_target('"%s",' % target)
765f9996aaSopenharmony_ci        elif _os == 'darwin' or _os == 'Darwin':
775f9996aaSopenharmony_ci            item.get('targets').get('darwin').add_target('"%s",' % target)
785f9996aaSopenharmony_ci        elif _os == 'ohos' or _os == 'Ohos':
795f9996aaSopenharmony_ci            item.get('targets').get('ohos').add_target('"%s",' % target)
805f9996aaSopenharmony_ci
815f9996aaSopenharmony_ci
825f9996aaSopenharmony_cidef write_sdk_build_gni(sdk_targets: list, build_only_targets: list, gni: str):
835f9996aaSopenharmony_ci    template = Template(
845f9996aaSopenharmony_ci        """#Generated code, DONOT modify it.
855f9996aaSopenharmony_ci            ohos_sdk_modules = {
865f9996aaSopenharmony_ci                {% for item in sdk_targets %}
875f9996aaSopenharmony_ci
885f9996aaSopenharmony_ci                    {% set sdk_type = item.get('type') %}
895f9996aaSopenharmony_ci                    {% set targets = item.get('targets') %}
905f9996aaSopenharmony_ci                    {% set systems = targets.keys() %}
915f9996aaSopenharmony_ci                    {% set _sdk_type = sdk_type.replace('-', '_') %}
925f9996aaSopenharmony_ci
935f9996aaSopenharmony_ci                        {{ _sdk_type }} = {
945f9996aaSopenharmony_ci                            {% for os in systems %}
955f9996aaSopenharmony_ci                                {{ os }} = [
965f9996aaSopenharmony_ci                                    {% for t in targets.get(os).get_targets() %}
975f9996aaSopenharmony_ci                                        {{ t }}
985f9996aaSopenharmony_ci                                    {% endfor %}
995f9996aaSopenharmony_ci                                ]
1005f9996aaSopenharmony_ci                            {% endfor %}
1015f9996aaSopenharmony_ci                        }
1025f9996aaSopenharmony_ci                {% endfor %}
1035f9996aaSopenharmony_ci
1045f9996aaSopenharmony_ci                extras = [
1055f9996aaSopenharmony_ci                {% for t in build_only_targets%}
1065f9996aaSopenharmony_ci                    "{{ t }}",
1075f9996aaSopenharmony_ci                {% endfor %}
1085f9996aaSopenharmony_ci                ]
1095f9996aaSopenharmony_ci            }
1105f9996aaSopenharmony_ci        """,  # noqa E501
1115f9996aaSopenharmony_ci        trim_blocks=True,
1125f9996aaSopenharmony_ci        lstrip_blocks=True)
1135f9996aaSopenharmony_ci
1145f9996aaSopenharmony_ci    contents = template.render(
1155f9996aaSopenharmony_ci        sdk_targets=sdk_targets, build_only_targets=build_only_targets)
1165f9996aaSopenharmony_ci    write_file(gni, contents)
1175f9996aaSopenharmony_ci
1185f9996aaSopenharmony_ci
1195f9996aaSopenharmony_cidef get_build_gn(label: str):
1205f9996aaSopenharmony_ci    match = re.search(r"(.*?):(.*?)", label)
1215f9996aaSopenharmony_ci    if match:
1225f9996aaSopenharmony_ci        gn = '{}/BUILD.gn'.format(match.group(1))
1235f9996aaSopenharmony_ci        if gn.startswith("//"):
1245f9996aaSopenharmony_ci            return gn[len("//"):]
1255f9996aaSopenharmony_ci        else:
1265f9996aaSopenharmony_ci            return gn
1275f9996aaSopenharmony_ci    else:
1285f9996aaSopenharmony_ci        raise Exception("failed to get BUILD.gn of {}".format(label))
1295f9996aaSopenharmony_ci
1305f9996aaSopenharmony_ci
1315f9996aaSopenharmony_cidef variant_to_product(variant: dict, options: dict):
1325f9996aaSopenharmony_ci    relations = read_json_file(options.variant_to_product)
1335f9996aaSopenharmony_ci    if variant in relations.keys():
1345f9996aaSopenharmony_ci        return relations.get(variant)
1355f9996aaSopenharmony_ci    else:
1365f9996aaSopenharmony_ci        raise Exception('Error: failed to read {} in {}'.format(
1375f9996aaSopenharmony_ci            variant, options.variant_to_product))
1385f9996aaSopenharmony_ci
1395f9996aaSopenharmony_ci
1405f9996aaSopenharmony_cidef expand_platform_targets(options, label: str, install_dir: str):
1415f9996aaSopenharmony_ci    base = options.base_platform
1425f9996aaSopenharmony_ci    platforms = options.platforms
1435f9996aaSopenharmony_ci    variant = list(set(platforms) - set([base]))
1445f9996aaSopenharmony_ci
1455f9996aaSopenharmony_ci    if label.find('${base}') != -1:
1465f9996aaSopenharmony_ci        return [label.replace('${base}', base)], [install_dir]
1475f9996aaSopenharmony_ci    elif label.find('${platforms}') != -1:
1485f9996aaSopenharmony_ci        return [label.replace('${platforms}', p) for p in platforms], [
1495f9996aaSopenharmony_ci            install_dir.replace('${platforms}',
1505f9996aaSopenharmony_ci                                variant_to_product(c, options))
1515f9996aaSopenharmony_ci            for c in platforms
1525f9996aaSopenharmony_ci        ]
1535f9996aaSopenharmony_ci    elif label.find('${variant}') != -1:
1545f9996aaSopenharmony_ci        return [label.replace('${variant}', c) for c in variant], [
1555f9996aaSopenharmony_ci            install_dir.replace('${variant}', variant_to_product(c, options))
1565f9996aaSopenharmony_ci            for c in variant
1575f9996aaSopenharmony_ci        ]
1585f9996aaSopenharmony_ci    else:
1595f9996aaSopenharmony_ci        return [label], [install_dir]
1605f9996aaSopenharmony_ci
1615f9996aaSopenharmony_ci
1625f9996aaSopenharmony_cidef add_sdk_targets(sdk_type, sdk_targets):
1635f9996aaSopenharmony_ci    sdk_targets.append({
1645f9996aaSopenharmony_ci        'type': sdk_type,
1655f9996aaSopenharmony_ci        'targets': {
1665f9996aaSopenharmony_ci            'linux': SdkTargets('linux'),
1675f9996aaSopenharmony_ci            'windows': SdkTargets('windows'),
1685f9996aaSopenharmony_ci            'darwin': SdkTargets('darwin'),
1695f9996aaSopenharmony_ci            'ohos': SdkTargets('ohos')
1705f9996aaSopenharmony_ci        }
1715f9996aaSopenharmony_ci    })
1725f9996aaSopenharmony_ci
1735f9996aaSopenharmony_ci
1745f9996aaSopenharmony_cidef parse_description_file(options):
1755f9996aaSopenharmony_ci    data = read_json_file(options.sdk_description_file)
1765f9996aaSopenharmony_ci    if data is None:
1775f9996aaSopenharmony_ci        raise Exception("read file '{}' failed.".format(
1785f9996aaSopenharmony_ci            options.sdk_description_file))
1795f9996aaSopenharmony_ci
1805f9996aaSopenharmony_ci    module_install_infos = []
1815f9996aaSopenharmony_ci    sdk_types = []
1825f9996aaSopenharmony_ci    sdk_targets = []
1835f9996aaSopenharmony_ci    build_only_targets = []
1845f9996aaSopenharmony_ci
1855f9996aaSopenharmony_ci    for d in data:
1865f9996aaSopenharmony_ci        check_keys(d.keys())
1875f9996aaSopenharmony_ci
1885f9996aaSopenharmony_ci        label = d.get('module_label')
1895f9996aaSopenharmony_ci        install_dir = d.get('install_dir')
1905f9996aaSopenharmony_ci        build_only = d.get('build_only')
1915f9996aaSopenharmony_ci
1925f9996aaSopenharmony_ci        # skip labels that we cannot find.
1935f9996aaSopenharmony_ci        rebased_build_gn = build_utils.rebase_path(
1945f9996aaSopenharmony_ci            get_build_gn(label), current_base=options.source_root_dir)
1955f9996aaSopenharmony_ci        if not os.path.exists(rebased_build_gn):
1965f9996aaSopenharmony_ci            continue
1975f9996aaSopenharmony_ci
1985f9996aaSopenharmony_ci        if build_only:
1995f9996aaSopenharmony_ci            build_only_targets.append(label)
2005f9996aaSopenharmony_ci            continue
2015f9996aaSopenharmony_ci
2025f9996aaSopenharmony_ci        module_labels, install_dirs = expand_platform_targets(
2035f9996aaSopenharmony_ci            options, label, install_dir)
2045f9996aaSopenharmony_ci        target_os = d.get('target_os')
2055f9996aaSopenharmony_ci
2065f9996aaSopenharmony_ci        sdk_type = get_sdk_type(install_dir)
2075f9996aaSopenharmony_ci
2085f9996aaSopenharmony_ci        if sdk_type not in sdk_types:
2095f9996aaSopenharmony_ci            add_sdk_targets(sdk_type, sdk_targets)
2105f9996aaSopenharmony_ci            sdk_types.append(sdk_type)
2115f9996aaSopenharmony_ci
2125f9996aaSopenharmony_ci        for item in sdk_targets:
2135f9996aaSopenharmony_ci            if item['type'] == sdk_type:
2145f9996aaSopenharmony_ci                for m in module_labels:
2155f9996aaSopenharmony_ci                    add_target(item, m, target_os)
2165f9996aaSopenharmony_ci
2175f9996aaSopenharmony_ci        for label, install_dir in zip(module_labels, install_dirs):
2185f9996aaSopenharmony_ci            install_info = {
2195f9996aaSopenharmony_ci                'label': label,
2205f9996aaSopenharmony_ci                'install_dir': install_dir
2215f9996aaSopenharmony_ci            }
2225f9996aaSopenharmony_ci            module_install_infos.append(install_info)
2235f9996aaSopenharmony_ci
2245f9996aaSopenharmony_ci    return {
2255f9996aaSopenharmony_ci        "sdk_targets": sdk_targets,
2265f9996aaSopenharmony_ci        "install_infos": module_install_infos,
2275f9996aaSopenharmony_ci        "sdk_types": sdk_types,
2285f9996aaSopenharmony_ci        "build_only_targets": build_only_targets
2295f9996aaSopenharmony_ci    }
2305f9996aaSopenharmony_ci
2315f9996aaSopenharmony_ci
2325f9996aaSopenharmony_cidef main():
2335f9996aaSopenharmony_ci    parser = argparse.ArgumentParser()
2345f9996aaSopenharmony_ci    parser.add_argument('--sdk-description-file', required=True)
2355f9996aaSopenharmony_ci    parser.add_argument('--sdk-install-info-file', required=True)
2365f9996aaSopenharmony_ci    parser.add_argument('--sdk-modules-gni', required=True)
2375f9996aaSopenharmony_ci    parser.add_argument('--sdk-types-file', required=True)
2385f9996aaSopenharmony_ci    parser.add_argument('--base-platform', required=True)
2395f9996aaSopenharmony_ci    parser.add_argument('--platforms', action='append', required=True)
2405f9996aaSopenharmony_ci    parser.add_argument('--source-root-dir', required=True)
2415f9996aaSopenharmony_ci    parser.add_argument('--variant-to-product', required=True)
2425f9996aaSopenharmony_ci    parser.add_argument('--node-js', required=True)
2435f9996aaSopenharmony_ci
2445f9996aaSopenharmony_ci    options = parser.parse_args()
2455f9996aaSopenharmony_ci
2465f9996aaSopenharmony_ci    convert_permissions(options.source_root_dir, options.node_js)
2475f9996aaSopenharmony_ci
2485f9996aaSopenharmony_ci    data = parse_description_file(options)
2495f9996aaSopenharmony_ci
2505f9996aaSopenharmony_ci    write_sdk_build_gni(
2515f9996aaSopenharmony_ci        data.get('sdk_targets'), data.get('build_only_targets'),
2525f9996aaSopenharmony_ci        options.sdk_modules_gni)
2535f9996aaSopenharmony_ci    write_json_file(options.sdk_install_info_file, data.get('install_infos'))
2545f9996aaSopenharmony_ci    with open(options.sdk_types_file, 'w') as f:
2555f9996aaSopenharmony_ci        f.write('\n'.join(data.get('sdk_types')))
2565f9996aaSopenharmony_ci
2575f9996aaSopenharmony_ci
2585f9996aaSopenharmony_ciif __name__ == '__main__':
2595f9996aaSopenharmony_ci    sys.exit(main())
260