• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 optparse
17import os
18import sys
19import json
20
21from zipfile import ZipFile  # noqa: E402
22from util import build_utils  # noqa: E402
23
24
25def parse_args(args):
26    args = build_utils.expand_file_args(args)
27
28    parser = optparse.OptionParser()
29    build_utils.add_depfile_option(parser)
30    parser.add_option('--output', help='stamp file')
31    parser.add_option('--js-assets-dir', help='js assets directory')
32    parser.add_option('--ets-assets-dir', help='ets assets directory')
33    parser.add_option('--nodejs-path', help='path to nodejs app')
34    parser.add_option('--webpack-js', help='path to webpack.js')
35    parser.add_option('--webpack-config-js', help='path to webpack.config.js')
36    parser.add_option('--webpack-config-ets', help='path to webpack.rich.config.js')
37    parser.add_option('--hap-profile', help='path to hap profile')
38    parser.add_option('--build-mode', help='debug mode or release mode')
39    parser.add_option('--js-sources-file', help='path to js sources file')
40    parser.add_option('--js2abc',
41                      action='store_true',
42                      default=False,
43                      help='whether to transform js to ark bytecode')
44    parser.add_option('--ets2abc',
45                      action='store_true',
46                      default=False,
47                      help='whether to transform ets to ark bytecode')
48    parser.add_option('--ark-frontend-dir', help='path to ark frontend dir')
49    parser.add_option('--ace-loader-home', help='path to ace-loader dir.')
50    parser.add_option('--ets-loader-home', help='path to ets-loader dir.')
51    parser.add_option('--app-profile', default=False, help='path to app-profile.')
52
53    options, _ = parser.parse_args(args)
54    options.js_assets_dir = build_utils.parse_gn_list(options.js_assets_dir)
55    options.ets_assets_dir = build_utils.parse_gn_list(options.ets_assets_dir)
56    return options
57
58def make_my_env(build_dir, options, js2abc, ability_index):
59    out_dir = os.path.abspath(os.path.dirname(options.output))
60    assets_dir = os.path.join(out_dir, "assets")
61    if options.app_profile:
62        if js2abc:
63            assets_dir = os.path.join(assets_dir, "js")
64        else:
65            assets_dir = os.path.join(assets_dir, "ets")
66    gen_dir = os.path.join(out_dir, "gen")
67    my_env = {
68        "aceModuleBuild": assets_dir,
69        "buildMode": options.build_mode,
70        "PATH": os.environ.get('PATH'),
71        "appResource": os.path.join(gen_dir, "ResourceTable.txt")
72    }
73    with open(options.hap_profile) as profile:
74        config = json.load(profile)
75        ability_cnt = len(config['module']['abilities'])
76        if ability_index < ability_cnt and (options.js_asset_cnt > 1 or options.ets_asset_cnt > 1):
77            if config['module']['abilities'][ability_index].__contains__('forms'):
78                my_env["abilityType"] = 'form'
79            else:
80                my_env["abilityType"] = config['module']['abilities'][ability_index]['type']
81        elif config['module'].__contains__('testRunner'):
82            my_env["abilityType"] = 'testrunner'
83
84    if options.app_profile:
85        my_env["aceProfilePath"] = os.path.join(gen_dir, "resources/base/profile")
86        my_env["aceModuleJsonPath"] = os.path.abspath(options.hap_profile)
87    else:
88        manifest = os.path.join(build_dir, 'manifest.json')
89        my_env["aceManifestPath"] = manifest
90    return my_env
91
92def make_manifest_data(config, options, js2abc, ability_index):
93    data = dict()
94    data['appID'] = config['app']['bundleName']
95    ability_cnt = len(config['module']['abilities'])
96    assets_cnt = 0
97    if js2abc:
98        assets_cnt = options.js_asset_cnt
99    else:
100        assets_cnt = options.ets_asset_cnt
101    if ability_index < ability_cnt and config['module']['abilities'][ability_index].__contains__("label"):
102        data['appName'] = config['module']['abilities'][ability_index]['label']
103    if options.app_profile:
104        data['versionName'] = config['app']['versionName']
105        data['versionCode'] = config['app']['versionCode']
106        data['pages'] = config['module']['pages']
107        data['deviceType'] = config['module']['deviceTypes']
108    else:
109        data['versionName'] = config['app']['version']['name']
110        data['versionCode'] = config['app']['version']['code']
111        for js_module in config['module']['js']:
112            ability_name = ''
113            js_module_name = js_module.get('name').split('.')[-1]
114            if ability_index < ability_cnt:
115                ability_name = config['module']['abilities'][ability_index]['name'].split('.')[-1]
116            if js_module_name != ability_name:
117                if (js_module_name == 'default' and ability_name == 'MainAbility') or assets_cnt == 1:
118                    ability_name = 'default'
119            if js_module_name == ability_name:
120                data['pages'] = js_module.get('pages')
121                data['window'] = js_module.get('window')
122                if js_module.get('type') == 'form':
123                    data['pages'] = []
124                    data['type'] = 'form'
125        data['deviceType'] = config['module']['deviceType']
126    if js2abc and (config['module']['abilities'][0].get('srcLanguage') == 'ets' or ability_index >= ability_cnt):
127        for js_page in config['module']['js']:
128            if js_page.get('type') == 'form':
129                data['pages'] = js_page.get('pages')
130                data['type'] = js_page.get('type')
131                data['window'] = js_page.get('window')
132    if not js2abc:
133        if not options.app_profile and ability_index < len(config['module']['js']):
134            data['mode'] = config['module']['js'][ability_index].get('mode')
135    return data
136
137def build_ace(cmd, options, js2abc, loader_home, assets_dir):
138    gen_dir = ''
139    src_path = ''
140    if js2abc:
141        for asset_index in range(options.js_asset_cnt):
142            ability_dir = os.path.relpath(assets_dir[asset_index], loader_home)
143            if options.js_sources_file:
144                with open(options.js_sources_file, 'wb') as js_sources_file:
145                    sources = get_all_js_sources(ability_dir)
146                    js_sources_file.write('\n'.join(sources).encode())
147            with build_utils.temp_dir() as build_dir:
148                my_env = make_my_env(build_dir, options, js2abc, asset_index)
149                my_env["aceModuleRoot"] = ability_dir
150                gen_dir = my_env.get("aceModuleBuild")
151                if options.app_profile:
152                    gen_dir = os.path.dirname(gen_dir)
153                my_env.update({"cachePath": os.path.join(build_dir, ".cache")})
154                if not options.app_profile:
155                    src_path = 'default'
156                manifest = os.path.join(build_dir, 'manifest.json')
157                if not os.path.exists(manifest) and not options.app_profile:
158                    with open(options.hap_profile) as profile:
159                        config = json.load(profile)
160                        data = make_manifest_data(config, options, js2abc, asset_index)
161                        if config['module'].__contains__('testRunner'):
162                            src_path = config['module']['testRunner']['srcPath']
163                        if options.js_asset_cnt > 1 and asset_index < len(config['module']['abilities']):
164                            if 'srcPath' in config['module']['abilities'][asset_index]:
165                                src_path = config['module']['abilities'][asset_index]['srcPath']
166                        if config['module']['abilities'][0].get('srcLanguage') == 'ets':
167                            for ability in config['module']['abilities']:
168                                if ability.__contains__('forms'):
169                                    src_path = ability['forms'][0].get('name')
170                        if asset_index >= len(config['module']['abilities']):
171                            for ability in config['module']['abilities']:
172                                if ability.__contains__('forms'):
173                                    src_path = ability['forms'][0].get('name')
174
175                        build_utils.write_json(data, manifest)
176                        my_env["aceModuleBuild"] = os.path.join(my_env.get("aceModuleBuild"), src_path)
177                build_utils.check_output(
178                    cmd, cwd=loader_home, env=my_env)
179    else:
180        for asset_index in range(options.ets_asset_cnt):
181            ability_dir = os.path.relpath(assets_dir[asset_index], loader_home)
182            if options.js_sources_file:
183                with open(options.js_sources_file, 'wb') as js_sources_file:
184                    sources = get_all_js_sources(ability_dir)
185                    js_sources_file.write('\n'.join(sources).encode())
186            with build_utils.temp_dir() as build_dir:
187                my_env = make_my_env(build_dir, options, js2abc, asset_index)
188                my_env["aceModuleRoot"] = ability_dir
189                gen_dir = my_env.get("aceModuleBuild")
190                if options.app_profile:
191                    gen_dir = os.path.dirname(gen_dir)
192                if not options.app_profile:
193                    src_path = 'default'
194                manifest = os.path.join(build_dir, 'manifest.json')
195                if not os.path.exists(manifest) and not options.app_profile:
196                    with open(options.hap_profile) as profile:
197                        config = json.load(profile)
198                        data = make_manifest_data(config, options, js2abc, asset_index)
199                        if 'srcPath' in config['module']['abilities'][asset_index]:
200                            src_path = config['module']['abilities'][asset_index]['srcPath']
201                        build_utils.write_json(data, manifest)
202                        my_env["aceModuleBuild"] = os.path.join(my_env.get("aceModuleBuild"), src_path)
203                build_utils.check_output(
204                    cmd, cwd=loader_home, env=my_env)
205    if options.app_profile:
206        build_utils.zip_dir(options.output,
207                            gen_dir,
208                            zip_prefix_path=src_path)
209    elif not options.app_profile and not options.hap_profile:
210        build_utils.zip_dir(options.output,
211                            gen_dir,
212                            zip_prefix_path='assets/js/{}/'.format(src_path))
213    else:
214        build_utils.zip_dir(options.output,
215                            gen_dir,
216                            zip_prefix_path='assets/js/')
217
218
219def get_all_js_sources(base):
220    sources = []
221    for root, _, files in os.walk(base):
222        for file in files:
223            if file[-3:] in ('.js', '.ts'):
224                sources.append(os.path.join(root, file))
225
226    return sources
227
228
229def main(args):
230    options = parse_args(args)
231
232    inputs = [
233        options.nodejs_path, options.webpack_js, options.webpack_config_js, options.webpack_config_ets
234    ]
235    depfiles = []
236    options.js_asset_cnt = 0
237    options.ets_asset_cnt = 0
238    if options.js_assets_dir:
239        options.js_asset_cnt = len(options.js_assets_dir)
240        for asset_index in range(options.js_asset_cnt):
241            depfiles.extend(build_utils.get_all_files(options.js_assets_dir[asset_index]))
242    if options.ets_assets_dir:
243        options.ets_asset_cnt = len(options.ets_assets_dir)
244        for asset_index in range(options.ets_asset_cnt):
245            depfiles.extend(build_utils.get_all_files(options.ets_assets_dir[asset_index]))
246    if not options.js_assets_dir and not options.ets_assets_dir:
247        with ZipFile(options.output, 'w') as file:
248            return
249
250    if options.ark_frontend_dir:
251        depfiles.extend(build_utils.get_all_files(options.ark_frontend_dir))
252
253    depfiles.append(options.webpack_js)
254    depfiles.append(options.webpack_config_js)
255    depfiles.append(options.webpack_config_ets)
256    depfiles.extend(build_utils.get_all_files(options.ace_loader_home))
257    depfiles.extend(build_utils.get_all_files(options.ets_loader_home))
258
259    node_js = os.path.relpath(options.nodejs_path, options.ace_loader_home)
260
261    if options.js_assets_dir:
262        js2abc = True
263        loader_home = options.ace_loader_home
264        assets_dir = options.js_assets_dir
265        cmd = [
266            node_js,
267            os.path.relpath(
268                options.webpack_js, options.ace_loader_home),
269            '--config',
270            os.path.relpath(
271                options.webpack_config_js, options.ace_loader_home)
272        ]
273        ark_frontend_dir = os.path.relpath(
274            options.ark_frontend_dir, options.ace_loader_home)
275        if options.app_profile:
276            cmd.extend(['--env', 'buildMode={}'.format(options.build_mode), 'compilerType=ark',
277                        'arkFrontendDir={}'.format(ark_frontend_dir), 'nodeJs={}'.format(node_js)])
278        else:
279            cmd.extend(['--env', 'compilerType=ark',
280                    'arkFrontendDir={}'.format(ark_frontend_dir), 'nodeJs={}'.format(node_js)])
281        build_utils.call_and_write_depfile_if_stale(
282            lambda: build_ace(cmd, options, js2abc, loader_home, assets_dir),
283            options,
284            depfile_deps=depfiles,
285            input_paths=depfiles + inputs,
286            input_strings=cmd + [options.build_mode],
287            output_paths=([options.output]),
288            force=False,
289            add_pydeps=False)
290
291    if options.ets_assets_dir:
292        js2abc = False
293        loader_home = options.ets_loader_home
294        assets_dir = options.ets_assets_dir
295        cmd = [
296            node_js,
297            os.path.relpath(
298                options.webpack_js, options.ets_loader_home),
299            '--config',
300            os.path.relpath(
301                options.webpack_config_ets, options.ets_loader_home)
302        ]
303        ark_frontend_dir = os.path.relpath(
304            options.ark_frontend_dir, options.ets_loader_home)
305        if options.app_profile:
306            cmd.extend(['--env', 'buildMode={}'.format(options.build_mode), 'compilerType=ark',
307                        'arkFrontendDir={}'.format(ark_frontend_dir), 'nodeJs={}'.format(node_js)])
308        else:
309            cmd.extend(['--env', 'compilerType=ark',
310                        'arkFrontendDir={}'.format(ark_frontend_dir), 'nodeJs={}'.format(node_js)])
311        build_utils.call_and_write_depfile_if_stale(
312            lambda: build_ace(cmd, options, js2abc, loader_home, assets_dir),
313            options,
314            depfile_deps=depfiles,
315            input_paths=depfiles + inputs,
316            input_strings=cmd + [options.build_mode],
317            output_paths=([options.output]),
318            force=False,
319            add_pydeps=False)
320
321
322if __name__ == '__main__':
323    sys.exit(main(sys.argv[1:]))
324