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 optparse 175f9996aaSopenharmony_ciimport os 185f9996aaSopenharmony_ciimport sys 195f9996aaSopenharmony_ciimport json 205f9996aaSopenharmony_ci 215f9996aaSopenharmony_cifrom zipfile import ZipFile # noqa: E402 225f9996aaSopenharmony_cifrom util import build_utils # noqa: E402 235f9996aaSopenharmony_ci 245f9996aaSopenharmony_ci 255f9996aaSopenharmony_cidef parse_args(args): 265f9996aaSopenharmony_ci args = build_utils.expand_file_args(args) 275f9996aaSopenharmony_ci 285f9996aaSopenharmony_ci parser = optparse.OptionParser() 295f9996aaSopenharmony_ci build_utils.add_depfile_option(parser) 305f9996aaSopenharmony_ci parser.add_option('--output', help='stamp file') 315f9996aaSopenharmony_ci parser.add_option('--js-assets-dir', help='js assets directory') 325f9996aaSopenharmony_ci parser.add_option('--ets-assets-dir', help='ets assets directory') 335f9996aaSopenharmony_ci parser.add_option('--js-forms-dir', help='js forms directory') 345f9996aaSopenharmony_ci parser.add_option('--testrunner-dir', help='testrunner directory') 355f9996aaSopenharmony_ci parser.add_option('--nodejs-path', help='path to nodejs app') 365f9996aaSopenharmony_ci parser.add_option('--webpack-js', help='path to js webpack.js') 375f9996aaSopenharmony_ci parser.add_option('--webpack-ets', help='path to ets webpack.js') 385f9996aaSopenharmony_ci parser.add_option('--webpack-config-js', help='path to webpack.config.js') 395f9996aaSopenharmony_ci parser.add_option('--webpack-config-ets', help='path to webpack.rich.config.js') 405f9996aaSopenharmony_ci parser.add_option('--hap-profile', help='path to hap profile') 415f9996aaSopenharmony_ci parser.add_option('--build-mode', help='debug mode or release mode') 425f9996aaSopenharmony_ci parser.add_option('--js-sources-file', help='path to js sources file') 435f9996aaSopenharmony_ci parser.add_option('--js2abc', 445f9996aaSopenharmony_ci action='store_true', 455f9996aaSopenharmony_ci default=False, 465f9996aaSopenharmony_ci help='whether to transform js to ark bytecode') 475f9996aaSopenharmony_ci parser.add_option('--ets2abc', 485f9996aaSopenharmony_ci action='store_true', 495f9996aaSopenharmony_ci default=False, 505f9996aaSopenharmony_ci help='whether to transform ets to ark bytecode') 515f9996aaSopenharmony_ci parser.add_option('--ark-es2abc-dir', help='path to ark es2abc dir') 525f9996aaSopenharmony_ci parser.add_option('--ace-loader-home', help='path to ace-loader dir.') 535f9996aaSopenharmony_ci parser.add_option('--ets-loader-home', help='path to ets-loader dir.') 545f9996aaSopenharmony_ci parser.add_option('--app-profile', default=False, help='path to app-profile.') 555f9996aaSopenharmony_ci parser.add_option('--manifest-file-path', help='path to manifest.json dir.') 565f9996aaSopenharmony_ci 575f9996aaSopenharmony_ci options, _ = parser.parse_args(args) 585f9996aaSopenharmony_ci options.js_assets_dir = build_utils.parse_gn_list(options.js_assets_dir) 595f9996aaSopenharmony_ci options.ets_assets_dir = build_utils.parse_gn_list(options.ets_assets_dir) 605f9996aaSopenharmony_ci options.js_forms_dir = build_utils.parse_gn_list(options.js_forms_dir) 615f9996aaSopenharmony_ci options.testrunner_dir = build_utils.parse_gn_list(options.testrunner_dir) 625f9996aaSopenharmony_ci return options 635f9996aaSopenharmony_ci 645f9996aaSopenharmony_ci 655f9996aaSopenharmony_cidef make_my_env(options, js2abc: bool) -> dict: 665f9996aaSopenharmony_ci out_dir = os.path.abspath(os.path.dirname(options.output)) 675f9996aaSopenharmony_ci gen_dir = os.path.join(out_dir, "gen") 685f9996aaSopenharmony_ci assets_dir = os.path.join(out_dir, "assets") 695f9996aaSopenharmony_ci if options.app_profile: 705f9996aaSopenharmony_ci if js2abc: 715f9996aaSopenharmony_ci assets_dir = os.path.join(assets_dir, "js") 725f9996aaSopenharmony_ci else: 735f9996aaSopenharmony_ci assets_dir = os.path.join(assets_dir, "ets") 745f9996aaSopenharmony_ci my_env = { 755f9996aaSopenharmony_ci "aceModuleBuild": assets_dir, 765f9996aaSopenharmony_ci "buildMode": options.build_mode, 775f9996aaSopenharmony_ci "PATH": os.environ.get('PATH'), 785f9996aaSopenharmony_ci "appResource": os.path.join(gen_dir, "ResourceTable.txt") 795f9996aaSopenharmony_ci } 805f9996aaSopenharmony_ci if options.app_profile: 815f9996aaSopenharmony_ci my_env["aceProfilePath"] = os.path.join(gen_dir, "resources/base/profile") 825f9996aaSopenharmony_ci my_env["aceModuleJsonPath"] = os.path.abspath(options.hap_profile) 835f9996aaSopenharmony_ci return my_env 845f9996aaSopenharmony_ci 855f9996aaSopenharmony_ci 865f9996aaSopenharmony_cidef make_manifest_data(config: dict, options, js2abc: bool, asset_index: int, assets_cnt: int, src_path: str) -> dict: 875f9996aaSopenharmony_ci data = dict() 885f9996aaSopenharmony_ci data['appID'] = config['app']['bundleName'] 895f9996aaSopenharmony_ci if options.app_profile: 905f9996aaSopenharmony_ci data['versionName'] = config['app']['versionName'] 915f9996aaSopenharmony_ci data['versionCode'] = config['app']['versionCode'] 925f9996aaSopenharmony_ci data['pages'] = config['module']['pages'] 935f9996aaSopenharmony_ci data['deviceType'] = config['module']['deviceTypes'] 945f9996aaSopenharmony_ci else: 955f9996aaSopenharmony_ci data['appName'] = config['module']['abilities'][asset_index].get('label') 965f9996aaSopenharmony_ci data['versionName'] = config['app']['version']['name'] 975f9996aaSopenharmony_ci data['versionCode'] = config['app']['version']['code'] 985f9996aaSopenharmony_ci data['deviceType'] = config['module']['deviceType'] 995f9996aaSopenharmony_ci for js_module in config['module']['js']: 1005f9996aaSopenharmony_ci js_module_name = js_module.get('name').split('.')[-1] 1015f9996aaSopenharmony_ci 1025f9996aaSopenharmony_ci # According to the page name and ability entry match the corresponding page for ability 1035f9996aaSopenharmony_ci # Compatibility with mismatches due to "MainAbility" and "default" 1045f9996aaSopenharmony_ci if js_module_name == src_path or (js_module_name == 'MainAbility' and src_path == 'default') \ 1055f9996aaSopenharmony_ci or (js_module_name == 'default' and src_path == 'MainAbility'): 1065f9996aaSopenharmony_ci data['pages'] = js_module.get('pages') 1075f9996aaSopenharmony_ci data['window'] = js_module.get('window') 1085f9996aaSopenharmony_ci if js_module.get('type') == 'form' and options.js_forms_dir: 1095f9996aaSopenharmony_ci data['type'] = 'form' 1105f9996aaSopenharmony_ci if not js2abc: 1115f9996aaSopenharmony_ci data['mode'] = js_module.get('mode') 1125f9996aaSopenharmony_ci return data 1135f9996aaSopenharmony_ci 1145f9996aaSopenharmony_ci 1155f9996aaSopenharmony_cidef build_ace(cmd: str, options, js2abc: bool, loader_home: str, assets_dir: str, assets_name: str): 1165f9996aaSopenharmony_ci my_env = make_my_env(options, js2abc) 1175f9996aaSopenharmony_ci gen_dir = my_env.get("aceModuleBuild") 1185f9996aaSopenharmony_ci assets_cnt = len(assets_dir) 1195f9996aaSopenharmony_ci use_compile_cache = os.environ.get("USE_COMPILE_CACHE", "false").lower() == "true" 1205f9996aaSopenharmony_ci for asset_index in range(assets_cnt): 1215f9996aaSopenharmony_ci ability_dir = os.path.relpath(assets_dir[asset_index], loader_home) 1225f9996aaSopenharmony_ci my_env["aceModuleRoot"] = ability_dir 1235f9996aaSopenharmony_ci if options.js_sources_file: 1245f9996aaSopenharmony_ci with open(options.js_sources_file, 'wb') as js_sources_file: 1255f9996aaSopenharmony_ci sources = get_all_js_sources(ability_dir) 1265f9996aaSopenharmony_ci js_sources_file.write('\n'.join(sources).encode()) 1275f9996aaSopenharmony_ci src_path = os.path.basename(assets_dir[asset_index]) 1285f9996aaSopenharmony_ci 1295f9996aaSopenharmony_ci # Create a fixed directory for manifest.json 1305f9996aaSopenharmony_ci if js2abc: 1315f9996aaSopenharmony_ci build_dir = os.path.abspath(os.path.join(options.manifest_file_path, 'js', src_path)) 1325f9996aaSopenharmony_ci my_env.update({"cachePath": os.path.join(build_dir, ".cache")}) 1335f9996aaSopenharmony_ci else: 1345f9996aaSopenharmony_ci build_dir = os.path.abspath(os.path.join(options.manifest_file_path, 'ets', src_path)) 1355f9996aaSopenharmony_ci if not os.path.exists(build_dir): 1365f9996aaSopenharmony_ci os.makedirs(build_dir, exist_ok=True) 1375f9996aaSopenharmony_ci manifest = os.path.join(build_dir, 'manifest.json') 1385f9996aaSopenharmony_ci 1395f9996aaSopenharmony_ci # Determine abilityType according to config.json 1405f9996aaSopenharmony_ci if assets_name == 'testrunner_dir': 1415f9996aaSopenharmony_ci my_env["abilityType"] = 'testrunner' 1425f9996aaSopenharmony_ci elif assets_name != 'js_forms_dir' and not options.app_profile and assets_cnt > 1: 1435f9996aaSopenharmony_ci with open(options.hap_profile) as profile: 1445f9996aaSopenharmony_ci config = json.load(profile) 1455f9996aaSopenharmony_ci if config['module']['abilities'][asset_index].__contains__('forms'): 1465f9996aaSopenharmony_ci my_env["abilityType"] = 'form' 1475f9996aaSopenharmony_ci else: 1485f9996aaSopenharmony_ci my_env["abilityType"] = config['module']['abilities'][asset_index]['type'] 1495f9996aaSopenharmony_ci else: 1505f9996aaSopenharmony_ci my_env["abilityType"] = 'page' 1515f9996aaSopenharmony_ci 1525f9996aaSopenharmony_ci # Generate manifest.json only when abilityType is page 1535f9996aaSopenharmony_ci data = dict() 1545f9996aaSopenharmony_ci if my_env["abilityType"] == 'page': 1555f9996aaSopenharmony_ci with open(options.hap_profile) as profile: 1565f9996aaSopenharmony_ci config = json.load(profile) 1575f9996aaSopenharmony_ci data = make_manifest_data(config, options, js2abc, asset_index, assets_cnt, src_path) 1585f9996aaSopenharmony_ci build_utils.write_json(data, manifest) 1595f9996aaSopenharmony_ci 1605f9996aaSopenharmony_ci # If missing page, skip it 1615f9996aaSopenharmony_ci if not data.__contains__('pages'): 1625f9996aaSopenharmony_ci print('Warning: There is no page matching this {}'.format(src_path)) 1635f9996aaSopenharmony_ci continue 1645f9996aaSopenharmony_ci 1655f9996aaSopenharmony_ci if not options.app_profile: 1665f9996aaSopenharmony_ci my_env["aceManifestPath"] = manifest 1675f9996aaSopenharmony_ci my_env["aceModuleBuild"] = os.path.join(gen_dir, src_path) 1685f9996aaSopenharmony_ci 1695f9996aaSopenharmony_ci enable_compile_cache(asset_index, assets_cnt, my_env, use_compile_cache) 1705f9996aaSopenharmony_ci build_utils.check_output(cmd, cwd=loader_home, env=my_env) 1715f9996aaSopenharmony_ci 1725f9996aaSopenharmony_ci if options.app_profile: 1735f9996aaSopenharmony_ci gen_dir = os.path.dirname(gen_dir) 1745f9996aaSopenharmony_ci build_utils.zip_dir(options.output, gen_dir) 1755f9996aaSopenharmony_ci else: 1765f9996aaSopenharmony_ci build_utils.zip_dir(options.output, gen_dir, zip_prefix_path='assets/js/') 1775f9996aaSopenharmony_ci 1785f9996aaSopenharmony_ci 1795f9996aaSopenharmony_cidef enable_compile_cache(asset_index: int, assets_cnt: int, env: dict, use_compile_cache: bool): 1805f9996aaSopenharmony_ci if use_compile_cache: 1815f9996aaSopenharmony_ci env["useCompileCache"] = "true" 1825f9996aaSopenharmony_ci if assets_cnt > 1 and asset_index == assets_cnt - 1: 1835f9996aaSopenharmony_ci env["addTestRunner"] = "true" 1845f9996aaSopenharmony_ci 1855f9996aaSopenharmony_ci 1865f9996aaSopenharmony_cidef get_all_js_sources(base) -> list: 1875f9996aaSopenharmony_ci sources = [] 1885f9996aaSopenharmony_ci for root, _, files in os.walk(base): 1895f9996aaSopenharmony_ci for file in files: 1905f9996aaSopenharmony_ci if file[-3:] in ('.js', '.ts'): 1915f9996aaSopenharmony_ci sources.append(os.path.join(root, file)) 1925f9996aaSopenharmony_ci 1935f9996aaSopenharmony_ci return sources 1945f9996aaSopenharmony_ci 1955f9996aaSopenharmony_ci 1965f9996aaSopenharmony_cidef main(args): 1975f9996aaSopenharmony_ci options = parse_args(args) 1985f9996aaSopenharmony_ci 1995f9996aaSopenharmony_ci inputs = [ 2005f9996aaSopenharmony_ci options.nodejs_path, options.webpack_js, options.webpack_ets, 2015f9996aaSopenharmony_ci options.webpack_config_js, options.webpack_config_ets 2025f9996aaSopenharmony_ci ] 2035f9996aaSopenharmony_ci depfiles = [] 2045f9996aaSopenharmony_ci if not options.js_assets_dir and not options.ets_assets_dir: 2055f9996aaSopenharmony_ci with ZipFile(options.output, 'w') as file: 2065f9996aaSopenharmony_ci return 2075f9996aaSopenharmony_ci 2085f9996aaSopenharmony_ci if options.ark_es2abc_dir: 2095f9996aaSopenharmony_ci depfiles.extend(build_utils.get_all_files(options.ark_es2abc_dir)) 2105f9996aaSopenharmony_ci 2115f9996aaSopenharmony_ci depfiles.append(options.webpack_js) 2125f9996aaSopenharmony_ci depfiles.append(options.webpack_ets) 2135f9996aaSopenharmony_ci depfiles.append(options.webpack_config_js) 2145f9996aaSopenharmony_ci depfiles.append(options.webpack_config_ets) 2155f9996aaSopenharmony_ci depfiles.extend(build_utils.get_all_files(options.ace_loader_home)) 2165f9996aaSopenharmony_ci depfiles.extend(build_utils.get_all_files(options.ets_loader_home)) 2175f9996aaSopenharmony_ci 2185f9996aaSopenharmony_ci node_js = os.path.relpath(options.nodejs_path, options.ace_loader_home) 2195f9996aaSopenharmony_ci assets_dict = dict() 2205f9996aaSopenharmony_ci if options.js_assets_dir: 2215f9996aaSopenharmony_ci assets_dict['js_assets_dir'] = options.js_assets_dir 2225f9996aaSopenharmony_ci if options.ets_assets_dir: 2235f9996aaSopenharmony_ci assets_dict['ets_assets_dir'] = options.ets_assets_dir 2245f9996aaSopenharmony_ci if options.js_forms_dir: 2255f9996aaSopenharmony_ci assets_dict['js_forms_dir'] = options.js_forms_dir 2265f9996aaSopenharmony_ci if options.testrunner_dir: 2275f9996aaSopenharmony_ci assets_dict['testrunner_dir'] = options.testrunner_dir 2285f9996aaSopenharmony_ci 2295f9996aaSopenharmony_ci for assets_name, assets_dir in assets_dict.items(): 2305f9996aaSopenharmony_ci for asset in assets_dir: 2315f9996aaSopenharmony_ci depfiles.extend(build_utils.get_all_files(asset)) 2325f9996aaSopenharmony_ci if assets_name == 'ets_assets_dir': 2335f9996aaSopenharmony_ci js2abc = False 2345f9996aaSopenharmony_ci loader_home = options.ets_loader_home 2355f9996aaSopenharmony_ci webpack_config = options.webpack_config_ets 2365f9996aaSopenharmony_ci webpack_path = options.webpack_ets 2375f9996aaSopenharmony_ci else: 2385f9996aaSopenharmony_ci js2abc = True 2395f9996aaSopenharmony_ci loader_home = options.ace_loader_home 2405f9996aaSopenharmony_ci webpack_config = options.webpack_config_js 2415f9996aaSopenharmony_ci webpack_path = options.webpack_js 2425f9996aaSopenharmony_ci cmd = [ 2435f9996aaSopenharmony_ci node_js, 2445f9996aaSopenharmony_ci os.path.relpath(webpack_path, loader_home), 2455f9996aaSopenharmony_ci '--config', 2465f9996aaSopenharmony_ci os.path.relpath(webpack_config, loader_home) 2475f9996aaSopenharmony_ci ] 2485f9996aaSopenharmony_ci ark_es2abc_dir = os.path.relpath(options.ark_es2abc_dir, loader_home) 2495f9996aaSopenharmony_ci if options.app_profile: 2505f9996aaSopenharmony_ci cmd.extend(['--env', 'buildMode={}'.format(options.build_mode), 'compilerType=ark', 2515f9996aaSopenharmony_ci 'arkFrontendDir={}'.format(ark_es2abc_dir), 'nodeJs={}'.format(node_js)]) 2525f9996aaSopenharmony_ci else: 2535f9996aaSopenharmony_ci cmd.extend(['--env', 'compilerType=ark', 2545f9996aaSopenharmony_ci 'arkFrontendDir={}'.format(ark_es2abc_dir), 'nodeJs={}'.format(node_js)]) 2555f9996aaSopenharmony_ci build_utils.call_and_write_depfile_if_stale( 2565f9996aaSopenharmony_ci lambda: build_ace(cmd, options, js2abc, loader_home, assets_dir, assets_name), 2575f9996aaSopenharmony_ci options, 2585f9996aaSopenharmony_ci depfile_deps=depfiles, 2595f9996aaSopenharmony_ci input_paths=depfiles + inputs, 2605f9996aaSopenharmony_ci input_strings=cmd + [options.build_mode], 2615f9996aaSopenharmony_ci output_paths=([options.output]), 2625f9996aaSopenharmony_ci force=False, 2635f9996aaSopenharmony_ci add_pydeps=False) 2645f9996aaSopenharmony_ci 2655f9996aaSopenharmony_ciif __name__ == '__main__': 2665f9996aaSopenharmony_ci sys.exit(main(sys.argv[1:])) 267