1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4#
5# Copyright (c) 2023 Huawei Device Co., Ltd.
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19
20import os
21import sys
22import subprocess
23import json
24import time
25
26sys.path.append(os.path.dirname(os.path.abspath(__file__)))  # ohos/build/hb dir
27sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))  # ohos/build dir
28sys.path.append(
29    os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'lite'))  # ohos/build/lite dir
30
31from containers.arg import Arg, ModuleType
32from containers.status import throw_exception, judge_indep
33from resources.global_var import ARGS_DIR
34from resources.global_var import CURRENT_OHOS_ROOT
35from exceptions.ohos_exception import OHOSException
36
37from services.preloader import OHOSPreloader
38from services.loader import OHOSLoader
39from services.gn import Gn
40from services.ninja import Ninja
41from services.hpm import Hpm
42from services.hdc import Hdc
43
44from resolver.build_args_resolver import BuildArgsResolver
45from resolver.set_args_resolver import SetArgsResolver
46from resolver.clean_args_resolver import CleanArgsResolver
47from resolver.env_args_resolver import EnvArgsResolver
48from resolver.tool_args_resolver import ToolArgsResolver
49from resolver.indep_build_args_resolver import IndepBuildArgsResolver
50from resolver.install_args_resolver import InstallArgsResolver
51from resolver.package_args_resolver import PackageArgsResolver
52from resolver.publish_args_resolver import PublishArgsResolver
53from resolver.update_args_resolver import UpdateArgsResolver
54from resolver.push_args_resolver import PushArgsResolver
55
56from modules.interface.module_interface import ModuleInterface
57from modules.interface.build_module_interface import BuildModuleInterface
58from modules.interface.set_module_interface import SetModuleInterface
59from modules.interface.env_module_interface import EnvModuleInterface
60from modules.interface.clean_module_interface import CleanModuleInterface
61from modules.interface.tool_module_interface import ToolModuleInterface
62from modules.interface.indep_build_module_interface import IndepBuildModuleInterface
63from modules.interface.install_module_interface import InstallModuleInterface
64from modules.interface.package_module_interface import PackageModuleInterface
65from modules.interface.publish_module_interface import PublishModuleInterface
66from modules.interface.update_module_interface import UpdateModuleInterface
67from modules.interface.push_module_interface import PushModuleInterface
68
69from modules.ohos_build_module import OHOSBuildModule
70from modules.ohos_set_module import OHOSSetModule
71from modules.ohos_clean_module import OHOSCleanModule
72from modules.ohos_env_module import OHOSEnvModule
73from modules.ohos_tool_module import OHOSToolModule
74from modules.ohos_indep_build_module import OHOSIndepBuildModule
75from modules.ohos_install_module import OHOSInstallModule
76from modules.ohos_package_module import OHOSPackageModule
77from modules.ohos_publish_module import OHOSPublishModule
78from modules.ohos_update_module import OHOSUpdateModule
79from modules.ohos_push_module import OHOSPushModule
80
81from helper.separator import Separator
82from util.log_util import LogUtil
83from util.system_util import SystemUtil
84
85
86class Main():
87    @staticmethod
88    @throw_exception
89    def main():
90        main = Main()
91        module_initializers = {
92            'build': main._init_indep_build_module if main._is_indep_build() else main._init_build_module,
93            'init': main._init_hb_init_module,
94            'indep_build': main._init_indep_build_module,
95            'set': main._init_set_module,
96            'env': main._init_env_module,
97            'clean': main._init_clean_module,
98            'tool': main._init_tool_module,
99            'install': main._init_install_module,
100            'package': main._init_package_module,
101            'publish': main._init_publish_module,
102            'update': main._init_update_module,
103            'push': main._push_module
104        }
105
106        module_type = sys.argv[1]
107        if module_type == 'help':
108            for all_module_type in ModuleType:
109                LogUtil.hb_info(Separator.long_line)
110                LogUtil.hb_info(Arg.get_help(all_module_type))
111            exit()
112
113        if module_type not in module_initializers:
114            raise OHOSException(f'There is no such option {module_type}', '0018')
115
116        start_time = SystemUtil.get_current_time()
117        module = module_initializers[module_type]()
118        try:
119            module.run()
120            if module_type == 'build':
121                LogUtil.hb_info('Cost Time:  {}'.format(SystemUtil.get_current_time() - start_time))
122        except KeyboardInterrupt:
123            for file in os.listdir(ARGS_DIR):
124                if file.endswith('.json') and os.path.exists(os.path.join(ARGS_DIR, file)):
125                    os.remove(os.path.join(ARGS_DIR, file))
126            print('User abort')
127            return -1
128        else:
129            return 0
130
131    def _set_path(self):
132        user_home = os.path.expanduser("~")
133        prebuilts_cache_path = os.path.join(user_home, '.prebuilts_cache', 'hpm', 'node_modules', '.bin')
134        nodejs_bin_path = os.path.join(CURRENT_OHOS_ROOT, 'prebuilts', 'build-tools', 'common', 'nodejs', 'current',
135                                       'bin')
136        os.environ['PATH'] = prebuilts_cache_path + os.pathsep + nodejs_bin_path + os.pathsep + os.environ['PATH']
137
138    def _init_build_module(self) -> BuildModuleInterface:
139        args_dict = Arg.parse_all_args(ModuleType.BUILD)
140
141        if args_dict.get("product_name").arg_value != '':
142            set_args_dict = Arg.parse_all_args(ModuleType.SET)
143            set_args_resolver = SetArgsResolver(set_args_dict)
144            ohos_set_module = OHOSSetModule(set_args_dict, set_args_resolver, "")
145            ohos_set_module.set_product()
146
147        preloader = OHOSPreloader()
148        loader = OHOSLoader()
149        generate_ninja = Gn()
150        ninja = Ninja()
151        build_args_resolver = BuildArgsResolver(args_dict)
152
153        return OHOSBuildModule(args_dict, build_args_resolver, preloader, loader, generate_ninja, ninja)
154
155    def _init_hb_init_module(self):
156        subprocess.run([os.path.join(CURRENT_OHOS_ROOT, 'build', 'prebuilts_config.sh')])
157        sys.exit()
158
159    def _init_set_module(self) -> SetModuleInterface:
160        Arg.clean_args_file()
161        args_dict = Arg.parse_all_args(ModuleType.SET)
162        set_args_resolver = SetArgsResolver(args_dict)
163        from services.menu import Menu
164        menu = Menu()
165        return OHOSSetModule(args_dict, set_args_resolver, menu)
166
167    def _init_env_module(self) -> EnvModuleInterface:
168        if len(sys.argv) > 2 and sys.argv[2] in ['--sshkey', '-s']:
169            self._set_path()
170            subprocess.run(['hpm', 'config', 'set', 'loginUser', str(sys.argv[3])])
171            subprocess.run(['hpm', 'gen-keys'])
172            key_path = os.path.join(os.path.expanduser("~"), '.hpm', 'key', 'publicKey_' + sys.argv[3] + '.pem')
173            print(f'Please add the content of {key_path} to https://repo.harmonyos.com/#/cn/profile/sshkeys')
174            sys.exit()
175        args_dict = Arg.parse_all_args(ModuleType.ENV)
176        env_args_resolver = EnvArgsResolver(args_dict)
177        return OHOSEnvModule(args_dict, env_args_resolver)
178
179    def _init_clean_module(self) -> CleanModuleInterface:
180        args_dict = Arg.parse_all_args(ModuleType.CLEAN)
181        clean_args_resolever = CleanArgsResolver(args_dict)
182        return OHOSCleanModule(args_dict, clean_args_resolever)
183
184    def _init_tool_module(self) -> ToolModuleInterface:
185        Arg.clean_args_file()
186        args_dict = Arg.parse_all_args(ModuleType.TOOL)
187        generate_ninja = Gn()
188        tool_args_resolever = ToolArgsResolver(args_dict)
189        return OHOSToolModule(args_dict, tool_args_resolever, generate_ninja)
190
191    def _init_indep_build_module(self) -> IndepBuildModuleInterface:
192        cwd = os.getcwd()
193        if not os.path.exists(os.path.join(cwd, 'build', 'indep_configs', 'build_indep.sh')):
194            print("ERROR: you are running hb build command in wrong dir!")
195            sys.exit()
196        self._set_path()
197        Arg.clean_args_file_by_type(ModuleType.INDEP_BUILD)
198        args_dict = Arg.parse_all_args(ModuleType.INDEP_BUILD)
199        hpm = Hpm()
200        indep_build_args_resolver = IndepBuildArgsResolver(args_dict)
201        return OHOSIndepBuildModule(args_dict, indep_build_args_resolver, hpm)
202
203    def _is_indep_build(self) -> bool:
204        if judge_indep():
205            return True
206        env_args_dict = Arg.read_args_file(ModuleType.ENV)
207        return env_args_dict.get("indep_build").get("argDefault")
208
209    def _init_install_module(self) -> InstallModuleInterface:
210        self._set_path()
211        Arg.clean_args_file_by_type(ModuleType.INSTALL)
212        args_dict = Arg.parse_all_args(ModuleType.INSTALL)
213        hpm = Hpm()
214        install_args_resolver = InstallArgsResolver(args_dict)
215        return OHOSInstallModule(args_dict, install_args_resolver, hpm)
216
217    def _init_package_module(self) -> PackageModuleInterface:
218        self._set_path()
219        Arg.clean_args_file_by_type(ModuleType.PACKAGE)
220        args_dict = Arg.parse_all_args(ModuleType.PACKAGE)
221        hpm = Hpm()
222        package_args_resolver = PackageArgsResolver(args_dict)
223        return OHOSPackageModule(args_dict, package_args_resolver, hpm)
224
225    def _init_publish_module(self) -> PublishModuleInterface:
226        self._set_path()
227        args_dict = Arg.parse_all_args(ModuleType.PUBLISH)
228        hpm = Hpm()
229        publish_args_resolver = PublishArgsResolver(args_dict)
230        return OHOSPublishModule(args_dict, publish_args_resolver, hpm)
231
232    def _init_update_module(self) -> UpdateModuleInterface:
233        self._set_path()
234        Arg.clean_args_file_by_type(ModuleType.UPDATE)
235        args_dict = Arg.parse_all_args(ModuleType.UPDATE)
236        hpm = Hpm()
237        update_args_resolver = UpdateArgsResolver(args_dict)
238        return OHOSUpdateModule(args_dict, update_args_resolver, hpm)
239
240    def _init_push_module(self) -> PushModuleInterface:
241        args_dict = Arg.parse_all_args(ModuleType.PUSH)
242        hdc = Hdc()
243        update_args_resolver = PushArgsResolver(args_dict)
244        return OHOSPushModule(args_dict, update_args_resolver, hdc)
245
246    def _push_module(self):
247        if sys.argv[2] in ['-h', '-help', 'h', 'help']:
248            print('Please use the command "hb push" like this: hb push component_name -t device_num')
249            sys.exit()
250        check_hdc = subprocess.run(['hdc', '-v'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
251        if check_hdc.returncode != 0:
252            print("Error: Please make sure 'hdc' is installed and properly configured.")
253            sys.exit()
254        check_device = subprocess.run(['hdc', 'list', 'targets'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
255                                      text=True)
256        if check_device.stdout.strip() == "[Empty]":
257            print("Error: Device is not connected.")
258            sys.exit()
259        if len(check_device.stdout.strip().split('\n')) == 1:
260            device = check_device.stdout.strip()
261        else:
262            device = sys.argv[4]
263            if device not in check_device.stdout:
264                print("Error: Wrong device number")
265                sys.exit()
266        subprocess.run(["hdc", "-t", str(device), "shell", "mount", "-o", "rw,remount", "/"], check=True,
267                       stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
268        default = os.path.join(CURRENT_OHOS_ROOT, "out", "default")
269        with open(os.path.join(default, "build_configs", "component_mapping.json"), 'r') as r:
270            single_component_path = json.load(r).get("single_component_path")
271        part_path = next(iter(single_component_path.values()))
272        with open(os.path.join(CURRENT_OHOS_ROOT, part_path, "bundle.json"), 'r') as r:
273            bundle = json.load(r)
274        push_list = bundle.get("deployment")
275        if push_list:
276            if not isinstance(push_list, list):
277                print("Error: Deployment value format error, should be in list format!")
278            for one_push in push_list:
279                if one_push.get("src") and not os.path.exists(os.path.join(CURRENT_OHOS_ROOT, one_push.get("src"))):
280                    print("Error: The path in src does not exist, please modify the src path!")
281                if one_push.get("src") and one_push.get("target"):
282                    subprocess.run(
283                        ["hdc", "-t", str(device), "file", "send", os.path.join(CURRENT_OHOS_ROOT, one_push.get("src")),
284                         one_push.get("target")], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
285        print("hb push success!")
286        sys.exit()
287
288
289if __name__ == "__main__":
290    sys.exit(Main.main())
291