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
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 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        self._set_path()
193        Arg.clean_args_file_by_type(ModuleType.INDEP_BUILD)
194        args_dict = Arg.parse_all_args(ModuleType.INDEP_BUILD)
195        hpm = Hpm()
196        indep_build_args_resolver = IndepBuildArgsResolver(args_dict)
197        return OHOSIndepBuildModule(args_dict, indep_build_args_resolver, hpm)
198
199    def _is_indep_build(self) -> bool:
200        if "--indep-build" in sys.argv[2:] or "-i" in sys.argv[2:] or (len(sys.argv) == 4 and sys.argv[-1] == "-t"):
201            return True
202        env_args_dict = Arg.read_args_file(ModuleType.ENV)
203        return env_args_dict.get("indep_build").get("argDefault")
204
205    def _init_install_module(self) -> InstallModuleInterface:
206        self._set_path()
207        Arg.clean_args_file_by_type(ModuleType.INSTALL)
208        args_dict = Arg.parse_all_args(ModuleType.INSTALL)
209        hpm = Hpm()
210        install_args_resolver = InstallArgsResolver(args_dict)
211        return OHOSInstallModule(args_dict, install_args_resolver, hpm)
212
213    def _init_package_module(self) -> PackageModuleInterface:
214        self._set_path()
215        Arg.clean_args_file_by_type(ModuleType.PACKAGE)
216        args_dict = Arg.parse_all_args(ModuleType.PACKAGE)
217        hpm = Hpm()
218        package_args_resolver = PackageArgsResolver(args_dict)
219        return OHOSPackageModule(args_dict, package_args_resolver, hpm)
220
221    def _init_publish_module(self) -> PublishModuleInterface:
222        self._set_path()
223        args_dict = Arg.parse_all_args(ModuleType.PUBLISH)
224        hpm = Hpm()
225        publish_args_resolver = PublishArgsResolver(args_dict)
226        return OHOSPublishModule(args_dict, publish_args_resolver, hpm)
227
228    def _init_update_module(self) -> UpdateModuleInterface:
229        self._set_path()
230        Arg.clean_args_file_by_type(ModuleType.UPDATE)
231        args_dict = Arg.parse_all_args(ModuleType.UPDATE)
232        hpm = Hpm()
233        update_args_resolver = UpdateArgsResolver(args_dict)
234        return OHOSUpdateModule(args_dict, update_args_resolver, hpm)
235
236    def _init_push_module(self) -> PushModuleInterface:
237        args_dict = Arg.parse_all_args(ModuleType.PUSH)
238        hdc = Hdc()
239        update_args_resolver = PushArgsResolver(args_dict)
240        return OHOSPushModule(args_dict, update_args_resolver, hdc)
241
242    def _push_module(self):
243        if sys.argv[2] in ['-h', '-help', 'h', 'help']:
244            print('Please use the command "hb push" like this: hb push component_name -t device_num')
245            sys.exit()
246        check_hdc = subprocess.run(['hdc', '-v'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
247        if check_hdc.returncode != 0:
248            print("Error: Please make sure 'hdc' is installed and properly configured.")
249            sys.exit()
250        check_device = subprocess.run(['hdc', 'list', 'targets'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
251                                      text=True)
252        if check_device.stdout.strip() == "[Empty]":
253            print("Error: Device is not connected.")
254            sys.exit()
255        if len(check_device.stdout.strip().split('\n')) == 1:
256            device = check_device.stdout.strip()
257        else:
258            device = sys.argv[4]
259            if device not in check_device.stdout:
260                print("Error: Wrong device number")
261                sys.exit()
262        subprocess.run(["hdc", "-t", str(device), "shell", "mount", "-o", "rw,remount", "/"], check=True,
263                       stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
264        default = os.path.join(CURRENT_OHOS_ROOT, "out", "default")
265        with open(os.path.join(default, "build_configs", "component_mapping.json"), 'r') as r:
266            single_component_path = json.load(r).get("single_component_path")
267        part_path = next(iter(single_component_path.values()))
268        with open(os.path.join(CURRENT_OHOS_ROOT, part_path, "bundle.json"), 'r') as r:
269            bundle = json.load(r)
270        push_list = bundle.get("deployment")
271        if push_list:
272            if not isinstance(push_list, list):
273                print("Error: Deployment value format error, should be in list format!")
274            for one_push in push_list:
275                if one_push.get("src") and not os.path.exists(os.path.join(CURRENT_OHOS_ROOT, one_push.get("src"))):
276                    print("Error: The path in src does not exist, please modify the src path!")
277                if one_push.get("src") and one_push.get("target"):
278                    subprocess.run(
279                        ["hdc", "-t", str(device), "file", "send", os.path.join(CURRENT_OHOS_ROOT, one_push.get("src")),
280                         one_push.get("target")], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
281        print("hb push success!")
282        sys.exit()
283
284
285if __name__ == "__main__":
286    sys.exit(Main.main())
287