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 151# Collect assets entry according to config.json 152def load_assets(options, assets, assets_type): 153 pre_path = assets[0] 154 pre_path = pre_path.rstrip('/') 155 with open(options.hap_profile) as profile: 156 config = json.load(profile) 157 158 # In multi-ability cases, load the assets entry according to "srcPath" in config.json 159 if os.path.basename(pre_path) == 'js' or os.path.basename(pre_path) == 'ets': 160 assets = [] 161 for ability in config['module']['abilities']: 162 if assets_type == 'js': 163 if ability.__contains__('srcPath') and ability.get('srcLanguage') == assets_type: 164 assets.append(os.path.join(pre_path, ability['srcPath'])) 165 166 # Load js form entry according to "jsComponentName" in config.json 167 if ability.__contains__('forms'): 168 for form in ability['forms']: 169 if form.__contains__('jsComponentName'): 170 options.js_forms.append(os.path.join(pre_path, form['jsComponentName'])) 171 else: 172 raise Exception('"module.abilities.ability.forms.form.jsComponentName" is required') 173 else: 174 if ability.__contains__('srcPath'): 175 assets.append(os.path.join(pre_path, ability['srcPath'])) 176 else: 177 pre_path = os.path.dirname(pre_path) 178 179 # Load testrunner entry 180 if config['module'].__contains__('testRunner') and assets_type == 'js': 181 options.testrunner.append(os.path.join(pre_path, config['module']['testRunner']['srcPath'])) 182 if not assets: 183 assets.append(pre_path) 184 return assets 185 186 187def main(): 188 parser = argparse.ArgumentParser() 189 190 parser.add_argument('--output', 191 help='output meta data file', 192 required=True) 193 parser.add_argument('--type', help='type of module', required=True) 194 parser.add_argument('--raw-assets', nargs='+', help='raw assets directory') 195 parser.add_argument('--js-assets', nargs='+', help='js assets directory') 196 parser.add_argument('--ets-assets', nargs='+', help='ets assets directory') 197 parser.add_argument('--resources', nargs='+', help='resources directory') 198 parser.add_argument('--hap-path', help='path to output hap') 199 parser.add_argument('--depfile', help='path to .d file') 200 parser.add_argument('--deps-metadata', nargs="+", help='metadata deps') 201 parser.add_argument('--package-name', 202 help='package name for hap resources') 203 parser.add_argument('--hap-profile', help='path to hap profile') 204 parser.add_argument('--app-profile', help='path to app profile') 205 parser.add_argument('--unresolved-assets', nargs='+', help='unresolved assets directory') 206 parser.add_argument('--js2abc', 207 action='store_true', 208 default=False, 209 help='whether to transform js to ark bytecode') 210 options = parser.parse_args() 211 direct_deps = options.deps_metadata if options.deps_metadata else [] 212 213 # js forms entry list 214 options.js_forms = [] 215 216 # testrunner entry list 217 options.testrunner = [] 218 219 if options.hap_profile: 220 if options.js_assets: 221 options.js_assets = load_assets(options, options.js_assets, 'js') 222 if options.ets_assets: 223 options.ets_assets = load_assets(options, options.ets_assets, 'ets') 224 if options.unresolved_assets: 225 options.unresolved_assets = load_assets(options, options.unresolved_assets, 'unresolved') 226 227 possible_input_strings = [ 228 options.type, options.raw_assets, options.js_assets, options.ets_assets, options.resources, 229 options.hap_path, options.hap_profile, options.package_name, options.app_profile 230 ] 231 input_strings = [x for x in possible_input_strings if x] 232 233 build_utils.call_and_write_depfile_if_stale( 234 lambda: write_meta_data(options, direct_deps), 235 options, 236 depfile_deps=direct_deps, 237 input_paths=direct_deps, 238 input_strings=input_strings, 239 output_paths=([options.output]), 240 force=False, 241 add_pydeps=False) 242 243 244if __name__ == '__main__': 245 sys.exit(main()) 246