• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright (c) 2024 Huawei Device Co., Ltd.
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18import json
19import os
20import subprocess
21import shutil
22import argparse
23import sys
24import urllib.request
25import socket
26
27
28def _run_cmd(cmd):
29    res = subprocess.Popen(cmd, stdout=subprocess.PIPE,
30                           stderr=subprocess.PIPE)
31    sout, serr = res.communicate(timeout=10000)
32    return sout.rstrip().decode('utf-8'), serr, res.returncode
33
34
35def _check_sha256(check_url: str, local_file: str) -> bool:
36    check_sha256_cmd = ('curl -s -k ' + check_url + '.sha256').split(' ')
37    local_sha256_cmd = ['sha256sum', local_file]
38    check_sha256, err, returncode = _run_cmd(check_sha256_cmd)
39    local_sha256, err, returncode = _run_cmd(local_sha256_cmd)
40    local_sha256 = local_sha256.split(' ')[0]
41    if check_sha256 != local_sha256:
42        print('remote file {}.sha256 is not found, begin check SHASUMS256.txt'.format(check_url))
43        check_sha256 = _obtain_sha256_by_sha_sums256(check_url)
44    return check_sha256 == local_sha256
45
46
47def _obtain_sha256_by_sha_sums256(check_url: str) -> str:
48    sha_sums256 = 'SHASUMS256.txt'
49    sha_sums256_path = os.path.join(os.path.dirname(check_url), sha_sums256)
50    file_name = os.path.basename(check_url)
51    cmd = ('curl -s -k ' + sha_sums256_path).split(' ')
52    data_sha_sums256, err, returncode = _run_cmd(cmd)
53    check_sha256 = None
54    for line in data_sha_sums256.split('\n'):
55        if file_name in line:
56            check_sha256 = line.split(' ')[0]
57    return check_sha256
58
59
60def npm_install(dir):
61    result = subprocess.run(["npm", "install", "--prefix", dir], capture_output=True, text=True)
62    if result.returncode == 0:
63        print("{}目录下npm install完毕".format(dir))
64    else:
65        print("依赖项安装失败:", result.stderr)
66
67
68def copy_file(src, dest):
69    if not os.path.exists(dest):
70        os.makedirs(dest)
71    shutil.copy(src, dest)
72
73
74def copy_folder(src, dest):
75    if os.path.exists(dest):
76        if os.path.islink(dest):
77            os.unlink(dest)
78        else:
79            shutil.rmtree(dest)
80    shutil.copytree(src, dest)
81
82
83def symlink_src2dest(src_dir, dest_dir):
84    if os.path.exists(dest_dir):
85        if os.path.islink(dest_dir):
86            os.unlink(dest_dir)
87        elif os.path.isdir(dest_dir):
88            shutil.rmtree(dest_dir)
89        else:
90            os.remove(dest_dir)
91    else:
92        os.makedirs(os.path.dirname(dest_dir), exist_ok=True)
93
94    print("symlink {} ---> {}".format(src_dir, dest_dir))
95    os.symlink(src_dir, dest_dir)
96
97
98def install_hpm(code_path, download_dir, symlink_dir, home_path):
99    content = """\
100package-lock=true
101registry=http://repo.huaweicloud.com/repository/npm
102strict-ssl=false
103lockfile=false
104"""
105    with os.fdopen(os.open(os.path.join(home_path, '.npmrc'), os.O_WRONLY | os.O_CREAT, mode=0o640), 'w') as f:
106        os.truncate(f.fileno(), 0)
107        f.write(content)
108    if not os.path.exists(download_dir):
109        os.makedirs(download_dir)
110    with os.fdopen(os.open(os.path.join(download_dir, 'package.json'), os.O_WRONLY | os.O_CREAT, mode=0o640),
111                    'w') as f:
112        os.truncate(f.fileno(), 0)
113        f.write('{}\n')
114    npm_path = os.path.join(code_path, "prebuilts/build-tools/common/nodejs/current/bin/npm")
115    node_bin_path = os.path.join(code_path, "prebuilts/build-tools/common/nodejs/current/bin")
116    os.environ['PATH'] = f"{node_bin_path}:{os.environ['PATH']}"
117    subprocess.run(
118        [npm_path, 'install', '@ohos/hpm-cli', '--registry', 'https://repo.huaweicloud.com/repository/npm/', '--prefix',
119         download_dir])
120    symlink_src2dest(os.path.join(download_dir, 'node_modules'), symlink_dir)
121
122
123def process_npm(npm_dict, args):
124    code_path = args.code_path
125    home_path = args.home_path
126    name = npm_dict.get('name')
127    npm_download = npm_dict.get('download')
128    package_path = os.path.join(code_path, npm_download.get('package_path'))
129    package_lock_path = os.path.join(code_path, npm_download.get('package_lock_path'))
130    hash_value = \
131        subprocess.run(['sha256sum', package_lock_path], capture_output=True, text=True).stdout.strip().split(' ')[0]
132    download_dir = os.path.join(home_path, npm_download.get('download_dir'), hash_value)
133
134    if '@ohos/hpm-cli' == name:
135        symlink = os.path.join(code_path, npm_download.get('symlink'))
136        install_hpm(code_path, os.path.join(home_path, download_dir), os.path.join(code_path, symlink), home_path)
137        return
138
139    copy_file(package_path, download_dir)
140    copy_file(package_lock_path, download_dir)
141
142    if not os.path.exists(os.path.join(download_dir, "npm-install.js")):
143        npm_install_script = os.path.join(os.path.dirname(package_path), "npm-install.js")
144        if os.path.exists(npm_install_script):
145            shutil.copyfile(npm_install_script, os.path.join(download_dir, "npm-install.js"))
146
147    npm_install(download_dir)
148
149    if name == 'legacy_bin':
150        for link in npm_download.get('symlink', []):
151            symlink_src2dest(os.path.join(download_dir, "node_modules"), os.path.join(code_path, link))
152        return
153
154    symlink = os.path.join(code_path, npm_download.get('symlink'))
155
156    if name in ['parse5']:
157        copy_folder(os.path.join(download_dir, "node_modules"), symlink)
158        return
159
160    copy_folder(os.path.join(download_dir, "node_modules"), symlink)
161
162    for copy_entry in npm_download.get('copy', []):
163        copy_folder(os.path.join(code_path, copy_entry['src']), os.path.join(code_path, copy_entry['dest']))
164
165    for copy_ext_entry in npm_download.get('copy_ext', []):
166        copy_folder(os.path.join(code_path, copy_ext_entry['src']), os.path.join(code_path, copy_ext_entry['dest']))
167
168
169def download_url(url, folder_path):
170    filename = url.split('/')[-1]
171    file_path = os.path.join(folder_path, filename)
172    if os.path.exists(file_path):
173        if _check_sha256(url, file_path):
174            return
175        else:
176            os.remove(file_path)
177    if not os.path.exists(folder_path):
178        os.makedirs(folder_path)
179    try:
180        print("Downloading {}".format(url))
181        with urllib.request.urlopen(url) as response, os.fdopen(
182                os.open(file_path, os.O_WRONLY | os.O_CREAT, mode=0o640), 'wb') as out_file:
183            total_size = int(response.headers['Content-Length'])
184            chunk_size = 16 * 1024
185            downloaded_size = 0
186            print_process(chunk_size, downloaded_size, out_file, response, total_size)
187        print("\n{} downloaded successfully".format(url))
188    except urllib.error.URLError as e:
189        print("Error:", e.reason)
190    except socket.timeout:
191        print("Timeout error: Connection timed out")
192
193
194def print_process(chunk_size, downloaded_size, out_file, response, total_size):
195    while True:
196        chunk = response.read(chunk_size)
197        if not chunk:
198            break
199        out_file.write(chunk)
200        downloaded_size += len(chunk)
201        if total_size != 0:
202            progress = downloaded_size / total_size * 50
203            print(f'\r[{"=" * int(progress)}{" " * (50 - int(progress))}] {progress * 2:.2f}%', end='', flush=True)
204        else:
205            print("\r[Error] Total size is zero, unable to calculate progress.", end='', flush=True)
206
207
208def extract_compress_files(source_file, destination_folder):
209    if not os.path.exists(destination_folder):
210        os.makedirs(destination_folder, exist_ok=True)
211    if source_file.endswith('.zip'):
212        command = ['unzip', '-qq', '-o', '-d', destination_folder, source_file]
213    elif source_file.endswith('.tar.gz'):
214        command = ['tar', '-xzf', source_file, '-C', destination_folder]
215    elif source_file.endswith('.tar.xz'):
216        command = ['tar', '-xJf', source_file, '-C', destination_folder]
217    else:
218        print("暂不支持解压此类型压缩文件!")
219        command = []
220    try:
221        subprocess.run(command, check=True)
222        print(f"{source_file} extracted to {destination_folder}")
223    except subprocess.CalledProcessError as e:
224        print(f"Error: {e}")
225
226
227def install_python(version, download_dir, one_type, code_path):
228    after_extract_folder = os.listdir(os.path.join(download_dir, version))[0]
229    copy_folder(os.path.join(download_dir, version, after_extract_folder, one_type.get('copy_src')),
230                os.path.join(download_dir, version, after_extract_folder, one_type.get('copy_dest')))
231    copy_folder(os.path.join(download_dir, version, after_extract_folder),
232                os.path.join(code_path, one_type.get('symlink')))
233    python3_path = os.path.join(download_dir, version, after_extract_folder, one_type.get('copy_src'),
234                                'bin', 'python3.10')
235    pip3_path = os.path.join(download_dir, version, after_extract_folder, one_type.get('copy_src'), 'bin',
236                             'pip3.10')
237    subprocess.run(
238        [python3_path, pip3_path, "install", "--trusted-host", "repo.huaweicloud.com", "-i",
239         "http://repo.huaweicloud.com/repository/pypi/simple"] + one_type.get(
240            'pip_install'))
241
242
243def install_rustc(url, download_dir, version, one_type, code_path):
244    part_file_name = url.split('/')[-1].split('linux')[0]
245    after_extract_file_list = os.listdir(os.path.join(download_dir, version))
246    for file_name in after_extract_file_list:
247        if part_file_name in file_name:
248            script_path = os.path.join(download_dir, version, file_name, "install.sh")
249            subprocess.run([script_path, "--prefix=''",
250                            "--destdir='{}'".format(os.path.join(code_path, one_type.get('destdir')))])
251            break
252
253
254def process_tar(tar_dict, args):
255    code_path = args.code_path
256    home_path = args.home_path
257    os_type = args.target_os
258    cpu_type = args.target_cpu
259    tar_name = tar_dict.get('name')
260    print(tar_name)
261    tar_download = tar_dict.get('download')
262    for one_type in tar_download:
263        download_flag = download_or_not(cpu_type, one_type, os_type)
264        if download_flag == True:
265            version = one_type.get('version')
266            url = os.path.join(args.repo_https, one_type.get('url'))
267            download_dir = os.path.join(home_path, one_type.get('download_dir'))
268            download_url(url, download_dir)
269            extract_compress_files(os.path.join(download_dir, url.split('/')[-1]),
270                                   os.path.join(download_dir, version))
271            if tar_name == 'python':
272                install_python(version, download_dir, one_type, code_path)
273                continue
274            if 'rustc' in tar_name:
275                install_rustc(url, download_dir, version, one_type, code_path)
276                continue
277            if tar_name == 'llvm':
278                after_extract_folder = os.listdir(os.path.join(download_dir, version))[0]
279                copy_folder(os.path.join(download_dir, version, after_extract_folder, one_type.get('copy_src')),
280                            os.path.join(download_dir, version, after_extract_folder, one_type.get('copy_dest')))
281                copy_folder(os.path.join(download_dir, version, after_extract_folder),
282                            os.path.join(code_path, one_type.get('symlink')))
283                continue
284            if tar_name in ['ark_tools']:
285                after_extract_folder = os.listdir(os.path.join(download_dir, version))[0]
286                copy_folder(os.path.join(download_dir, version, after_extract_folder),
287                            os.path.join(code_path, one_type.get('symlink')))
288                continue
289            after_extract_file_list = os.listdir(os.path.join(download_dir, version))
290            symlink = os.path.join(code_path, one_type.get('symlink'))
291            if one_type.get('type') == 'dir':
292                deal_tar_dir(after_extract_file_list, download_dir, symlink, tar_name, version)
293            else:
294                file_name = after_extract_file_list[0]
295                symlink_src2dest(os.path.join(download_dir, version, file_name), symlink)
296            if tar_name == 'nodejs' and url == os.path.join(args.repo_https,
297                                                            "nodejs/v14.21.1/node-v14.21.1-linux-x64.tar.gz"):
298                symlink_src2dest(symlink, os.path.join(os.path.dirname(symlink), 'current'))
299
300
301def download_or_not(cpu_type, one_type, os_type):
302    download_flag = False
303    if cpu_type == 'any':
304        if one_type.get('target_os') == os_type:
305            download_flag = True
306    else:
307        if one_type.get('target_os') == os_type and (
308                one_type.get('target_cpu') == cpu_type or one_type.get('target_cpu') == ""):
309            download_flag = True
310    return download_flag
311
312
313def deal_tar_dir(after_extract_file_list, download_dir, symlink, tar_name, version):
314    for one_file in after_extract_file_list:
315        if tar_name == 'packing_tool':
316            symlink_src2dest(os.path.join(download_dir, version, one_file),
317                             os.path.join(symlink, one_file))
318        else:
319            symlink_src2dest(os.path.join(download_dir, version, one_file),
320                             symlink)
321
322
323def main():
324    parser = argparse.ArgumentParser()
325    parser.add_argument('--code_path', required=True, type=str, help='path of openharmony code')
326    parser.add_argument('--home_path', required=True, type=str, help='path of home')
327    parser.add_argument('--config_file', required=True, type=str, help='path of prebuilts_config.json')
328    parser.add_argument('--repo_https', required=True, type=str, default='https://repo.huaweicloud.com',
329                        help='path of prebuilts_config.json')
330    parser.add_argument('--target_os', required=True, type=str, help='type of os')
331    parser.add_argument('--target_cpu', type=str, default='any', help='type of cpu')
332    args = parser.parse_args()
333    config_file = args.config_file
334    with open(config_file, 'r', encoding='utf-8') as r:
335        config = json.load(r)
336    tar = config['tar']
337    for one_tar in tar:
338        process_tar(one_tar, args)
339    npm = config['npm']
340    for one_npm in npm:
341        process_npm(one_npm, args)
342
343
344if __name__ == '__main__':
345    sys.exit(main())
346