1#!/usr/bin/env python3
2# coding: utf-8
3
4"""
5Copyright (c) 2024 Huawei Device Co., Ltd.
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17"""
18
19import argparse
20import asyncio
21import json
22import os
23import shutil
24import sys
25
26import yaml
27
28
29def parse_configs():
30    config_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../config.yaml')
31    with open(config_file_path, 'r', encoding='utf-8') as config_file:
32        configs = yaml.safe_load(config_file)
33    return configs
34
35
36def get_output_path_list(file_name):
37    configs = parse_configs()
38    download_list = configs['download_list']
39    for item in download_list:
40        if item['name'] in file_name:
41            output_path_list = item['output_path_list']
42    return output_path_list
43
44
45def is_mac():
46    return sys.platform == 'darwin'
47
48
49def get_api_version(json_path):
50    with open(json_path, 'r') as uni:
51        uni_cont = uni.read()
52        uni_data = json.loads(uni_cont)
53        api_version = uni_data['apiVersion']
54    return api_version
55
56
57def before_update_sdk(file_path):
58    pass
59
60
61def after_update_sdk(file_path, output_path):
62    if is_mac():
63        add_executable_permission_for_mac(output_path)
64    # modify sdk version while api version is different from your download
65    modify_package_json(file_path, output_path)
66
67
68def add_executable_permission(file_path):
69    current_mode = os.stat(file_path).st_mode
70    new_mode = current_mode | 0o111
71    os.chmod(file_path, new_mode)
72
73
74def add_executable_permission_for_mac(sdk_path):
75    for item in os.listdir(sdk_path):
76        if item != '.DS_Store':
77            if item == 'toolchains':
78                add_executable_permission(
79                    os.path.join(sdk_path, item, 'restool'))
80                add_executable_permission(
81                    os.path.join(sdk_path, item, 'ark_disasm'))
82            elif item == 'ets':
83                add_executable_permission(os.path.join(sdk_path, item, 'build-tools',
84                                                       'ets-loader', 'bin', 'ark', 'build-mac', 'bin', 'es2abc'))
85                add_executable_permission(os.path.join(sdk_path, item, 'build-tools',
86                                                       'ets-loader', 'bin', 'ark', 'build-mac', 'legacy_api8',
87                                                       'bin', 'js2abc'))
88            elif item == 'js':
89                add_executable_permission(os.path.join(sdk_path, item, 'build-tools',
90                                                       'ace-loader', 'bin', 'ark', 'build-mac', 'bin', 'es2abc'))
91                add_executable_permission(os.path.join(sdk_path, item, 'build-tools',
92                                                       'ace-loader', 'bin', 'ark', 'build-mac', 'legacy_api8',
93                                                       'bin', 'js2abc'))
94
95
96def get_output_path_api_version(output_path):
97    api_version = os.path.basename(output_path)
98    if api_version == 'openharmony':
99        parts = output_path.split(os.sep)
100        if len(parts) >= 2:
101            filename = parts[-2]
102            configs = parse_configs()
103            download_list = configs.get('download_list')
104            sdk_item = next((item for item in download_list if item.get('name') == 'sdk'), None)
105            api_version_file_map = sdk_item.get('api_version_file_name_map') if sdk_item else {}
106            api_version = api_version_file_map.get(filename)
107        else:
108            api_version = None
109
110    return api_version
111
112
113def modify_package_json(file_path, output_path):
114    output_path_version = get_output_path_api_version(output_path)
115    if output_path_version is None:
116        print('Modify package json failed, Please check your configuration file'
117              ' to ensure the mapping between API and file names is correct.')
118        return
119    api_version = get_api_version(os.path.join(
120        *[file_path, 'ets', 'oh-uni-package.json']))
121    if output_path_version != api_version:
122        for file_name in os.listdir(output_path):
123            if file_name == '.DS_Store':
124                continue
125            package_json_path = os.path.join(output_path, rf'{file_name}/oh-uni-package.json')
126            with open(package_json_path, 'r+') as json_file:
127                json_file.seek(0)
128                data = json.load(json_file)
129                data['apiVersion'] = get_output_path_api_version(output_path)
130                json_file.seek(0)
131                json.dump(data, json_file, indent=2)
132                json_file.truncate()
133
134
135async def update_sdk_to_output_path(file_path, output_path):
136    before_update_sdk(file_path)
137    await copy_image_async(file_path, output_path)
138    after_update_sdk(file_path, output_path)
139
140
141async def update_dayu_to_output_path(file_path, output_path):
142    await copy_image_async(file_path, output_path)
143
144
145async def copy_image_async(file_path, output_path):
146    if os.path.exists(output_path):
147        loop = asyncio.get_event_loop()
148        await loop.run_in_executor(None, shutil.rmtree, output_path)
149    print(f'Copy from {file_path} to {output_path}, please wait!!!')
150    loop = asyncio.get_event_loop()
151    await loop.run_in_executor(None, shutil.copytree, file_path, output_path)
152
153
154async def update_image_async(file_path, output_path, semaphore):
155    await semaphore.acquire()
156    try:
157        update_task_mapping = {
158            "sdk": update_sdk_to_output_path,
159            "dayu": update_dayu_to_output_path
160        }
161        for task in update_task_mapping:
162            if task in file_path:
163                await update_task_mapping[task](file_path, output_path)
164                await asyncio.sleep(1)
165                print(f'File copied to {output_path} successfully')
166                break
167    finally:
168        semaphore.release()
169
170
171def parse_args():
172    parser = argparse.ArgumentParser()
173    parser.add_argument('--sdkFilePath', type=str, dest='sdk_file_path', default=None,
174                        help='specify which sdk image you want to copy')
175    parser.add_argument('--sdkOutputPath', type=str, dest='sdk_output_path', default=None,
176                        nargs='+',
177                        help='specify where you want to store the file')
178    parser.add_argument('--dayuFilePath', type=str, dest='dayu_file_path', default=None,
179                        help='specify which dayu image you want to copy')
180    parser.add_argument('--dayuOutputPath', type=str, dest='dayu_output_path', default=None,
181                        nargs='+',
182                        help='specify where you want to store the file')
183
184    return parser.parse_args()
185
186
187async def start_update_image_task(file_path, output_path_list, max_async_tasks=3):
188    if output_path_list is None:
189        output_path_list = get_output_path_list(file_path)
190    semaphore = asyncio.Semaphore(max_async_tasks)
191    tasks = [asyncio.create_task(update_image_async(file_path, output_path, semaphore))
192             for output_path in output_path_list]
193
194    await asyncio.gather(*tasks)
195
196
197async def run():
198    arguments = parse_args()
199
200    if arguments.sdk_file_path is not None:
201        await start_update_image_task(arguments.sdk_file_path, arguments.sdk_output_path)
202    if arguments.dayu_file_path is not None:
203        await start_update_image_task(arguments.dayu_file_path, arguments.dayu_output_path)
204    if arguments.sdk_file_path is None and arguments.dayu_file_path is None:
205        print('please input which image you want to copy')
206        return
207
208
209if __name__ == '__main__':
210    asyncio.run(run())
211