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 subprocess 185f9996aaSopenharmony_ciimport sys 195f9996aaSopenharmony_ciimport shutil 205f9996aaSopenharmony_ciimport os 215f9996aaSopenharmony_ciimport tempfile 225f9996aaSopenharmony_ciimport json 235f9996aaSopenharmony_cifrom util import build_utils # noqa: E402 245f9996aaSopenharmony_ci 255f9996aaSopenharmony_ci 265f9996aaSopenharmony_cidef sign_hap(options, unsigned_hap_path: str, signed_hap_path: str): 275f9996aaSopenharmony_ci cmd = ['python3', options.sign_hap_py_path] 285f9996aaSopenharmony_ci cmd.extend(['--hapsigner', options.hapsigner]) 295f9996aaSopenharmony_ci cmd.extend(['--sign-algo', options.sign_algo]) 305f9996aaSopenharmony_ci cmd.extend(['--keyalias', options.keyalias]) 315f9996aaSopenharmony_ci cmd.extend(['--inFile', unsigned_hap_path]) 325f9996aaSopenharmony_ci cmd.extend(['--outFile', signed_hap_path]) 335f9996aaSopenharmony_ci cmd.extend(['--profileFile', options.certificate_profile]) 345f9996aaSopenharmony_ci cmd.extend(['--keystoreFile', options.keystore_path]) 355f9996aaSopenharmony_ci cmd.extend(['--keystorePwd', options.keystorepasswd]) 365f9996aaSopenharmony_ci cmd.extend(['--keyPwd', options.private_key_path]) 375f9996aaSopenharmony_ci cmd.extend(['--certificate-file', options.certificate_file]) 385f9996aaSopenharmony_ci cmd.extend(['--profileSigned', '1']) 395f9996aaSopenharmony_ci cmd.extend(['--inForm', 'zip']) 405f9996aaSopenharmony_ci cmd.extend(['--compatible_version', options.sign_compatible_version]) 415f9996aaSopenharmony_ci child = subprocess.Popen(cmd, 425f9996aaSopenharmony_ci stdout=subprocess.PIPE, 435f9996aaSopenharmony_ci stderr=subprocess.PIPE) 445f9996aaSopenharmony_ci stdout, stderr = child.communicate() 455f9996aaSopenharmony_ci if child.returncode: 465f9996aaSopenharmony_ci print(stdout.decode(), stderr.decode()) 475f9996aaSopenharmony_ci raise Exception("Failed to sign hap {}.".format(options.sign_hap_py_path)) 485f9996aaSopenharmony_ci 495f9996aaSopenharmony_ci 505f9996aaSopenharmony_cidef add_resources(packaged_resources: list, package_dir: str, packing_cmd: list): 515f9996aaSopenharmony_ci if packaged_resources: 525f9996aaSopenharmony_ci build_utils.extract_all(packaged_resources, 535f9996aaSopenharmony_ci package_dir, 545f9996aaSopenharmony_ci no_clobber=False) 555f9996aaSopenharmony_ci index_file_path = os.path.join(package_dir, 'resources.index') 565f9996aaSopenharmony_ci if os.path.exists(index_file_path): 575f9996aaSopenharmony_ci packing_cmd.extend(['--index-path', index_file_path]) 585f9996aaSopenharmony_ci resources_path = os.path.join(package_dir, 'resources') 595f9996aaSopenharmony_ci if os.path.exists(resources_path): 605f9996aaSopenharmony_ci packing_cmd.extend(['--resources-path', resources_path]) 615f9996aaSopenharmony_ci 625f9996aaSopenharmony_ci 635f9996aaSopenharmony_cidef add_assets(options, package_dir: str, packing_cmd: list): 645f9996aaSopenharmony_ci packaged_js_assets, assets = options.packaged_js_assets, options.assets 655f9996aaSopenharmony_ci if options.app_profile: 665f9996aaSopenharmony_ci assets_dir = os.path.join(package_dir, 'ets') 675f9996aaSopenharmony_ci js_assets_dir = os.path.join(package_dir, 'js') 685f9996aaSopenharmony_ci else: 695f9996aaSopenharmony_ci assets_dir = os.path.join(package_dir, 'assets') 705f9996aaSopenharmony_ci 715f9996aaSopenharmony_ci if packaged_js_assets: 725f9996aaSopenharmony_ci build_utils.extract_all(packaged_js_assets, 735f9996aaSopenharmony_ci package_dir, 745f9996aaSopenharmony_ci no_clobber=False) 755f9996aaSopenharmony_ci if options.build_mode == "release": 765f9996aaSopenharmony_ci for root, _, files in os.walk(assets_dir): 775f9996aaSopenharmony_ci for f in files: 785f9996aaSopenharmony_ci filename = os.path.join(root, f) 795f9996aaSopenharmony_ci if filename.endswith('.js.map'): 805f9996aaSopenharmony_ci os.unlink(filename) 815f9996aaSopenharmony_ci if assets: 825f9996aaSopenharmony_ci if not os.path.exists(assets_dir): 835f9996aaSopenharmony_ci os.mkdir(assets_dir) 845f9996aaSopenharmony_ci for item in assets: 855f9996aaSopenharmony_ci if os.path.isfile(item): 865f9996aaSopenharmony_ci shutil.copyfile( 875f9996aaSopenharmony_ci item, os.path.join(assets_dir, os.path.basename(item))) 885f9996aaSopenharmony_ci elif os.path.isdir(item): 895f9996aaSopenharmony_ci shutil.copytree( 905f9996aaSopenharmony_ci item, os.path.join(assets_dir, os.path.basename(item))) 915f9996aaSopenharmony_ci if os.path.exists(assets_dir) and len(os.listdir(assets_dir)) != 0: 925f9996aaSopenharmony_ci if options.app_profile: 935f9996aaSopenharmony_ci packing_cmd.extend(['--ets-path', assets_dir]) 945f9996aaSopenharmony_ci else: 955f9996aaSopenharmony_ci packing_cmd.extend(['--assets-path', assets_dir]) 965f9996aaSopenharmony_ci if options.app_profile: 975f9996aaSopenharmony_ci if os.path.exists(js_assets_dir) and len(os.listdir(js_assets_dir)) != 0: 985f9996aaSopenharmony_ci packing_cmd.extend(['--js-path', js_assets_dir]) 995f9996aaSopenharmony_ci 1005f9996aaSopenharmony_ci 1015f9996aaSopenharmony_cidef get_ark_toolchain_version(options): 1025f9996aaSopenharmony_ci cmd = [options.nodejs_path, options.js2abc_js, '--bc-version'] 1035f9996aaSopenharmony_ci return build_utils.check_output(cmd).strip('\n') 1045f9996aaSopenharmony_ci 1055f9996aaSopenharmony_ci 1065f9996aaSopenharmony_cidef tweak_hap_profile(options, package_dir: str): 1075f9996aaSopenharmony_ci config_name = 'config.json' 1085f9996aaSopenharmony_ci if options.app_profile: 1095f9996aaSopenharmony_ci config_name = 'module.json' 1105f9996aaSopenharmony_ci hap_profile = os.path.join(package_dir, config_name) 1115f9996aaSopenharmony_ci if not os.path.exists(hap_profile): 1125f9996aaSopenharmony_ci raise Exception('Error: {} of hap file not exists'.format(config_name)) 1135f9996aaSopenharmony_ci config = {} 1145f9996aaSopenharmony_ci with open(hap_profile, 'r') as fileobj: 1155f9996aaSopenharmony_ci config = json.load(fileobj) 1165f9996aaSopenharmony_ci if options.app_profile: 1175f9996aaSopenharmony_ci config.get('module')['virtualMachine'] = 'ark{}'.format( 1185f9996aaSopenharmony_ci get_ark_toolchain_version(options)) 1195f9996aaSopenharmony_ci else: 1205f9996aaSopenharmony_ci config.get('module').get('distro')['virtualMachine'] = 'ark{}'.format( 1215f9996aaSopenharmony_ci get_ark_toolchain_version(options)) 1225f9996aaSopenharmony_ci build_utils.write_json(config, hap_profile) 1235f9996aaSopenharmony_ci 1245f9996aaSopenharmony_ci 1255f9996aaSopenharmony_cidef create_hap(options, signed_hap: str): 1265f9996aaSopenharmony_ci with build_utils.temp_dir() as package_dir, tempfile.NamedTemporaryFile( 1275f9996aaSopenharmony_ci suffix='.hap') as output: 1285f9996aaSopenharmony_ci packing_cmd = ['java', '-jar', options.hap_packing_tool] 1295f9996aaSopenharmony_ci packing_cmd.extend( 1305f9996aaSopenharmony_ci ['--mode', 'hap', '--force', 'true', '--out-path', output.name]) 1315f9996aaSopenharmony_ci 1325f9996aaSopenharmony_ci hap_profile_path = os.path.join(package_dir, 1335f9996aaSopenharmony_ci os.path.basename(options.hap_profile)) 1345f9996aaSopenharmony_ci shutil.copy(options.hap_profile, hap_profile_path) 1355f9996aaSopenharmony_ci packing_cmd.extend(['--json-path', hap_profile_path]) 1365f9996aaSopenharmony_ci add_assets(options, package_dir, packing_cmd) 1375f9996aaSopenharmony_ci 1385f9996aaSopenharmony_ci add_resources(options.packaged_resources, package_dir, packing_cmd) 1395f9996aaSopenharmony_ci if options.enable_ark: 1405f9996aaSopenharmony_ci tweak_hap_profile(options, package_dir) 1415f9996aaSopenharmony_ci if options.dso: 1425f9996aaSopenharmony_ci lib_path = os.path.join(package_dir, "lib") 1435f9996aaSopenharmony_ci hap_lib_path = os.path.join(lib_path, options.ohos_app_abi) 1445f9996aaSopenharmony_ci os.makedirs(hap_lib_path, exist_ok=True) 1455f9996aaSopenharmony_ci for dso in sorted(options.dso): 1465f9996aaSopenharmony_ci shutil.copy(dso, hap_lib_path) 1475f9996aaSopenharmony_ci packing_cmd.extend(['--lib-path', lib_path]) 1485f9996aaSopenharmony_ci 1495f9996aaSopenharmony_ci build_utils.check_output(packing_cmd) 1505f9996aaSopenharmony_ci 1515f9996aaSopenharmony_ci sign_hap(options, output.name, signed_hap) 1525f9996aaSopenharmony_ci 1535f9996aaSopenharmony_ci 1545f9996aaSopenharmony_cidef parse_args(args): 1555f9996aaSopenharmony_ci args = build_utils.expand_file_args(args) 1565f9996aaSopenharmony_ci 1575f9996aaSopenharmony_ci parser = optparse.OptionParser() 1585f9996aaSopenharmony_ci build_utils.add_depfile_option(parser) 1595f9996aaSopenharmony_ci parser.add_option('--hap-path', help='path to output hap') 1605f9996aaSopenharmony_ci parser.add_option('--hapsigner', help='path to signer') 1615f9996aaSopenharmony_ci parser.add_option('--assets', help='path to assets') 1625f9996aaSopenharmony_ci parser.add_option('--dso', 1635f9996aaSopenharmony_ci action="append", 1645f9996aaSopenharmony_ci help='path to dynamic shared objects') 1655f9996aaSopenharmony_ci parser.add_option('--ohos-app-abi', help='ohos app abi') 1665f9996aaSopenharmony_ci parser.add_option('--hap-profile', help='path to hap profile') 1675f9996aaSopenharmony_ci parser.add_option('--nodejs-path', help='path to node') 1685f9996aaSopenharmony_ci parser.add_option('--js2abc-js', help='path to ts2abc.js') 1695f9996aaSopenharmony_ci parser.add_option('--enable-ark', 1705f9996aaSopenharmony_ci action='store_true', 1715f9996aaSopenharmony_ci default=False, 1725f9996aaSopenharmony_ci help='whether to transform js to ark bytecode') 1735f9996aaSopenharmony_ci parser.add_option('--hap-packing-tool', help='path to hap packing tool') 1745f9996aaSopenharmony_ci parser.add_option('--private-key-path', help='path to private key') 1755f9996aaSopenharmony_ci parser.add_option('--sign-algo', help='signature algorithm') 1765f9996aaSopenharmony_ci parser.add_option('--certificate-profile', 1775f9996aaSopenharmony_ci help='path to certificate profile') 1785f9996aaSopenharmony_ci parser.add_option('--keyalias', help='keyalias') 1795f9996aaSopenharmony_ci parser.add_option('--keystore-path', help='path to keystore') 1805f9996aaSopenharmony_ci parser.add_option('--keystorepasswd', help='password of keystore') 1815f9996aaSopenharmony_ci parser.add_option('--certificate-file', help='path to certificate file') 1825f9996aaSopenharmony_ci parser.add_option('--packaged-resources', 1835f9996aaSopenharmony_ci help='path to packaged resources') 1845f9996aaSopenharmony_ci parser.add_option('--packaged-js-assets', 1855f9996aaSopenharmony_ci help='path to packaged js assets') 1865f9996aaSopenharmony_ci parser.add_option('--app-profile', default=False, 1875f9996aaSopenharmony_ci help='path to packaged js assets') 1885f9996aaSopenharmony_ci parser.add_option('--build-mode', help='debug mode or release mode') 1895f9996aaSopenharmony_ci 1905f9996aaSopenharmony_ci parser.add_option('--sign_hap_py_path', help='sign_hap_py_path') 1915f9996aaSopenharmony_ci parser.add_option('--sign_compatible_version', default='', help='limit compatible_Version') 1925f9996aaSopenharmony_ci 1935f9996aaSopenharmony_ci options, _ = parser.parse_args(args) 1945f9996aaSopenharmony_ci if options.assets: 1955f9996aaSopenharmony_ci options.assets = build_utils.parse_gn_list(options.assets) 1965f9996aaSopenharmony_ci return options 1975f9996aaSopenharmony_ci 1985f9996aaSopenharmony_ci 1995f9996aaSopenharmony_cidef main(args): 2005f9996aaSopenharmony_ci options = parse_args(args) 2015f9996aaSopenharmony_ci 2025f9996aaSopenharmony_ci inputs = [ 2035f9996aaSopenharmony_ci options.hap_profile, options.packaged_js_assets, 2045f9996aaSopenharmony_ci options.packaged_resources, options.certificate_file, 2055f9996aaSopenharmony_ci options.keystore_path, options.certificate_profile 2065f9996aaSopenharmony_ci ] 2075f9996aaSopenharmony_ci depfiles = [] 2085f9996aaSopenharmony_ci for dire in options.assets: 2095f9996aaSopenharmony_ci depfiles += (build_utils.get_all_files(dire)) 2105f9996aaSopenharmony_ci if options.dso: 2115f9996aaSopenharmony_ci depfiles.extend(options.dso) 2125f9996aaSopenharmony_ci 2135f9996aaSopenharmony_ci build_utils.call_and_write_depfile_if_stale( 2145f9996aaSopenharmony_ci lambda: create_hap(options, options.hap_path), 2155f9996aaSopenharmony_ci options, 2165f9996aaSopenharmony_ci depfile_deps=depfiles, 2175f9996aaSopenharmony_ci input_paths=inputs + depfiles, 2185f9996aaSopenharmony_ci input_strings=[ 2195f9996aaSopenharmony_ci options.keystorepasswd, options.keyalias, options.sign_algo, 2205f9996aaSopenharmony_ci options.private_key_path 2215f9996aaSopenharmony_ci ], 2225f9996aaSopenharmony_ci output_paths=([options.hap_path]), 2235f9996aaSopenharmony_ci force=False, 2245f9996aaSopenharmony_ci add_pydeps=False) 2255f9996aaSopenharmony_ci 2265f9996aaSopenharmony_ci 2275f9996aaSopenharmony_ciif __name__ == '__main__': 2285f9996aaSopenharmony_ci sys.exit(main(sys.argv[1:])) 229