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 sys
17import argparse
18import os
19import shutil
20
21sys.path.append(
22    os.path.dirname(os.path.dirname(os.path.dirname(
23        os.path.abspath(__file__)))))
24from scripts.util.file_utils import read_json_file, write_json_file, write_file  # noqa: E402
25from scripts.util import build_utils  # noqa: E402
26
27sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "rules"))
28from categorized_libraries_utils import load_categorized_libraries
29from categorized_libraries_utils import update_module_info
30
31
32def _get_modules_info(system_install_info: dict, depfiles: list):
33    modules_info_dict = {}
34    for subsystem_info in system_install_info:
35        part_name = subsystem_info.get('part_name')
36        part_info_file = subsystem_info.get('part_info_file')
37
38        # read subsystem module info
39        part_install_info = read_json_file(part_info_file)
40        if part_install_info is None:
41            raise Exception(
42                "read part '{}' installed modules info failed.".format(
43                    part_name))
44        depfiles.append(part_info_file)
45
46        for info in part_install_info:
47            module_def = info.get('module_def')
48            module_info_file = info.get('module_info_file')
49            depfiles.append(module_info_file)
50            if module_def not in modules_info_dict:
51                modules_info_dict[module_def] = module_info_file
52    return modules_info_dict
53
54
55def _get_post_process_modules_info(post_process_modules_info_files: list, depfiles: list):
56    modules_info_list = []
57    for _modules_info_file in post_process_modules_info_files:
58        _modules_info = read_json_file(_modules_info_file)
59        if _modules_info is None:
60            raise Exception("read _modules_info_file '{}' failed.".format(
61                _modules_info_file))
62        modules_info_list.extend(_modules_info)
63        depfiles.append(_modules_info_file)
64    return modules_info_list
65
66
67def copy_modules(system_install_info: dict, install_modules_info_file: str,
68                 modules_info_file: str, module_list_file: str,
69                 post_process_modules_info_files: list, platform_installed_path: str,
70                 host_toolchain, additional_system_files: dict, depfiles: list, categorized_libraries: dict):
71    output_result = []
72    dest_list = []
73    symlink_dest = []
74
75    modules_info_dict = _get_modules_info(system_install_info, depfiles)
76    for value in modules_info_dict.values():
77        module_info = read_json_file(value)
78        if not module_info:
79            raise Exception("read module install info file '{}' error.".format(value))
80        install = module_info.get('install_enable')
81        if not install:
82            continue
83        update_module_info(module_info, categorized_libraries)
84        output_result.append(module_info)
85
86    # get post process modules info
87    post_process_modules = _get_post_process_modules_info(
88        post_process_modules_info_files, depfiles)
89    for _module_info in post_process_modules:
90        install = _module_info.get('install_enable')
91        if not install:
92            continue
93        output_result.append(_module_info)
94
95    for source, system_path in additional_system_files:
96        shutil.copy(source, os.path.join(platform_installed_path, system_path))
97
98    # copy modules
99    for module_info in output_result:
100        if module_info.get('type') == 'none':
101            continue
102        # copy module lib
103        label = module_info.get('label')
104        if label and host_toolchain in label:
105            continue
106        source = module_info.get('source')
107        dests = module_info.get('dest')
108        # check source
109        if not os.path.exists(source):
110            raise Exception("source '{}' doesn't exist.".format(source))
111        depfiles.append(source)
112        for dest in dests:
113            if dest.startswith('/'):
114                dest = dest[1:]
115            dest_list.append(dest)
116            # dest_dir_prefix
117            if os.path.isfile(source):
118                dest_dir = os.path.join(platform_installed_path,
119                                        os.path.dirname(dest))
120            elif os.path.isdir(source):
121                dest_dir = os.path.join(platform_installed_path, dest)
122            if not os.path.exists(dest_dir):
123                os.makedirs(dest_dir, exist_ok=True)
124            if os.path.isdir(source):
125                is_hvigor_hap = False
126                for filename in os.listdir(source):
127                    if filename.endswith('.hap') or filename.endswith('.hsp'):
128                        is_hvigor_hap = True
129                        shutil.copy2(os.path.join(source, filename),
130                                     os.path.join(platform_installed_path, dest, filename))
131                if not is_hvigor_hap:
132                    shutil.copytree(source, os.path.join(platform_installed_path, dest), dirs_exist_ok=True)
133            else:
134                shutil.copy2(source, os.path.join(platform_installed_path, dest))
135
136        # add symlink
137        if 'symlink' in module_info:
138            symlink_dest = module_info.get('symlink')
139            for dest in dests:
140                symlink_src_file = os.path.basename(dest)
141                for name in symlink_dest:
142                    symlink_dest_dir = os.path.dirname(dest)
143                    symlink_dest_file = os.path.join(platform_installed_path,
144                                                     symlink_dest_dir, name)
145                    if not os.path.exists(symlink_dest_file):
146                        os.symlink(symlink_src_file, symlink_dest_file)
147        if 'symlink_ext' in module_info:
148            symlink_ext = module_info.get('symlink_ext')
149            for dest in dests:
150                symlink_src_file = os.path.join(platform_installed_path, dest)
151                for name in symlink_ext:
152                    symlink_dest_file = os.path.join(platform_installed_path, dest.split('/')[0], name)
153                    relpath = os.path.relpath(os.path.dirname(symlink_src_file), os.path.dirname(symlink_dest_file))
154                    if not os.path.exists(os.path.dirname(symlink_dest_file)):
155                        os.makedirs(os.path.dirname(symlink_dest_file), exist_ok=True)
156                    if not os.path.exists(symlink_dest_file):
157                        os.symlink(os.path.join(relpath, os.path.basename(dest)), symlink_dest_file)
158        if 'symlink_path' in module_info:
159            symlink_path = module_info.get('symlink_path')
160            dest_file = os.path.join(platform_installed_path, dests[0])
161            if os.path.exists(dest_file):
162                os.remove(dest_file)
163            os.symlink(symlink_path, dest_file)
164            if not os.path.lexists(dest_file):
165                raise FileNotFoundError(f"target symlink {dest_file} to {symlink_path} create failed")
166
167    # write install module info to file
168    write_json_file(install_modules_info_file, modules_info_dict)
169
170    # write all module info
171    write_json_file(modules_info_file, output_result)
172
173    # output module list to file
174    write_file(module_list_file, '\n'.join(dest_list))
175
176
177def main():
178    parser = argparse.ArgumentParser()
179    parser.add_argument('--system-install-info-file', required=True)
180    parser.add_argument('--install-modules-info-file', required=True)
181    parser.add_argument('--modules-info-file', required=True)
182    parser.add_argument('--modules-list-file', required=True)
183    parser.add_argument('--platform-installed-path', required=True)
184    parser.add_argument('--system-dir', required=True)
185    parser.add_argument('--sa-profile-extract-dir', required=True)
186    parser.add_argument('--merged-sa-profile', required=True)
187    parser.add_argument('--depfile', required=True)
188    parser.add_argument('--system-image-zipfile', required=True)
189    parser.add_argument('--host-toolchain', required=True)
190    parser.add_argument('--categorized-libraries', required=False)
191    parser.add_argument(
192        '--additional-system-files',
193        action='append',
194        help="additional system files is used for files don't have module infos. \
195                use with caution"
196    )
197    parser.add_argument('--post-process-modules-info-files',
198                        nargs='*',
199                        default=[])
200    args = parser.parse_args()
201
202    additional_system_files = []
203    for tuples in args.additional_system_files or []:
204        filepath, system_path = tuples.split(':')
205        additional_system_files.append((filepath, system_path))
206
207    depfiles = []
208    build_utils.extract_all(args.merged_sa_profile,
209                            args.sa_profile_extract_dir,
210                            no_clobber=False)
211    sa_files = build_utils.get_all_files(args.sa_profile_extract_dir)
212
213    system_install_info = read_json_file(args.system_install_info_file)
214    if system_install_info is None:
215        raise Exception("read file '{}' failed.".format(
216            args.system_install_info_file))
217
218    system_install_base_dir = args.system_dir
219    if os.path.exists(system_install_base_dir):
220        shutil.rmtree(system_install_base_dir)
221        print('remove system dir...')
222    os.makedirs(system_install_base_dir, exist_ok=True)
223
224    vendor_install_base_dir = os.path.join(args.platform_installed_path,
225                                           'vendor')
226    if os.path.exists(vendor_install_base_dir):
227        shutil.rmtree(vendor_install_base_dir)
228        print('remove vendor dir...')
229
230    eng_system_install_base_dir = os.path.join(args.platform_installed_path,
231                                           'eng_system')
232    if os.path.exists(eng_system_install_base_dir):
233        shutil.rmtree(eng_system_install_base_dir)
234        print('remove eng_system dir...')
235
236    eng_chipset_install_base_dir = os.path.join(args.platform_installed_path,
237                                           'eng_chipset')
238    if os.path.exists(eng_chipset_install_base_dir):
239        shutil.rmtree(eng_chipset_install_base_dir)
240        print('remove eng_chipset dir...')
241
242    sys_prod_install_base_dir = os.path.join(args.platform_installed_path,
243                                           'sys_prod')
244    if os.path.exists(sys_prod_install_base_dir):
245        shutil.rmtree(sys_prod_install_base_dir)
246        print('remove sys_prod dir...')
247
248    chip_prod_install_base_dir = os.path.join(args.platform_installed_path,
249                                           'chip_prod')
250    if os.path.exists(chip_prod_install_base_dir):
251        shutil.rmtree(chip_prod_install_base_dir)
252        print('remove chip_prod dir...')
253
254    updater_install_base_dir = os.path.join(args.platform_installed_path,
255                                            'updater')
256    if os.path.exists(updater_install_base_dir):
257        shutil.rmtree(updater_install_base_dir)
258        print('remove updater dir...')
259
260    updater_vendor_install_base_dir = os.path.join(args.platform_installed_path,
261                                            'updater_vendor')
262    if os.path.exists(updater_vendor_install_base_dir):
263        shutil.rmtree(updater_vendor_install_base_dir)
264        print('remove updater dir...')
265
266    ramdisk_install_base_dir = os.path.join(args.platform_installed_path,
267                                            'ramdisk')
268    if os.path.exists(ramdisk_install_base_dir):
269        shutil.rmtree(ramdisk_install_base_dir)
270        print('remove ramdisk dir...')
271
272    print('copy modules...')
273    categorized_libraries = load_categorized_libraries(args.categorized_libraries)
274    copy_modules(system_install_info, args.install_modules_info_file,
275                 args.modules_info_file, args.modules_list_file,
276                 args.post_process_modules_info_files,
277                 args.platform_installed_path, args.host_toolchain,
278                 additional_system_files, depfiles, categorized_libraries)
279
280    if os.path.exists(args.system_image_zipfile):
281        os.unlink(args.system_image_zipfile)
282    build_utils.zip_dir(args.system_image_zipfile, args.system_dir)
283    depfiles.extend([item for item in depfiles if item not in sa_files])
284    build_utils.write_depfile(args.depfile, args.install_modules_info_file,
285                              depfiles)
286    return 0
287
288
289if __name__ == '__main__':
290    sys.exit(main())
291