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 sys
175f9996aaSopenharmony_ciimport argparse
185f9996aaSopenharmony_ciimport os
195f9996aaSopenharmony_ciimport json
205f9996aaSopenharmony_ciimport copy
215f9996aaSopenharmony_ci
225f9996aaSopenharmony_cisys.path.append(
235f9996aaSopenharmony_ci    os.path.dirname(os.path.dirname(os.path.dirname(
245f9996aaSopenharmony_ci        os.path.abspath(__file__)))))
255f9996aaSopenharmony_cifrom scripts.util import build_utils  # noqa E402
265f9996aaSopenharmony_ci
275f9996aaSopenharmony_cideps_metadta_cache = {}
285f9996aaSopenharmony_ci
295f9996aaSopenharmony_ci
305f9996aaSopenharmony_cidef get_all_deps(direct_deps):
315f9996aaSopenharmony_ci    if direct_deps == []:
325f9996aaSopenharmony_ci        return []
335f9996aaSopenharmony_ci    deps = copy.deepcopy(direct_deps)
345f9996aaSopenharmony_ci    all_deps = set()
355f9996aaSopenharmony_ci    all_deps.update(deps)
365f9996aaSopenharmony_ci    while len(deps) > 0:
375f9996aaSopenharmony_ci        dep = deps.pop(0)
385f9996aaSopenharmony_ci        if dep not in deps_metadta_cache:
395f9996aaSopenharmony_ci            with open(dep) as dep_fp:
405f9996aaSopenharmony_ci                deps_metadta_cache[dep] = json.load(dep_fp).get('root')
415f9996aaSopenharmony_ci        for n in deps_metadta_cache[dep].get('metadata_deps'):
425f9996aaSopenharmony_ci            if n not in all_deps:
435f9996aaSopenharmony_ci                deps.append(n)
445f9996aaSopenharmony_ci                all_deps.add(n)
455f9996aaSopenharmony_ci    return sorted(list(all_deps))
465f9996aaSopenharmony_ci
475f9996aaSopenharmony_ci
485f9996aaSopenharmony_cidef get_deps_metadata(deps):
495f9996aaSopenharmony_ci    return [deps_metadta_cache.get(d) for d in deps]
505f9996aaSopenharmony_ci
515f9996aaSopenharmony_ci
525f9996aaSopenharmony_cidef get_deps_of_type(deps_data, target_type):
535f9996aaSopenharmony_ci    return [d for d in deps_data if d.get('type') == target_type]
545f9996aaSopenharmony_ci
555f9996aaSopenharmony_ci
565f9996aaSopenharmony_ciclass Deps(object):
575f9996aaSopenharmony_ci    def __init__(self, direct_deps):
585f9996aaSopenharmony_ci        self.direct_deps = direct_deps
595f9996aaSopenharmony_ci        self.all_deps = get_all_deps(direct_deps)
605f9996aaSopenharmony_ci        self.all_deps_data = get_deps_metadata(self.all_deps)
615f9996aaSopenharmony_ci
625f9996aaSopenharmony_ci    def all(self, target_type):
635f9996aaSopenharmony_ci        return get_deps_of_type(self.all_deps_data, target_type)
645f9996aaSopenharmony_ci
655f9996aaSopenharmony_ci
665f9996aaSopenharmony_cidef write_meta_data(options, direct_deps):
675f9996aaSopenharmony_ci    meta_data = {
685f9996aaSopenharmony_ci        'root': {
695f9996aaSopenharmony_ci            'type': options.type,
705f9996aaSopenharmony_ci            'metadata_path': options.output,
715f9996aaSopenharmony_ci            'metadata_deps': direct_deps
725f9996aaSopenharmony_ci        }
735f9996aaSopenharmony_ci    }
745f9996aaSopenharmony_ci    root = meta_data['root']
755f9996aaSopenharmony_ci    if options.type == 'app_profile':
765f9996aaSopenharmony_ci        root[options.type] = options.app_profile
775f9996aaSopenharmony_ci        root['resources'] = options.resources
785f9996aaSopenharmony_ci    if options.type == 'js_assets':
795f9996aaSopenharmony_ci        root[options.type] = options.js_assets
805f9996aaSopenharmony_ci        if options.js_forms:
815f9996aaSopenharmony_ci            root['js_forms'] = options.js_forms
825f9996aaSopenharmony_ci        if options.testrunner:
835f9996aaSopenharmony_ci            root['testrunner'] = options.testrunner
845f9996aaSopenharmony_ci    if options.type == 'ets_assets':
855f9996aaSopenharmony_ci        root[options.type] = options.ets_assets
865f9996aaSopenharmony_ci    if options.type == 'assets':
875f9996aaSopenharmony_ci        root[options.type] = options.raw_assets
885f9996aaSopenharmony_ci    if options.type == 'unresolved_assets':
895f9996aaSopenharmony_ci        root[options.type] = options.unresolved_assets
905f9996aaSopenharmony_ci    if options.type == 'resources':
915f9996aaSopenharmony_ci        deps = Deps(direct_deps)
925f9996aaSopenharmony_ci        root[options.type] = options.resources
935f9996aaSopenharmony_ci        package_name = options.package_name
945f9996aaSopenharmony_ci        root['package_name'] = package_name if package_name else ""
955f9996aaSopenharmony_ci        for target_type in ['app_profile']:
965f9996aaSopenharmony_ci            for dep in deps.all(target_type):
975f9996aaSopenharmony_ci                if root.get(target_type):
985f9996aaSopenharmony_ci                    root.get(target_type).extend(dep[target_type])
995f9996aaSopenharmony_ci                    root.get('resources').extend(dep['resources'])
1005f9996aaSopenharmony_ci                else:
1015f9996aaSopenharmony_ci                    root[target_type] = dep[target_type]
1025f9996aaSopenharmony_ci                    root['resources'] += dep['resources']
1035f9996aaSopenharmony_ci    if options.type == 'hap' or options.type == 'resources':
1045f9996aaSopenharmony_ci        hap_profile = options.hap_profile
1055f9996aaSopenharmony_ci        root['hap_profile'] = hap_profile if hap_profile else ""
1065f9996aaSopenharmony_ci
1075f9996aaSopenharmony_ci    # Merge all metadata
1085f9996aaSopenharmony_ci    if options.type == 'hap':
1095f9996aaSopenharmony_ci        deps = Deps(direct_deps)
1105f9996aaSopenharmony_ci        root['hap_path'] = options.hap_path
1115f9996aaSopenharmony_ci        for target_type in ['js_assets', 'ets_assets', 'assets', 'resources']:
1125f9996aaSopenharmony_ci            root[target_type] = []
1135f9996aaSopenharmony_ci        if options.js_assets:
1145f9996aaSopenharmony_ci            root['js_assets'] = options.js_assets
1155f9996aaSopenharmony_ci        if options.ets_assets:
1165f9996aaSopenharmony_ci            root['ets_assets'] = options.ets_assets
1175f9996aaSopenharmony_ci        if options.raw_assets:
1185f9996aaSopenharmony_ci            root['assets'] = options.raw_assets
1195f9996aaSopenharmony_ci        if options.resources:
1205f9996aaSopenharmony_ci            root['resources'] = options.resources
1215f9996aaSopenharmony_ci        for target_type in ['js_assets', 'ets_assets', 'assets', 'resources', 'app_profile']:
1225f9996aaSopenharmony_ci            for dep in deps.all(target_type):
1235f9996aaSopenharmony_ci                if root.get(target_type):
1245f9996aaSopenharmony_ci                    root.get(target_type).extend(dep[target_type])
1255f9996aaSopenharmony_ci                    root.get('hap_profile').extend(dep['hap_profile'])
1265f9996aaSopenharmony_ci                else:
1275f9996aaSopenharmony_ci                    root[target_type] = dep[target_type]
1285f9996aaSopenharmony_ci                    if dep.get('hap_profile'):
1295f9996aaSopenharmony_ci                        root['hap_profile'] = dep['hap_profile']
1305f9996aaSopenharmony_ci                    if dep.get('js_forms'):
1315f9996aaSopenharmony_ci                        root['js_forms'] = dep['js_forms']
1325f9996aaSopenharmony_ci                    if dep.get('testrunner'):
1335f9996aaSopenharmony_ci                        root['testrunner'] = dep['testrunner']
1345f9996aaSopenharmony_ci        target_type = 'unresolved_assets'
1355f9996aaSopenharmony_ci        for dep in deps.all(target_type):
1365f9996aaSopenharmony_ci            if options.js2abc:
1375f9996aaSopenharmony_ci                if isinstance(dep[target_type], list):
1385f9996aaSopenharmony_ci                    for ability_path in dep[target_type]:
1395f9996aaSopenharmony_ci                        root.get('js_assets').append(ability_path)
1405f9996aaSopenharmony_ci                else:
1415f9996aaSopenharmony_ci                    root.get('js_assets').append(dep[target_type])
1425f9996aaSopenharmony_ci            else:
1435f9996aaSopenharmony_ci                if isinstance(dep[target_type], list):
1445f9996aaSopenharmony_ci                    for ability_path in dep[target_type]:
1455f9996aaSopenharmony_ci                        root.get('ets_assets').append(ability_path)
1465f9996aaSopenharmony_ci                else:
1475f9996aaSopenharmony_ci                    root.get('ets_assets').append(dep[target_type])
1485f9996aaSopenharmony_ci    build_utils.write_json(meta_data, options.output, only_if_changed=True)
1495f9996aaSopenharmony_ci
1505f9996aaSopenharmony_ci
1515f9996aaSopenharmony_ci# Collect assets entry according to config.json
1525f9996aaSopenharmony_cidef load_assets(options, assets, assets_type):
1535f9996aaSopenharmony_ci    pre_path = assets[0]
1545f9996aaSopenharmony_ci    pre_path = pre_path.rstrip('/')
1555f9996aaSopenharmony_ci    with open(options.hap_profile) as profile:
1565f9996aaSopenharmony_ci        config = json.load(profile)
1575f9996aaSopenharmony_ci
1585f9996aaSopenharmony_ci        # In multi-ability cases, load the assets entry according to "srcPath" in config.json
1595f9996aaSopenharmony_ci        if os.path.basename(pre_path) == 'js' or os.path.basename(pre_path) == 'ets':
1605f9996aaSopenharmony_ci            assets = []
1615f9996aaSopenharmony_ci            for ability in config['module']['abilities']:
1625f9996aaSopenharmony_ci                if assets_type == 'js':
1635f9996aaSopenharmony_ci                    if ability.__contains__('srcPath') and ability.get('srcLanguage') == assets_type:
1645f9996aaSopenharmony_ci                        assets.append(os.path.join(pre_path, ability['srcPath']))
1655f9996aaSopenharmony_ci
1665f9996aaSopenharmony_ci                    # Load js form entry according to "jsComponentName" in config.json
1675f9996aaSopenharmony_ci                    if ability.__contains__('forms'):
1685f9996aaSopenharmony_ci                        for form in ability['forms']:
1695f9996aaSopenharmony_ci                            if form.__contains__('jsComponentName'):
1705f9996aaSopenharmony_ci                                options.js_forms.append(os.path.join(pre_path, form['jsComponentName']))
1715f9996aaSopenharmony_ci                            else:
1725f9996aaSopenharmony_ci                                raise Exception('"module.abilities.ability.forms.form.jsComponentName" is required')
1735f9996aaSopenharmony_ci                else:
1745f9996aaSopenharmony_ci                    if ability.__contains__('srcPath'):
1755f9996aaSopenharmony_ci                        assets.append(os.path.join(pre_path, ability['srcPath']))
1765f9996aaSopenharmony_ci        else:
1775f9996aaSopenharmony_ci            pre_path = os.path.dirname(pre_path)
1785f9996aaSopenharmony_ci
1795f9996aaSopenharmony_ci        # Load testrunner entry
1805f9996aaSopenharmony_ci        if config['module'].__contains__('testRunner') and assets_type == 'js':
1815f9996aaSopenharmony_ci            options.testrunner.append(os.path.join(pre_path, config['module']['testRunner']['srcPath']))
1825f9996aaSopenharmony_ci    if not assets:
1835f9996aaSopenharmony_ci        assets.append(pre_path)
1845f9996aaSopenharmony_ci    return assets
1855f9996aaSopenharmony_ci
1865f9996aaSopenharmony_ci
1875f9996aaSopenharmony_cidef main():
1885f9996aaSopenharmony_ci    parser = argparse.ArgumentParser()
1895f9996aaSopenharmony_ci
1905f9996aaSopenharmony_ci    parser.add_argument('--output',
1915f9996aaSopenharmony_ci                        help='output meta data file',
1925f9996aaSopenharmony_ci                        required=True)
1935f9996aaSopenharmony_ci    parser.add_argument('--type', help='type of module', required=True)
1945f9996aaSopenharmony_ci    parser.add_argument('--raw-assets', nargs='+', help='raw assets directory')
1955f9996aaSopenharmony_ci    parser.add_argument('--js-assets', nargs='+', help='js assets directory')
1965f9996aaSopenharmony_ci    parser.add_argument('--ets-assets', nargs='+', help='ets assets directory')
1975f9996aaSopenharmony_ci    parser.add_argument('--resources', nargs='+', help='resources directory')
1985f9996aaSopenharmony_ci    parser.add_argument('--hap-path', help='path to output hap')
1995f9996aaSopenharmony_ci    parser.add_argument('--depfile', help='path to .d file')
2005f9996aaSopenharmony_ci    parser.add_argument('--deps-metadata', nargs="+", help='metadata deps')
2015f9996aaSopenharmony_ci    parser.add_argument('--package-name',
2025f9996aaSopenharmony_ci                        help='package name for hap resources')
2035f9996aaSopenharmony_ci    parser.add_argument('--hap-profile', help='path to hap profile')
2045f9996aaSopenharmony_ci    parser.add_argument('--app-profile', help='path to app profile')
2055f9996aaSopenharmony_ci    parser.add_argument('--unresolved-assets', nargs='+', help='unresolved assets directory')
2065f9996aaSopenharmony_ci    parser.add_argument('--js2abc',
2075f9996aaSopenharmony_ci                        action='store_true',
2085f9996aaSopenharmony_ci                        default=False,
2095f9996aaSopenharmony_ci                        help='whether to transform js to ark bytecode')
2105f9996aaSopenharmony_ci    options = parser.parse_args()
2115f9996aaSopenharmony_ci    direct_deps = options.deps_metadata if options.deps_metadata else []
2125f9996aaSopenharmony_ci
2135f9996aaSopenharmony_ci    # js forms entry list
2145f9996aaSopenharmony_ci    options.js_forms = []
2155f9996aaSopenharmony_ci
2165f9996aaSopenharmony_ci    # testrunner entry list
2175f9996aaSopenharmony_ci    options.testrunner = []
2185f9996aaSopenharmony_ci
2195f9996aaSopenharmony_ci    if options.hap_profile:
2205f9996aaSopenharmony_ci        if options.js_assets:
2215f9996aaSopenharmony_ci            options.js_assets = load_assets(options, options.js_assets, 'js')
2225f9996aaSopenharmony_ci        if options.ets_assets:
2235f9996aaSopenharmony_ci            options.ets_assets = load_assets(options, options.ets_assets, 'ets')
2245f9996aaSopenharmony_ci        if options.unresolved_assets:
2255f9996aaSopenharmony_ci            options.unresolved_assets = load_assets(options, options.unresolved_assets, 'unresolved')
2265f9996aaSopenharmony_ci
2275f9996aaSopenharmony_ci    possible_input_strings = [
2285f9996aaSopenharmony_ci        options.type, options.raw_assets, options.js_assets, options.ets_assets, options.resources,
2295f9996aaSopenharmony_ci        options.hap_path, options.hap_profile, options.package_name, options.app_profile
2305f9996aaSopenharmony_ci    ]
2315f9996aaSopenharmony_ci    input_strings = [x for x in possible_input_strings if x]
2325f9996aaSopenharmony_ci
2335f9996aaSopenharmony_ci    build_utils.call_and_write_depfile_if_stale(
2345f9996aaSopenharmony_ci        lambda: write_meta_data(options, direct_deps),
2355f9996aaSopenharmony_ci        options,
2365f9996aaSopenharmony_ci        depfile_deps=direct_deps,
2375f9996aaSopenharmony_ci        input_paths=direct_deps,
2385f9996aaSopenharmony_ci        input_strings=input_strings,
2395f9996aaSopenharmony_ci        output_paths=([options.output]),
2405f9996aaSopenharmony_ci        force=False,
2415f9996aaSopenharmony_ci        add_pydeps=False)
2425f9996aaSopenharmony_ci
2435f9996aaSopenharmony_ci
2445f9996aaSopenharmony_ciif __name__ == '__main__':
2455f9996aaSopenharmony_ci    sys.exit(main())
246