Files
phs_v1.0.1.0/build/scripts/hapbuilder.py
2024-09-27 19:16:49 +08:00

229 lines
9.2 KiB
Python
Executable File

#!/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 optparse
import subprocess
import sys
import shutil
import os
import tempfile
import json
from util import build_utils # noqa: E402
def sign_hap(options, unsigned_hap_path, signed_hap_path):
cmd = ['python3', options.sign_hap_py_path]
cmd.extend(['--hapsigner', options.hapsigner])
cmd.extend(['--sign-algo', options.sign_algo])
cmd.extend(['--keyalias', options.keyalias])
cmd.extend(['--inFile', unsigned_hap_path])
cmd.extend(['--outFile', signed_hap_path])
cmd.extend(['--profileFile', options.certificate_profile])
cmd.extend(['--keystoreFile', options.keystore_path])
cmd.extend(['--keystorePwd', options.keystorepasswd])
cmd.extend(['--keyPwd', options.private_key_path])
cmd.extend(['--certificate-file', options.certificate_file])
cmd.extend(['--profileSigned', '1'])
cmd.extend(['--inForm', 'zip'])
cmd.extend(['--compatible_version', options.sign_compatible_version])
child = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = child.communicate()
if child.returncode:
print(stdout.decode(), stderr.decode())
raise Exception("Failed to sign hap {}.".format(options.sign_hap_py_path))
def add_resources(packaged_resources, package_dir, packing_cmd):
if packaged_resources:
build_utils.extract_all(packaged_resources,
package_dir,
no_clobber=False)
index_file_path = os.path.join(package_dir, 'resources.index')
if os.path.exists(index_file_path):
packing_cmd.extend(['--index-path', index_file_path])
resources_path = os.path.join(package_dir, 'resources')
if os.path.exists(resources_path):
packing_cmd.extend(['--resources-path', resources_path])
def add_assets(options, package_dir, packing_cmd):
packaged_js_assets, assets = options.packaged_js_assets, options.assets
if options.app_profile:
assets_dir = os.path.join(package_dir, 'ets')
js_assets_dir = os.path.join(package_dir, 'js')
else:
assets_dir = os.path.join(package_dir, 'assets')
if packaged_js_assets:
build_utils.extract_all(packaged_js_assets,
package_dir,
no_clobber=False)
if options.build_mode == "release":
for root, _, files in os.walk(assets_dir):
for f in files:
filename = os.path.join(root, f)
if filename.endswith('.js.map'):
os.unlink(filename)
if assets:
if not os.path.exists(assets_dir):
os.mkdir(assets_dir)
for item in assets:
if os.path.isfile(item):
shutil.copyfile(
item, os.path.join(assets_dir, os.path.basename(item)))
elif os.path.isdir(item):
shutil.copytree(
item, os.path.join(assets_dir, os.path.basename(item)))
if os.path.exists(assets_dir) and len(os.listdir(assets_dir)) != 0:
if options.app_profile:
packing_cmd.extend(['--ets-path', assets_dir])
else:
packing_cmd.extend(['--assets-path', assets_dir])
if options.app_profile:
if os.path.exists(js_assets_dir) and len(os.listdir(js_assets_dir)) != 0:
packing_cmd.extend(['--js-path', js_assets_dir])
def get_ark_toolchain_version(options):
cmd = [options.nodejs_path, options.js2abc_js, '--bc-version']
return build_utils.check_output(cmd).strip('\n')
def tweak_hap_profile(options, package_dir):
config_name = 'config.json'
if options.app_profile:
config_name = 'module.json'
hap_profile = os.path.join(package_dir, config_name)
if not os.path.exists(hap_profile):
raise Exception('Error: {} of hap file not exists'.format(config_name))
config = {}
with open(hap_profile, 'r') as fileobj:
config = json.load(fileobj)
if options.app_profile:
config.get('module')['virtualMachine'] = 'ark{}'.format(
get_ark_toolchain_version(options))
else:
config.get('module').get('distro')['virtualMachine'] = 'ark{}'.format(
get_ark_toolchain_version(options))
build_utils.write_json(config, hap_profile)
def create_hap(options, signed_hap):
with build_utils.temp_dir() as package_dir, tempfile.NamedTemporaryFile(
suffix='.hap') as output:
packing_cmd = ['java', '-jar', options.hap_packing_tool]
packing_cmd.extend(
['--mode', 'hap', '--force', 'true', '--out-path', output.name])
hap_profile_path = os.path.join(package_dir,
os.path.basename(options.hap_profile))
shutil.copy(options.hap_profile, hap_profile_path)
packing_cmd.extend(['--json-path', hap_profile_path])
add_assets(options, package_dir, packing_cmd)
add_resources(options.packaged_resources, package_dir, packing_cmd)
if options.enable_ark:
tweak_hap_profile(options, package_dir)
if options.dso:
lib_path = os.path.join(package_dir, "lib")
hap_lib_path = os.path.join(lib_path, options.ohos_app_abi)
os.makedirs(hap_lib_path, exist_ok=True)
for dso in sorted(options.dso):
shutil.copy(dso, hap_lib_path)
packing_cmd.extend(['--lib-path', lib_path])
build_utils.check_output(packing_cmd)
sign_hap(options, output.name, signed_hap)
def parse_args(args):
args = build_utils.expand_file_args(args)
parser = optparse.OptionParser()
build_utils.add_depfile_option(parser)
parser.add_option('--hap-path', help='path to output hap')
parser.add_option('--hapsigner', help='path to signer')
parser.add_option('--assets', help='path to assets')
parser.add_option('--dso',
action="append",
help='path to dynamic shared objects')
parser.add_option('--ohos-app-abi', help='ohos app abi')
parser.add_option('--hap-profile', help='path to hap profile')
parser.add_option('--nodejs-path', help='path to node')
parser.add_option('--js2abc-js', help='path to ts2abc.js')
parser.add_option('--enable-ark',
action='store_true',
default=False,
help='whether to transform js to ark bytecode')
parser.add_option('--hap-packing-tool', help='path to hap packing tool')
parser.add_option('--private-key-path', help='path to private key')
parser.add_option('--sign-algo', help='signature algorithm')
parser.add_option('--certificate-profile',
help='path to certificate profile')
parser.add_option('--keyalias', help='keyalias')
parser.add_option('--keystore-path', help='path to keystore')
parser.add_option('--keystorepasswd', help='password of keystore')
parser.add_option('--certificate-file', help='path to certificate file')
parser.add_option('--packaged-resources',
help='path to packaged resources')
parser.add_option('--packaged-js-assets',
help='path to packaged js assets')
parser.add_option('--app-profile', default=False,
help='path to packaged js assets')
parser.add_option('--build-mode', help='debug mode or release mode')
parser.add_option('--sign_hap_py_path', help='sign_hap_py_path')
parser.add_option('--sign_compatible_version', default='', help='limit compatible_Version')
options, _ = parser.parse_args(args)
if options.assets:
options.assets = build_utils.parse_gn_list(options.assets)
return options
def main(args):
options = parse_args(args)
inputs = [
options.hap_profile, options.packaged_js_assets,
options.packaged_resources, options.certificate_file,
options.keystore_path, options.certificate_profile
]
depfiles = []
for dire in options.assets:
depfiles += (build_utils.get_all_files(dire))
if options.dso:
depfiles.extend(options.dso)
build_utils.call_and_write_depfile_if_stale(
lambda: create_hap(options, options.hap_path),
options,
depfile_deps=depfiles,
input_paths=inputs + depfiles,
input_strings=[
options.keystorepasswd, options.keyalias, options.sign_algo,
options.private_key_path
],
output_paths=([options.hap_path]),
force=False,
add_pydeps=False)
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))