#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (c) 2021 Huawei Device Co., Ltd. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys import argparse import os import json import copy sys.path.append( os.path.dirname(os.path.dirname(os.path.dirname( os.path.abspath(__file__))))) from scripts.util import build_utils # noqa E402 deps_metadta_cache = {} def get_all_deps(direct_deps): if direct_deps == []: return [] deps = copy.deepcopy(direct_deps) all_deps = set() all_deps.update(deps) while len(deps) > 0: dep = deps.pop(0) if dep not in deps_metadta_cache: with open(dep) as dep_fp: deps_metadta_cache[dep] = json.load(dep_fp).get('root') for n in deps_metadta_cache[dep].get('metadata_deps'): if n not in all_deps: deps.append(n) all_deps.add(n) return sorted(list(all_deps)) def get_deps_metadata(deps): return [deps_metadta_cache.get(d) for d in deps] def get_deps_of_type(deps_data, target_type): return [d for d in deps_data if d.get('type') == target_type] class Deps(object): def __init__(self, direct_deps): self.direct_deps = direct_deps self.all_deps = get_all_deps(direct_deps) self.all_deps_data = get_deps_metadata(self.all_deps) def all(self, target_type): return get_deps_of_type(self.all_deps_data, target_type) def write_meta_data(options, direct_deps): meta_data = { 'root': { 'type': options.type, 'metadata_path': options.output, 'metadata_deps': direct_deps } } root = meta_data['root'] if options.type == 'app_profile': root[options.type] = options.app_profile root['resources'] = options.resources if options.type == 'js_assets': root[options.type] = options.js_assets if options.js_forms: root['js_forms'] = options.js_forms if options.testrunner: root['testrunner'] = options.testrunner if options.type == 'ets_assets': root[options.type] = options.ets_assets if options.type == 'assets': root[options.type] = options.raw_assets if options.type == 'unresolved_assets': root[options.type] = options.unresolved_assets if options.type == 'resources': deps = Deps(direct_deps) root[options.type] = options.resources package_name = options.package_name root['package_name'] = package_name if package_name else "" for target_type in ['app_profile']: for dep in deps.all(target_type): if root.get(target_type): root.get(target_type).extend(dep[target_type]) root.get('resources').extend(dep['resources']) else: root[target_type] = dep[target_type] root['resources'] += dep['resources'] if options.type == 'hap' or options.type == 'resources': hap_profile = options.hap_profile root['hap_profile'] = hap_profile if hap_profile else "" # Merge all metadata if options.type == 'hap': deps = Deps(direct_deps) root['hap_path'] = options.hap_path for target_type in ['js_assets', 'ets_assets', 'assets', 'resources']: root[target_type] = [] if options.js_assets: root['js_assets'] = options.js_assets if options.ets_assets: root['ets_assets'] = options.ets_assets if options.raw_assets: root['assets'] = options.raw_assets if options.resources: root['resources'] = options.resources for target_type in ['js_assets', 'ets_assets', 'assets', 'resources', 'app_profile']: for dep in deps.all(target_type): if root.get(target_type): root.get(target_type).extend(dep[target_type]) root.get('hap_profile').extend(dep['hap_profile']) else: root[target_type] = dep[target_type] if dep.get('hap_profile'): root['hap_profile'] = dep['hap_profile'] if dep.get('js_forms'): root['js_forms'] = dep['js_forms'] if dep.get('testrunner'): root['testrunner'] = dep['testrunner'] target_type = 'unresolved_assets' for dep in deps.all(target_type): if options.js2abc: if isinstance(dep[target_type], list): for ability_path in dep[target_type]: root.get('js_assets').append(ability_path) else: root.get('js_assets').append(dep[target_type]) else: if isinstance(dep[target_type], list): for ability_path in dep[target_type]: root.get('ets_assets').append(ability_path) else: root.get('ets_assets').append(dep[target_type]) build_utils.write_json(meta_data, options.output, only_if_changed=True) # Collect assets entry according to config.json def load_assets(options, assets, assets_type): pre_path = assets[0] pre_path = pre_path.rstrip('/') with open(options.hap_profile) as profile: config = json.load(profile) # In multi-ability cases, load the assets entry according to "srcPath" in config.json if os.path.basename(pre_path) == 'js' or os.path.basename(pre_path) == 'ets': assets = [] for ability in config['module']['abilities']: if assets_type == 'js': if ability.__contains__('srcPath') and ability.get('srcLanguage') == assets_type: assets.append(os.path.join(pre_path, ability['srcPath'])) # Load js form entry according to "jsComponentName" in config.json if ability.__contains__('forms'): for form in ability['forms']: if form.__contains__('jsComponentName'): options.js_forms.append(os.path.join(pre_path, form['jsComponentName'])) else: raise Exception('"module.abilities.ability.forms.form.jsComponentName" is required') else: if ability.__contains__('srcPath'): assets.append(os.path.join(pre_path, ability['srcPath'])) else: pre_path = os.path.dirname(pre_path) # Load testrunner entry if config['module'].__contains__('testRunner') and assets_type == 'js': options.testrunner.append(os.path.join(pre_path, config['module']['testRunner']['srcPath'])) if not assets: assets.append(pre_path) return assets def main(): parser = argparse.ArgumentParser() parser.add_argument('--output', help='output meta data file', required=True) parser.add_argument('--type', help='type of module', required=True) parser.add_argument('--raw-assets', nargs='+', help='raw assets directory') parser.add_argument('--js-assets', nargs='+', help='js assets directory') parser.add_argument('--ets-assets', nargs='+', help='ets assets directory') parser.add_argument('--resources', nargs='+', help='resources directory') parser.add_argument('--hap-path', help='path to output hap') parser.add_argument('--depfile', help='path to .d file') parser.add_argument('--deps-metadata', nargs="+", help='metadata deps') parser.add_argument('--package-name', help='package name for hap resources') parser.add_argument('--hap-profile', help='path to hap profile') parser.add_argument('--app-profile', help='path to app profile') parser.add_argument('--unresolved-assets', nargs='+', help='unresolved assets directory') parser.add_argument('--js2abc', action='store_true', default=False, help='whether to transform js to ark bytecode') options = parser.parse_args() direct_deps = options.deps_metadata if options.deps_metadata else [] # js forms entry list options.js_forms = [] # testrunner entry list options.testrunner = [] if options.hap_profile: if options.js_assets: options.js_assets = load_assets(options, options.js_assets, 'js') if options.ets_assets: options.ets_assets = load_assets(options, options.ets_assets, 'ets') if options.unresolved_assets: options.unresolved_assets = load_assets(options, options.unresolved_assets, 'unresolved') possible_input_strings = [ options.type, options.raw_assets, options.js_assets, options.ets_assets, options.resources, options.hap_path, options.hap_profile, options.package_name, options.app_profile ] input_strings = [x for x in possible_input_strings if x] build_utils.call_and_write_depfile_if_stale( lambda: write_meta_data(options, direct_deps), options, depfile_deps=direct_deps, input_paths=direct_deps, input_strings=input_strings, output_paths=([options.output]), force=False, add_pydeps=False) if __name__ == '__main__': sys.exit(main())