1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# Copyright (c) 2021 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 sys 17import argparse 18import os 19import json 20import copy 21 22sys.path.append( 23 os.path.dirname(os.path.dirname(os.path.dirname( 24 os.path.abspath(__file__))))) 25from scripts.util import build_utils # noqa E402 26 27deps_metadta_cache = {} 28 29 30def get_all_deps(direct_deps): 31 if direct_deps == []: 32 return [] 33 deps = copy.deepcopy(direct_deps) 34 all_deps = set() 35 all_deps.update(deps) 36 while len(deps) > 0: 37 dep = deps.pop(0) 38 if dep not in deps_metadta_cache: 39 with open(dep) as dep_fp: 40 deps_metadta_cache[dep] = json.load(dep_fp).get('root') 41 for n in deps_metadta_cache[dep].get('metadata_deps'): 42 if n not in all_deps: 43 deps.append(n) 44 all_deps.add(n) 45 return sorted(list(all_deps)) 46 47 48def get_deps_metadata(deps): 49 return [deps_metadta_cache[d] for d in deps] 50 51 52def get_deps_of_type(deps_data, target_type): 53 return [d for d in deps_data if d['type'] == target_type] 54 55 56class Deps(object): 57 def __init__(self, direct_deps): 58 self.direct_deps = direct_deps 59 self.all_deps = get_all_deps(direct_deps) 60 self.all_deps_data = get_deps_metadata(self.all_deps) 61 62 def All(self, target_type): 63 return get_deps_of_type(self.all_deps_data, target_type) 64 65 66def write_meta_data(options, direct_deps): 67 meta_data = { 68 'root': { 69 'type': options.type, 70 'metadata_path': options.output, 71 'metadata_deps': direct_deps 72 } 73 } 74 root = meta_data['root'] 75 if options.type == 'app_profile': 76 root[options.type] = options.app_profile 77 root['resources'] = options.resources 78 if options.type == 'js_assets': 79 root[options.type] = options.js_assets 80 if options.js_forms: 81 root['js_forms'] = options.js_forms 82 if options.testrunner: 83 root['testrunner'] = options.testrunner 84 if options.type == 'ets_assets': 85 root[options.type] = options.ets_assets 86 if options.type == 'assets': 87 root[options.type] = options.raw_assets 88 if options.type == 'unresolved_assets': 89 root[options.type] = options.unresolved_assets 90 if options.type == 'resources': 91 deps = Deps(direct_deps) 92 root[options.type] = options.resources 93 package_name = options.package_name 94 root['package_name'] = package_name if package_name else "" 95 for target_type in ['app_profile']: 96 for dep in deps.All(target_type): 97 if root.get(target_type): 98 root.get(target_type).extend(dep[target_type]) 99 root.get('resources').extend(dep['resources']) 100 else: 101 root[target_type] = dep[target_type] 102 root['resources'] += dep['resources'] 103 if options.type == 'hap' or options.type == 'resources': 104 hap_profile = options.hap_profile 105 root['hap_profile'] = hap_profile if hap_profile else "" 106 107 # Merge all metadata 108 if options.type == 'hap': 109 deps = Deps(direct_deps) 110 root['hap_path'] = options.hap_path 111 for target_type in ['js_assets', 'ets_assets', 'assets', 'resources']: 112 root[target_type] = [] 113 if options.js_assets: 114 root['js_assets'] = options.js_assets 115 if options.ets_assets: 116 root['ets_assets'] = options.ets_assets 117 if options.raw_assets: 118 root['assets'] = options.raw_assets 119 if options.resources: 120 root['resources'] = options.resources 121 for target_type in ['js_assets', 'ets_assets', 'assets', 'resources', 'app_profile']: 122 for dep in deps.All(target_type): 123 if root.get(target_type): 124 root.get(target_type).extend(dep[target_type]) 125 root.get('hap_profile').extend(dep['hap_profile']) 126 else: 127 root[target_type] = dep[target_type] 128 if dep.get('hap_profile'): 129 root['hap_profile'] = dep['hap_profile'] 130 if dep.get('js_forms'): 131 root['js_forms'] = dep['js_forms'] 132 if dep.get('testrunner'): 133 root['testrunner'] = dep['testrunner'] 134 target_type = 'unresolved_assets' 135 for dep in deps.All(target_type): 136 if options.js2abc: 137 if isinstance(dep[target_type], list): 138 for ability_path in dep[target_type]: 139 root.get('js_assets').append(ability_path) 140 else: 141 root.get('js_assets').append(dep[target_type]) 142 else: 143 if isinstance(dep[target_type], list): 144 for ability_path in dep[target_type]: 145 root.get('ets_assets').append(ability_path) 146 else: 147 root.get('ets_assets').append(dep[target_type]) 148 build_utils.write_json(meta_data, options.output, only_if_changed=True) 149 150# Collect assets entry according to config.json 151def load_assets(options, assets, assets_type): 152 pre_path = assets[0] 153 with open(options.hap_profile) as profile: 154 config = json.load(profile) 155 156 # In multi-ability cases, load the assets entry according to "srcPath" in config.json 157 if os.path.basename(pre_path) == 'js' or os.path.basename(pre_path) == 'ets': 158 assets = [] 159 for ability in config['module']['abilities']: 160 if assets_type == 'js': 161 if ability.__contains__('srcPath') and ability.get('srcLanguage') == assets_type: 162 assets.append(os.path.join(pre_path, ability['srcPath'])) 163 164 # Load js form entry according to "jsComponentName" in config.json 165 if ability.__contains__('forms'): 166 for form in ability['forms']: 167 if form.__contains__('jsComponentName'): 168 options.js_forms.append(os.path.join(pre_path, form['jsComponentName'])) 169 else: 170 raise Exception('"module.abilities.ability.forms.form.jsComponentName" is required') 171 else: 172 if ability.__contains__('srcPath'): 173 assets.append(os.path.join(pre_path, ability['srcPath'])) 174 else: 175 pre_path = os.path.dirname(pre_path) 176 177 # Load testrunner entry 178 if config['module'].__contains__('testRunner') and assets_type == 'js': 179 options.testrunner.append(os.path.join(pre_path, config['module']['testRunner']['srcPath'])) 180 if not assets: 181 assets.append(pre_path) 182 return assets 183 184def main(): 185 parser = argparse.ArgumentParser() 186 187 parser.add_argument('--output', 188 help='output meta data file', 189 required=True) 190 parser.add_argument('--type', help='type of module', required=True) 191 parser.add_argument('--raw-assets', nargs='+', help='raw assets directory') 192 parser.add_argument('--js-assets', nargs='+', help='js assets directory') 193 parser.add_argument('--ets-assets', nargs='+', help='ets assets directory') 194 parser.add_argument('--resources', nargs='+', help='resources directory') 195 parser.add_argument('--hap-path', help='path to output hap') 196 parser.add_argument('--depfile', help='path to .d file') 197 parser.add_argument('--deps-metadata', nargs="+", help='metadata deps') 198 parser.add_argument('--package-name', 199 help='package name for hap resources') 200 parser.add_argument('--hap-profile', help='path to hap profile') 201 parser.add_argument('--app-profile', help='path to app profile') 202 parser.add_argument('--unresolved-assets', nargs='+', help='unresolved assets directory') 203 parser.add_argument('--js2abc', 204 action='store_true', 205 default=False, 206 help='whether to transform js to ark bytecode') 207 options = parser.parse_args() 208 direct_deps = options.deps_metadata if options.deps_metadata else [] 209 210 # js forms entry list 211 options.js_forms = [] 212 213 # testrunner entry list 214 options.testrunner = [] 215 216 if options.hap_profile: 217 if options.js_assets: 218 options.js_assets = load_assets(options, options.js_assets, 'js') 219 if options.ets_assets: 220 options.ets_assets = load_assets(options, options.ets_assets, 'ets') 221 if options.unresolved_assets: 222 options.unresolved_assets = load_assets(options, options.unresolved_assets, 'unresolved') 223 224 possible_input_strings = [ 225 options.type, options.raw_assets, options.js_assets, options.ets_assets, options.resources, 226 options.hap_path, options.hap_profile, options.package_name, options.app_profile 227 ] 228 input_strings = [x for x in possible_input_strings if x] 229 230 build_utils.call_and_write_depfile_if_stale( 231 lambda: write_meta_data(options, direct_deps), 232 options, 233 depfile_deps=direct_deps, 234 input_paths=direct_deps, 235 input_strings=input_strings, 236 output_paths=([options.output]), 237 force=False, 238 add_pydeps=False) 239 240 241if __name__ == '__main__': 242 sys.exit(main()) 243