• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# Copyright (c) 2023 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 argparse
17import os
18import sys
19import subprocess
20import shutil
21import json5
22
23from util import build_utils
24from util import file_utils
25
26
27def parse_args(args):
28    parser = argparse.ArgumentParser()
29    build_utils.add_depfile_option(parser)
30
31    parser.add_argument('--nodejs', help='nodejs path')
32    parser.add_argument('--cwd', help='app project directory')
33    parser.add_argument('--sdk-home', help='sdk home')
34    parser.add_argument('--enable-debug', action='store_true', help='if enable debuggable')
35    parser.add_argument('--build-level', default='project', help='module or project')
36    parser.add_argument('--assemble-type', default='assembleApp', help='assemble type')
37    parser.add_argument('--output-file', help='output file')
38    parser.add_argument('--build-profile', help='build profile file')
39    parser.add_argument('--system-lib-module-info-list', nargs='+', help='system lib module info list')
40    parser.add_argument('--ohos-app-abi', help='ohos app abi')
41    parser.add_argument('--ohpm-registry', help='ohpm registry', nargs='?')
42    parser.add_argument('--hap-out-dir', help='hap out dir')
43    parser.add_argument('--hap-name', help='hap name')
44    parser.add_argument('--test-hap', help='build ohosTest if enable', action='store_true')
45    parser.add_argument('--test-module', help='specify the module within ohosTest', default='entry')
46    parser.add_argument('--module-libs-dir', help='', default='entry')
47    parser.add_argument('--sdk-type-name', help='sdk type name', nargs='+', default=['sdk.dir'])
48
49    options = parser.parse_args(args)
50    return options
51
52
53def make_env(build_profile, cwd, ohpm_registry):
54    '''
55    Set up the application compilation environment and run "ohpm install"
56    :param build_profile: module compilation information file
57    :param cwd: app project directory
58    :param ohpm_registry: ohpm registry
59    :return: None
60    '''
61    cur_dir = os.getcwd()
62    with open(build_profile, 'r') as input_f:
63        build_info = json5.load(input_f)
64        modules_list = build_info.get('modules')
65        ohpm_install_cmd = ['ohpm', 'install']
66        if ohpm_registry:
67            ohpm_install_cmd.append('--registry=' + ohpm_registry)
68        os.chdir(cwd)
69        if os.path.exists(os.path.join(cwd, 'oh_modules')):
70            subprocess.run(['rm', '-rf', 'oh_modules'])
71        subprocess.run(['chmod', '+x', 'hvigorw'])
72        if os.path.exists(os.path.join(cwd, '.arkui-x/android/gradlew')):
73            subprocess.run(['chmod', '+x', '.arkui-x/android/gradlew'])
74
75        proc = subprocess.Popen(ohpm_install_cmd,
76                                stdout=subprocess.PIPE,
77                                stderr=subprocess.PIPE,
78                                encoding='utf-8')
79        stdout, stderr = proc.communicate()
80        if proc.returncode:
81            raise Exception('ReturnCode:{}. ohpm install failed. {}'.format(
82                proc.returncode, stderr))
83
84        for module in modules_list:
85            src_path = module.get('srcPath')
86            ohpm_install_path = os.path.join(cwd, src_path)
87            if os.path.exists(os.path.join(ohpm_install_path, 'oh_modules')):
88                subprocess.run(['rm', '-rf', os.path.join(ohpm_install_path, 'oh_modules')])
89            proc = subprocess.Popen(ohpm_install_cmd,
90                                    cwd=ohpm_install_path,
91                                    stdout=subprocess.PIPE,
92                                    stderr=subprocess.PIPE,
93                                    encoding='utf-8')
94            stdout, stderr = proc.communicate()
95            if proc.returncode:
96                raise Exception('ReturnCode:{}. ohpm install module failed. {}'.format(
97                    proc.returncode, stderr))
98    os.chdir(cur_dir)
99
100
101def gen_unsigned_hap_path_json(build_profile, cwd, options):
102    '''
103    Generate unsigned_hap_path_list
104    :param build_profile: module compilation information file
105    :param cwd: app project directory
106    :return: None
107    '''
108    unsigned_hap_path_json = {}
109    unsigned_hap_path_list = []
110    with open(build_profile, 'r') as input_f:
111        build_info = json5.load(input_f)
112        modules_list = build_info.get('modules')
113        for module in modules_list:
114            src_path = module.get('srcPath')
115            if options.test_hap:
116                unsigned_hap_path = os.path.join(
117                    cwd, src_path, 'build/default/outputs/ohosTest')
118            else:
119                unsigned_hap_path = os.path.join(
120                    cwd, src_path, 'build/default/outputs/default')
121            hap_file = build_utils.find_in_directory(
122                unsigned_hap_path, '*-unsigned.hap')
123            unsigned_hap_path_list.extend(hap_file)
124        unsigned_hap_path_json['unsigned_hap_path_list'] = unsigned_hap_path_list
125    file_utils.write_json_file(options.output_file, unsigned_hap_path_json)
126
127
128def copy_libs(cwd, system_lib_module_info_list, ohos_app_abi, module_libs_dir):
129    '''
130    Obtain the output location of system library .so by reading the module compilation information file,
131    and copy it to the app project directory
132    :param cwd: app project directory
133    :param system_lib_module_info_list: system library module compilation information file
134    :param ohos_app_abi: app abi
135    :return: None
136    '''
137    for _lib_info in system_lib_module_info_list:
138        lib_info = file_utils.read_json_file(_lib_info)
139        lib_path = lib_info.get('source')
140        if os.path.exists(lib_path):
141            lib_name = os.path.basename(lib_path)
142            dest = os.path.join(cwd, f'{module_libs_dir}/libs', ohos_app_abi, lib_name)
143            if not os.path.exists(os.path.dirname(dest)):
144                os.makedirs(os.path.dirname(dest), exist_ok=True)
145            shutil.copyfile(lib_path, dest)
146
147
148def hvigor_build(cwd, options):
149    '''
150    Run hvigorw to build the app or hap
151    :param cwd: app project directory
152    :param options: command line parameters
153    :return: None
154    '''
155    if options.test_hap:
156        cmd = ['bash', './hvigorw', '--mode', 'module', '-p',
157               f'module={options.test_module}@ohosTest', 'assembleHap']
158    else:
159        cmd = ['bash', './hvigorw', '--mode',
160               options.build_level, '-p', 'product=default', options.assemble_type]
161    if options.enable_debug:
162        cmd.extend(['-p', 'debuggable=true'])
163    else:
164        cmd.extend(['-p', 'debuggable=false'])
165    cmd.extend(['--no-daemon'])
166    sdk_dir = options.sdk_home
167    nodejs_dir = os.path.abspath(
168        os.path.dirname(os.path.dirname(options.nodejs)))
169
170    with open(os.path.join(cwd, 'local.properties'), 'w') as f:
171        for sdk_type in options.sdk_type_name:
172            f.write(f'{sdk_type}={sdk_dir}\n')
173        f.write(f'nodejs.dir={nodejs_dir}\n')
174    print("[0/0] Hvigor clean start")
175    subprocess.run(['bash', './hvigorw', '--sync', '--no-daemon'], cwd=cwd)
176    print("[0/0] Hvigor build start")
177    proc = subprocess.Popen(cmd,
178                            cwd=cwd,
179                            stdout=subprocess.PIPE,
180                            stderr=subprocess.PIPE,
181                            encoding='utf-8')
182    stdout, stderr = proc.communicate()
183    for line in stdout.splitlines():
184        print(f"[1/1] Hvigor info: {line}")
185    for line in stderr.splitlines():
186        print(f"[2/2] Hvigor warning: {line}")
187    os.makedirs(os.path.join(cwd, 'build'), exist_ok=True)
188    with open(os.path.join(cwd, 'build', 'build.log'), 'w') as f:
189        f.write(f'{stdout}\n')
190        f.write(f'{stderr}\n')
191    if proc.returncode or "ERROR: BUILD FAILED" in stderr or "ERROR: BUILD FAILED" in stdout:
192        raise Exception('ReturnCode:{}. Hvigor build failed: {}'.format(proc.returncode, stderr))
193    print("[0/0] Hvigor build end")
194
195
196def main(args):
197    options = parse_args(args)
198    cwd = os.path.abspath(options.cwd)
199
200    # copy system lib deps to app libs dir
201    if options.system_lib_module_info_list:
202        copy_libs(cwd, options.system_lib_module_info_list,
203                  options.ohos_app_abi, options.module_libs_dir)
204
205    os.environ['PATH'] = '{}:{}'.format(os.path.dirname(
206        os.path.abspath(options.nodejs)), os.environ.get('PATH'))
207
208    # add arkui-x to PATH
209    os.environ['PATH'] = f'{cwd}/.arkui-x/android:{os.environ.get("PATH")}'
210
211    # generate unsigned_hap_path_list and run ohpm install
212    make_env(options.build_profile, cwd, options.ohpm_registry)
213
214    # invoke hvigor to build hap or app
215    hvigor_build(cwd, options)
216
217    # generate a json file to record the path of all unsigned haps, and When signing hap later,
218    # this json file will serve as input to provide path information for each unsigned hap.
219    gen_unsigned_hap_path_json(options.build_profile, cwd, options)
220
221if __name__ == '__main__':
222    sys.exit(main(sys.argv[1:]))
223