diff --git a/prebuilts_config.json b/prebuilts_config.json
index 2ae636310e7dd97128df8e10afcecb6dfd05d70d..9a6371dbbf1a891318a9e7b420e5a96edfe6c537 100644
--- a/prebuilts_config.json
+++ b/prebuilts_config.json
@@ -1,409 +1,399 @@
{
- "npm": [
- {
- "name": "@ohos/hpm-cli",
- "download": {
- "version": "1.6.1",
- "package_path": "",
- "package_lock_path": "",
- "download_dir": ".prebuilts_cache/hpm",
- "symlink": "prebuilts/hpm/node_modules"
- }
- }
- ],
- "tar": [
- {
- "name": "nodejs",
- "tag": "base",
- "download": [
+ "download_root": "${code_dir}/../openharmony_prebuilts",
+ "tool_list": [
{
- "target_os": "linux",
- "target_cpu": "",
- "version": "v14.21.1",
- "url": "nodejs/v14.21.1/node-v14.21.1-linux-x64.tar.gz",
- "download_dir": ".prebuilts_cache/build-tools/common/nodejs",
- "symlink": "prebuilts/build-tools/common/nodejs/node-v14.21.1-linux-x64",
- "type": "dir"
+ "name": "ark_js_prebuilts",
+ "tag": "base",
+ "type": "src, indep",
+ "config": {
+ "linux": {
+ "arm64": {
+ "remote_url": "/openharmony/compiler/llvm_prebuilt_libs/ark_js_prebuilts_20231215.tar.gz"
+ },
+ "x86_64": {
+ "remote_url": "/openharmony/compiler/llvm_prebuilt_libs/ark_js_prebuilts_20230713.tar.gz"
+ }
+ },
+ "darwin": {
+ "arm64": {
+ "remote_url": "/openharmony/compiler/llvm_prebuilt_libs/ark_js_prebuilts_darwin_arm64_20230209.tar.gz"
+ },
+ "x86_64": {
+ "remote_url": "/openharmony/compiler/llvm_prebuilt_libs/ark_js_prebuilts_darwin_x64_20230209.tar.gz"
+ }
+ }
+ },
+ "unzip_dir": "${code_dir}/prebuilts/ark_tools",
+ "unzip_filename": "ark_js_prebuilts"
},
{
- "target_os": "darwin",
- "target_cpu": "",
- "version": "v14.21.1",
- "url": "nodejs/v14.21.1/node-v14.21.1-darwin-x64.tar.gz",
- "download_dir": ".prebuilts_cache/build-tools/common/nodejs",
- "symlink": "prebuilts/build-tools/common/nodejs/node-v14.21.1-darwin-x86",
- "type": "dir"
- }
- ]
- },
- {
- "name": "gn",
- "tag": "base",
- "download": [
- {
- "target_os": "linux",
- "target_cpu": "x86_64",
- "version": "20250509",
- "url": "openharmony/compiler/gn/20250509/gn-linux-x86-20250509.tar.gz",
- "download_dir": ".prebuilts_cache/build-tools/linux-x86/bin/gn",
- "symlink": "prebuilts/build-tools/linux-x86/bin/gn",
- "type": "file"
- },
- {
- "target_os": "linux",
- "target_cpu": "arm64",
- "version": "20240510",
- "url": "openharmony/compiler/gn/20240510/gn-linux-x86-20240510.tar.gz",
- "download_dir": ".prebuilts_cache/build-tools/linux-x86/bin/gn",
- "symlink": "prebuilts/build-tools/linux-x86/bin/gn",
- "type": "file"
- },
- {
- "target_os": "darwin",
- "target_cpu": "x86_64",
- "version": "20240416",
- "url": "openharmony/compiler/gn/20240416/gn-darwin-x86-20240416.tar.gz",
- "download_dir": ".prebuilts_cache/build-tools/darwin-x86/bin/gn",
- "symlink": "prebuilts/build-tools/darwin-x86/bin/gn",
- "type": "file"
- },
- {
- "target_os": "darwin",
- "target_cpu": "arm64",
- "version": "20240416",
- "url": "openharmony/compiler/gn/20240416/gn-darwin-x86-20240416.tar.gz",
- "download_dir": ".prebuilts_cache/build-tools/darwin-x86/bin/gn",
- "symlink": "prebuilts/build-tools/darwin-x86/bin/gn",
- "type": "file"
- }
- ]
- },
- {
- "name": "packing_tool",
- "tag": "base",
- "download": [
- {
- "target_os": "linux",
- "target_cpu": "x86_64",
- "version": "20241022",
- "url": "harmonyos/compiler/packing_tool/packing_tool_libs_20250215.zip",
- "download_dir": ".prebuilts_cache/packing_tool",
- "symlink": "prebuilts/packing_tool",
- "type": "dir"
- },
- {
- "target_os": "linux",
- "target_cpu": "arm64",
- "version": "20241022",
- "url": "harmonyos/compiler/packing_tool/packing_tool_libs_20250215.zip",
- "download_dir": ".prebuilts_cache/packing_tool",
- "symlink": "prebuilts/packing_tool",
- "type": "dir"
- },
- {
- "target_os": "darwin",
- "target_cpu": "x86_64",
- "version": "20241022",
- "url": "/harmonyos/compiler/packing_tool/packing_tool_libs_20250215.zip",
- "download_dir": ".prebuilts_cache/packing_tool",
- "symlink": "prebuilts/packing_tool",
- "type": "dir"
- },
- {
- "target_os": "darwin",
- "target_cpu": "arm64",
- "version": "20241022",
- "url": "/harmonyos/compiler/packing_tool/packing_tool_libs_20250215.zip",
- "download_dir": ".prebuilts_cache/packing_tool",
- "symlink": "prebuilts/packing_tool",
- "type": "dir"
- }
- ]
- },
- {
- "name": "ninja",
- "tag": "base",
- "download": [
- {
- "target_os": "linux",
- "target_cpu": "x86_64",
- "version": "20240416",
- "url": "openharmony/compiler/ninja/20240416/ninja-linux-x86-20240416.tar.gz",
- "download_dir": ".prebuilts_cache/build-tools/linux-x86/bin/ninja",
- "symlink": "prebuilts/build-tools/linux-x86/bin/ninja",
- "type": "file"
+ "name": "llvm",
+ "tag": "base",
+ "type": "src, indep",
+ "unzip_filename": "llvm",
+ "config": {
+ "linux": {
+ "arm64": {
+ "remote_url": "/openharmony/compiler/clang/15.0.4-da9259/linux_aarch64/clang_linux_aarch64-da9259-20250425.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/clang/ohos/linux-aarch64",
+ "rename_src": "${unzip_dir}/clang_linux_aarch64-da9259-20250425",
+ "type": "src"
+ },
+ "x86_64": [
+ {
+ "remote_url": "/openharmony/compiler/clang/15.0.4-da9259/ohos_arm64/clang_ohos-arm64-da9259-20250425.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/clang/ohos/ohos-arm64",
+ "rename_src": "${unzip_dir}/clang_ohos-arm64-da9259-20250425",
+ "type": "src"
+ },
+ {
+ "remote_url": "/openharmony/compiler/clang/15.0.4-da9259/windows/clang_windows-x86_64-da9259-20250425.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/clang/ohos/windows-x86_64",
+ "rename_src": "${unzip_dir}/clang_windows-x86_64-da9259-20250425",
+ "type": "src"
+ },
+ {
+ "remote_url": "/openharmony/compiler/clang/15.0.4-da9259/linux/clang_linux-x86_64-da9259-20250425.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/clang/ohos/linux-x86_64",
+ "rename_src": "${unzip_dir}/clang_linux-x86_64-da9259-20250425"
+ }
+ ]
+ },
+ "darwin": {
+ "arm64": {
+ "remote_url": "/openharmony/compiler/clang/15.0.4-da9259/darwin_arm64/clang_darwin-arm64-da9259-20250425.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/clang/ohos/darwin-arm64",
+ "rename_src": "${unzip_dir}/clang_darwin-arm64-da9259-20250425"
+ },
+ "x86_64": {
+ "remote_url": "/openharmony/compiler/clang/15.0.4-da9259/darwin_x86_64/clang_darwin-x86_64-da9259-20250425.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/clang/ohos/darwin-x86_64",
+ "rename_src": "${unzip_dir}/clang_darwin-x86_64-da9259-20250425"
+ }
+ }
+ },
+ "handle": [
+ {
+ "type": "move",
+ "src": "${rename_src}",
+ "dest": "${unzip_dir}/llvm"
+ },
+ {
+ "type": "symlink",
+ "src": "${unzip_dir}/llvm/lib/clang/15.0.4",
+ "dest": "${unzip_dir}/llvm/lib/clang/current"
+ }
+ ]
},
{
- "target_os": "linux",
- "target_cpu": "arm64",
- "version": "20240416",
- "url": "openharmony/compiler/ninja/20240416/ninja-linux-x86-20240416.tar.gz",
- "download_dir": ".prebuilts_cache/build-tools/linux-x86/bin/ninja",
- "symlink": "prebuilts/build-tools/linux-x86/bin/ninja",
- "type": "file"
+ "name": "gn",
+ "tag": "base",
+ "type": "src, indep",
+ "unzip_filename": "gn",
+ "config": {
+ "linux": {
+ "x86_64": {
+ "remote_url": "/openharmony/compiler/gn/20250509/gn-linux-x86-20250509.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/build-tools/linux-x86/bin"
+ },
+ "arm64": {
+ "remote_url": "/openharmony/compiler/gn/20240530/gn-linux-aarch64-20240530.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/build-tools/linux-aarch64/bin"
+ }
+ },
+ "darwin": {
+ "x86_64, arm64": {
+ "remote_url": "/openharmony/compiler/gn/20240416/gn-darwin-x86-20240416.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/build-tools/darwin-x86/bin"
+ }
+ }
+ }
},
{
- "target_os": "darwin",
- "target_cpu": "x86_64",
- "version": "1.11.0",
- "url": "openharmony/compiler/ninja/1.11.0/darwin/ninja-darwin-x86-1.11.0.tar.gz",
- "download_dir": ".prebuilts_cache/build-tools/darwin-x86/bin/ninja",
- "symlink": "prebuilts/build-tools/darwin-x86/bin/ninja",
- "type": "file"
+ "name": "hc-gen",
+ "tag": "base",
+ "type": "src, indep",
+ "config": {
+ "linux": {
+ "x86_64": {
+ "remote_url": "/openharmony/compiler/hc-gen/linux/hc-gen-20240926.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/hc_gen",
+ "unzip_filename": "hc-gen"
+ }
+ }
+ }
},
{
- "target_os": "darwin",
- "target_cpu": "arm64",
- "version": "1.11.0",
- "url": "openharmony/compiler/ninja/1.11.0/darwin/ninja-darwin-x86-1.11.0.tar.gz",
- "download_dir": ".prebuilts_cache/build-tools/darwin-x86/bin/ninja",
- "symlink": "prebuilts/build-tools/darwin-x86/bin/ninja",
- "type": "file"
+ "name": "OpenHarmonyApplication.pem",
+ "tag": "base",
+ "type": "indep",
+ "config": {
+ "linux": {
+ "x86_64": {
+ "remote_url": "/openharmony/compiler/certificates/20241025/OpenHarmonyApplication.zip",
+ "unzip_dir": "${code_dir}/prebuilts/ohos-sdk",
+ "unzip_filename": "OpenHarmonyApplication.pem"
+ }
+ }
+ }
},
{
- "target_os": "ohos",
- "target_cpu": "arm64",
- "version": "1.12.0",
- "url": "openharmony/compiler/ninja/1.12.0/ohos/ninja-ohos-1.12.0-20240827.tar.gz",
- "download_dir": ".prebuilts_cache/build-tools/ohos/bin/ninja",
- "symlink": "prebuilts/build-tools/ohos/bin/ninja",
- "type": "file"
- }
- ]
- },
- {
- "name": "llvm",
- "tag": "base",
- "download": [
- {
- "target_os": "linux",
- "target_cpu": "arm64",
- "version": "20250425",
- "url": "openharmony/compiler/clang/15.0.4-da9259/linux/clang_linux-x86_64-da9259-20250425.tar.gz",
- "download_dir": ".prebuilts_cache/clang/ohos/linux-x86_64/llvm",
- "symlink": "prebuilts/clang/ohos/linux-x86_64/llvm",
- "type": "dir",
- "copy_src":"lib/clang/15.0.4",
- "copy_dest":"lib/clang/current"
+ "name": "ninja",
+ "tag": "base",
+ "type": "src, indep",
+ "unzip_filename": "ninja",
+ "config": {
+ "linux": {
+ "arm64": {
+ "remote_url": "/openharmony/compiler/ninja/1.12.0/linux/ninja-linux-aarch64-1.12.0-20241210.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/build-tools/linux-aarch64/bin"
+ },
+ "x86_64": [
+ {
+ "remote_url": "/openharmony/compiler/ninja/1.12.0/linux/ninja-linux-x86-1.12.0-20240523.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/build-tools/linux-x86/bin"
+ },
+ {
+ "remote_url": "/openharmony/compiler/ninja/1.12.0/windows/ninja-windows-x86-1.12.0-20240523.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/build-tools/windows-x86/bin",
+ "type": "src"
+ },
+ {
+ "remote_url": "/openharmony/compiler/ninja/1.12.0/ohos/ninja-ohos-1.12.0-20240827.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/build-tools/ohos/bin",
+ "type": "src"
+ }
+ ]
+ },
+ "darwin": {
+ "arm64": {
+ "remote_url": "/openharmony/compiler/ninja/1.12.0/darwin/arm/ninja-darwin-arm-1.12.0-20240829.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/build-tools/darwin-x86/bin"
+ },
+ "x86_64": {
+ "remote_url": "/openharmony/compiler/ninja/1.12.0/darwin/x86/ninja-darwin-x86-1.12.0-20240829.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/build-tools/darwin-x86/bin"
+ }
+ }
+ }
},
{
- "target_os": "linux",
- "target_cpu": "x86_64",
- "version": "20250425",
- "url": "openharmony/compiler/clang/15.0.4-da9259/linux/clang_linux-x86_64-da9259-20250425.tar.gz",
- "download_dir": ".prebuilts_cache/clang/ohos/linux-x86_64/llvm",
- "symlink": "prebuilts/clang/ohos/linux-x86_64/llvm",
- "type": "dir",
- "copy_src":"lib/clang/15.0.4",
- "copy_dest":"lib/clang/current"
+ "name": "node",
+ "tag": "base",
+ "type": "src, indep",
+ "unzip_dir": "${code_dir}/prebuilts/build-tools/common/nodejs",
+ "config": {
+ "linux": {
+ "arm64": {
+ "remote_url": "/openharmony/compiler/nodejs/v14.21.1/node-v14.21.1-linux-aarch64.tar.gz",
+ "unzip_filename": "node-v14.21.1-linux-aarch64",
+ "symlink_src": "${code_dir}/prebuilts/build-tools/common/nodejs/node-v14.21.1-linux-aarch64"
+ },
+ "x86_64": [
+ {
+ "remote_url": "/nodejs/v14.21.1/node-v14.21.1-linux-x64.tar.gz",
+ "unzip_filename": "node-v14.21.1-linux-x64",
+ "symlink_src": "${code_dir}/prebuilts/build-tools/common/nodejs/node-v14.21.1-linux-x64"
+ },
+ {
+ "remote_url": "/nodejs/v16.20.2/node-v16.20.2-linux-x64.tar.gz",
+ "unzip_filename": "node-v16.20.2-linux-x64"
+ }
+ ]
+ },
+ "darwin": [
+ {
+ "remote_url": "/nodejs/v14.21.1/node-v14.21.1-darwin-x64.tar.gz",
+ "unzip_filename": "node-v14.21.1-darwin-x64",
+ "symlink_src": "${code_dir}/prebuilts/build-tools/common/nodejs/node-v14.21.1-darwin-x64"
+ },
+ {
+ "remote_url": "/nodejs/v16.20.2/node-v16.20.2-darwin-x64.tar.gz",
+ "unzip_filename": "node-v16.20.2-darwin-x64"
+ }
+ ]
+ },
+ "handle": [
+ {
+ "type": "symlink",
+ "src": "${symlink_src}",
+ "dest": "${code_dir}/prebuilts/build-tools/common/nodejs/current"
+ }
+ ]
},
{
- "target_os": "darwin",
- "target_cpu": "arm64",
- "version": "20250425",
- "url": "openharmony/compiler/clang/15.0.4-da9259/darwin_x86/clang_darwin-x86_64-da9259-20250425.tar.gz",
- "download_dir": ".prebuilts_cache/clang/ohos/darwin-x86_64/llvm",
- "symlink": "prebuilts/clang/ohos/darwin-x86_64/llvm",
- "type": "dir",
- "copy_src":"lib/clang/15.0.4",
- "copy_dest":"lib/clang/current"
+ "name": "packing_tool",
+ "tag": "base",
+ "type": "src, indep",
+ "config": {
+ "linux, darwin": {
+ "arm64, x86_64": {
+ "remote_url": "/harmonyos/compiler/packing_tool/packing_tool_libs_20250215.zip",
+ "unzip_dir": "${code_dir}/prebuilts/packing_tool",
+ "unzip_filename": "packing_tool"
+ }
+ }
+ }
},
{
- "target_os": "darwin",
- "target_cpu": "x86_64",
- "version": "20250425",
- "url": "openharmony/compiler/clang/15.0.4-da9259/darwin_x86/clang_darwin-x86_64-da9259-20250425.tar.gz",
- "download_dir": ".prebuilts_cache/clang/ohos/darwin-x86_64/llvm",
- "symlink": "prebuilts/clang/ohos/darwin-x86_64/llvm",
- "type": "dir",
- "copy_src":"lib/clang/15.0.4",
- "copy_dest":"lib/clang/current"
- }
- ]
- },
- {
- "name": "python",
- "tag": "base",
- "download": [
- {
- "target_os": "linux",
- "target_cpu": "arm64",
- "version": "20240715",
- "url": "openharmony/compiler/python/3.11.4/linux/python-linux-x86-GLIBC2.27-3.11.4_20250219.tar.gz",
- "download_dir": ".prebuilts_cache/python/linux-x86",
- "symlink": "prebuilts/python/linux-x86",
- "type": "dir",
- "copy_src": "3.11.4",
- "copy_dest": "current",
- "pip_install": [
- "pyyaml",
- "requests>=2.32.1",
- "prompt_toolkit==1.0.14",
- "asn1crypto",
- "cryptography",
- "json5==0.9.6"
- ]
+ "name": "python",
+ "tag": "base",
+ "type": "src, indep",
+ "unzip_dir": "${code_dir}/prebuilts/python",
+ "config": {
+ "linux": {
+ "arm64": {
+ "remote_url": "/openharmony/compiler/python/3.11.4/linux/python-linux-arm64-3.11.4_20240715.tar.gz",
+ "unzip_filename": "linux-arm64"
+ },
+ "x86_64": {
+ "remote_url": "/openharmony/compiler/python/3.11.4/linux/python-linux-x86-GLIBC2.27-3.11.4_20250219.tar.gz",
+ "unzip_filename": "linux-x86"
+ }
+ },
+ "darwin": {
+ "x86_64": {
+ "remote_url": "/openharmony/compiler/python/3.11.4/darwin/python-darwin-x86-3.11.4_20250228.tar.gz",
+ "unzip_filename": "darwin-x86"
+ },
+ "arm64": {
+ "remote_url": "/openharmony/compiler/python/3.11.4/darwin/python-darwin-arm64-3.11.4_20250228.tar.gz",
+ "unzip_filename": "darwin-arm64"
+ }
+ }
+ },
+ "handle": [
+ {
+ "type": "symlink",
+ "src": "${unzip_dir}/${unzip_filename}/3.11.4",
+ "dest": "${unzip_dir}/${unzip_filename}/current"
+ },
+ {
+ "type": "shell",
+ "python_path": "${unzip_dir}/${unzip_filename}/current/bin/python3",
+ "pip_path": "${unzip_dir}/${unzip_filename}/current/bin/pip3",
+ "cmd": [
+ "${python_path}",
+ "${pip_path}",
+ "install",
+ "--trusted-host",
+ "repo.huaweicloud.com",
+ "-i",
+ "http://repo.huaweicloud.com/repository/pypi/simple",
+ "pyyaml",
+ "requests>=2.32.1",
+ "prompt_toolkit==1.0.14",
+ "asn1crypto",
+ "cryptography",
+ "json5==0.9.6"
+ ]
+ }
+ ]
},
{
- "target_os": "linux",
- "target_cpu": "x86_64",
- "version": "20240715",
- "url": "openharmony/compiler/python/3.11.4/linux/python-linux-x86-GLIBC2.27-3.11.4_20250219.tar.gz",
- "download_dir": ".prebuilts_cache/python/linux-x86",
- "symlink": "prebuilts/python/linux-x86",
- "type": "dir",
- "copy_src": "3.11.4",
- "copy_dest": "current",
- "pip_install": [
- "pyyaml",
- "requests>=2.32.1",
- "prompt_toolkit==1.0.14",
- "asn1crypto",
- "cryptography",
- "json5==0.9.6"
- ]
+ "name": "hpm",
+ "tag": "base",
+ "type": "indep",
+ "handle": [
+ {
+ "type": "hpm_download",
+ "name": "@ohos/hpm-cli",
+ "version": "1.6.1",
+ "package_path": "${code_dir}",
+ "package_lock_path": "${code_dir}",
+ "download_dir": "${download_root}/hpm",
+ "symlink": "${code_dir}/prebuilts/hpm/node_modules"
+ }
+ ]
},
{
- "target_os": "darwin",
- "target_cpu": "arm64",
- "version": "20240715",
- "url": "openharmony/compiler/python/3.11.4/linux/python_darwin-arm64-3.11.4_20250228.tar.gz",
- "download_dir": ".prebuilts_cache/python/darwin-arm64",
- "symlink": "prebuilts/python/darwin-arm64",
- "type": "dir",
- "copy_src": "3.11.4",
- "copy_dest": "current",
- "pip_install": [
- "pyyaml",
- "requests>=2.32.1",
- "prompt_toolkit==1.0.14",
- "asn1crypto",
- "cryptography",
- "json5==0.9.6"
- ]
- },
- {
- "target_os": "darwin",
- "target_cpu": "x86_64",
- "version": "20240729",
- "url": "openharmony/compiler/python/3.11.4/linux/python-darwin-x86-3.11.4_20250228.tar.gz",
- "download_dir": ".prebuilts_cache/python/darwin-x86",
- "symlink": "prebuilts/python/darwin-x86",
- "type": "dir",
- "copy_src": "3.11.4",
- "copy_dest": "current",
- "pip_install": [
- "pyyaml",
- "requests>=2.32.1",
- "prompt_toolkit==1.0.14",
- "asn1crypto",
- "cryptography",
- "json5==0.9.6"
- ]
- }
- ]
- },
- {
- "name": "hcgen",
- "tag": "base",
- "download": [
- {
- "target_os": "linux",
- "target_cpu": "x86_64",
- "version": "linux",
- "url": "openharmony/compiler/hc-gen/linux/hc-gen-20240926.tar.gz",
- "download_dir": ".prebuilts_cache/hc_gen",
- "symlink": "prebuilts/hc_gen/hc-gen",
- "type": "dir"
- }
- ]
- },
- {
- "name": "OpenHarmonyApplication.pem",
- "tag": "base",
- "download": [
- {
- "target_os": "linux",
- "target_cpu": "x86_64",
- "version": "linux",
- "url": "openharmony/compiler/certificates/20241025/OpenHarmonyApplication.zip",
- "download_dir": ".prebuilts_cache/OpenHarmonyApplication.pem",
- "symlink": "prebuilts/ohos-sdk/OpenHarmonyApplication.pem",
- "type": "file"
- }
- ]
- },
- {
- "name": "rustc",
- "download": [
- {
- "target_os": "linux",
- "target_cpu": "x86_64",
- "version": "1.72.0",
- "url": "openharmony/compiler/rust/1.72.0-20250515/rust-nightly-x86_64-unknown-linux-gnu.tar.gz",
- "download_dir": ".prebuilts_cache/rustc/rust-nightly-x86_64-unknown-linux-gnu",
- "script": "install_ext.sh",
- "args": [{
- "prefix": "''"
- }],
- "destdir": "prebuilts/rustc/linux-x86_64/current",
- "type": "dir"
- }
- ]
- },
- {
- "name": "rustc-aarch64-std",
- "download": [
- {
- "target_os": "linux",
- "target_cpu": "x86_64",
- "version": "1.72.0",
- "url": "openharmony/compiler/rust/1.72.0-20250515/rust-std-nightly-aarch64-unknown-linux-ohos.tar.gz",
- "download_dir": ".prebuilts_cache/rustc/rust-nightly-x86_64-unknown-linux-gnu",
- "script": "install_ext.sh",
- "args": [{
- "prefix": "''"
- }],
- "destdir": "prebuilts/rustc/linux-x86_64/current",
- "type": "dir"
- }
- ]
- },
- {
- "name": "rustc-arm-std",
- "download": [
- {
- "target_os": "linux",
- "target_cpu": "x86_64",
- "version": "1.72.0",
- "url": "openharmony/compiler/rust/1.72.0-20250515/rust-std-nightly-armv7-unknown-linux-ohos.tar.gz",
- "download_dir": ".prebuilts_cache/rustc/rust-nightly-x86_64-unknown-linux-gnu",
- "script": "install_ext.sh",
- "args": [{
- "prefix": "''"
- }],
- "destdir": "prebuilts/rustc/linux-x86_64/current",
- "type": "dir"
- }
- ]
- },
- {
- "name": "rustc-x86_64-std",
- "download": [
- {
- "target_os": "linux",
- "target_cpu": "x86_64",
- "version": "1.72.0",
- "url": "openharmony/compiler/rust/1.72.0-20250515/rust-std-nightly-x86_64-unknown-linux-ohos.tar.gz",
- "download_dir": ".prebuilts_cache/rustc/rust-nightly-x86_64-unknown-linux-gnu",
- "script": "install_ext.sh",
- "args": [{
- "prefix": "''"
- }],
- "destdir": "prebuilts/rustc/linux-x86_64/current",
- "type": "dir"
+ "name": "rustc",
+ "tag": "base",
+ "type": "src, indep",
+ "unzip_dir": "${code_dir}/prebuilts/rustc",
+ "config": {
+ "linux": {
+ "arm64": {
+ "remote_url": "/openharmony/compiler/rust/20240528/rust-std-nightly-aarch64-unknown-linux-ohos_20240528.tar.gz",
+ "unzip_filename": "rustc-aarch64-std",
+ "install_dir": "${code_dir}/prebuilts/rustc/rust-std-nightly-aarch64-unknown-linux-ohos_20240528",
+ "destdir": "${code_dir}/prebuilts/rustc/linux-x86_64/current"
+ },
+ "x86_64": [
+ {
+ "remote_url": "/openharmony/compiler/rust/20240528/rust-nightly-x86_64-unknown-linux-gnu_20240528.tar.gz",
+ "install_dir": "${code_dir}/prebuilts/rustc/rust-nightly-x86_64-unknown-linux-gnu_20240528",
+ "destdir": "${code_dir}/prebuilts/rustc/linux-x86_64/current",
+ "unzip_filename": "rustc"
+ },
+ {
+ "remote_url": "/openharmony/compiler/rust/20240528/rust-std-nightly-aarch64-unknown-linux-ohos_20240528.tar.gz",
+ "install_dir": "${code_dir}/prebuilts/rustc/rust-std-nightly-aarch64-unknown-linux-ohos_20240528",
+ "destdir": "${code_dir}/prebuilts/rustc/linux-x86_64/current",
+ "unzip_filename": "rustc-aarch64-std"
+ },
+ {
+ "remote_url": "/openharmony/compiler/rust/20240528/rust-std-nightly-armv7-unknown-linux-ohos_20240528.tar.gz",
+ "install_dir": "${code_dir}/prebuilts/rustc/rust-std-nightly-armv7-unknown-linux-ohos_20240528",
+ "destdir": "${code_dir}/prebuilts/rustc/linux-x86_64/current",
+ "unzip_filename": "rustc-arm-std"
+ },
+ {
+ "remote_url": "/openharmony/compiler/rust/20240528/rust-std-nightly-x86_64-unknown-linux-ohos_20240528.tar.gz",
+ "install_dir": "${code_dir}/prebuilts/rustc/rust-std-nightly-x86_64-unknown-linux-ohos_20240528",
+ "destdir": "${code_dir}/prebuilts/rustc/linux-x86_64/current",
+ "unzip_filename": "rustc-x86_64-std"
+ },
+ {
+ "remote_url": "/openharmony/compiler/rust/20240528/rust-std-nightly-x86_64-pc-windows-gnullvm_20240528.tar.gz",
+ "install_dir": "${code_dir}/prebuilts/rustc/rust-std-nightly-x86_64-pc-windows-gnullvm_20240528",
+ "destdir": "${code_dir}/prebuilts/rustc/linux-x86_64/current",
+ "unzip_filename": "rustc-x86_64-windows-std",
+ "type": "src"
+ }
+ ]
+ },
+ "darwin": {
+ "arm64": [
+ {
+ "remote_url": "/openharmony/compiler/rust/20240429/rust-nightly-aarch64-apple-darwin_20240429.tar.gz",
+ "install_dir": "${code_dir}/prebuilts/rustc/rust-nightly-aarch64-apple-darwin_20240429",
+ "destdir": "${code_dir}/prebuilts/rustc/darwin-aarch64/current",
+ "unzip_filename": "rustc"
+ },
+ {
+ "remote_url": "/openharmony/compiler/rust/20240429/rust-std-nightly-aarch64-apple-darwin_20240429.tar.gz",
+ "install_dir": "${code_dir}/prebuilts/rustc/rust-std-nightly-aarch64-apple-darwin_20240429",
+ "destdir": "${code_dir}/prebuilts/rustc/darwin-aarch64/current",
+ "unzip_filename": "rustc-aarch64-std"
+ }
+ ],
+ "x86_64": [
+ {
+ "remote_url": "/openharmony/compiler/rust/20240429/rust-nightly-x86_64-apple-darwin_20240429.tar.gz",
+ "install_dir": "${code_dir}/prebuilts/rustc/rust-nightly-x86_64-apple-darwin_20240429",
+ "destdir": "${code_dir}/prebuilts/rustc/darwin-x86_64/current",
+ "unzip_filename": "rustc"
+ },
+ {
+ "remote_url": "/openharmony/compiler/rust/20240429/rust-std-nightly-x86_64-apple-darwin_20240429.tar.gz",
+ "install_dir": "${code_dir}/prebuilts/rustc/rust-std-nightly-x86_64-apple-darwin_20240429",
+ "destdir": "${code_dir}/prebuilts/rustc/darwin-x86_64/current",
+ "unzip_filename": "rustc-x86_64-std"
+ }
+ ]
+ }
+ },
+ "handle": [
+ {
+ "type": "shell",
+ "cmd": [
+ "${install_dir}/install.sh",
+ "--prefix=''",
+ "--destdir=${destdir}"
+ ]
+ }
+ ]
}
- ]
- }
- ]
-}
+ ]
+}
\ No newline at end of file
diff --git a/prebuilts_config.py b/prebuilts_config.py
index eca5e23b5d8708acceffbc58f2a4d07d7a8535de..cbd2f5cf99cf48032787b8a0d5b01f1498758a30 100644
--- a/prebuilts_config.py
+++ b/prebuilts_config.py
@@ -1,7 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2024 Huawei Device Co., Ltd.
+# Copyright (c) 2025 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
@@ -13,335 +12,66 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-#
-import json
import os
-import subprocess
-import shutil
import argparse
+import ssl
import sys
-import urllib.request
-import socket
-
-
-def _run_cmd(cmd):
- res = subprocess.Popen(cmd, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- sout, serr = res.communicate(timeout=10000)
- return sout.rstrip().decode('utf-8'), serr, res.returncode
-
-
-def _check_sha256(check_url: str, local_file: str) -> bool:
- check_sha256_cmd = ('curl -s -k ' + check_url + '.sha256').split(' ')
- local_sha256_cmd = ['sha256sum', local_file]
- check_sha256, err, returncode = _run_cmd(check_sha256_cmd)
- local_sha256, err, returncode = _run_cmd(local_sha256_cmd)
- local_sha256 = local_sha256.split(' ')[0]
- if check_sha256 != local_sha256:
- print('remote file {}.sha256 is not found, begin check SHASUMS256.txt'.format(check_url))
- check_sha256 = _obtain_sha256_by_sha_sums256(check_url)
- return check_sha256 == local_sha256
-
-
-def _obtain_sha256_by_sha_sums256(check_url: str) -> str:
- sha_sums256 = 'SHASUMS256.txt'
- sha_sums256_path = os.path.join(os.path.dirname(check_url), sha_sums256)
- file_name = os.path.basename(check_url)
- cmd = ('curl -s -k ' + sha_sums256_path).split(' ')
- data_sha_sums256, err, returncode = _run_cmd(cmd)
- check_sha256 = None
- for line in data_sha_sums256.split('\n'):
- if file_name in line:
- check_sha256 = line.split(' ')[0]
- return check_sha256
-
-
-def npm_install(dir_name):
- result = subprocess.run(["npm", "install", "--prefix", dir_name], capture_output=True, text=True)
- if result.returncode == 0:
- print("{}目录下npm install完毕".format(dir_name))
- else:
- print("依赖项安装失败:", result.stderr)
-
-
-def copy_file(src, dest):
- if not os.path.exists(dest):
- os.makedirs(dest)
- shutil.copy(src, dest)
-
-
-def copy_folder(src, dest):
- if os.path.exists(dest):
- if os.path.islink(dest):
- os.unlink(dest)
- else:
- shutil.rmtree(dest)
- shutil.copytree(src, dest)
-
-
-def symlink_src2dest(src_dir, dest_dir):
- if os.path.exists(dest_dir) or os.path.islink(dest_dir):
- if os.path.islink(dest_dir):
- os.unlink(dest_dir)
- elif os.path.isdir(dest_dir):
- shutil.rmtree(dest_dir)
- else:
- os.remove(dest_dir)
- else:
- os.makedirs(os.path.dirname(dest_dir), exist_ok=True)
-
- print("symlink {} ---> {}".format(src_dir, dest_dir))
- os.symlink(src_dir, dest_dir)
-
-
-def install_hpm(code_path, download_dir, symlink_dir, home_path):
- content = """\
-package-lock=true
-registry=http://repo.huaweicloud.com/repository/npm
-strict-ssl=false
-lockfile=false
-"""
- with os.fdopen(os.open(os.path.join(home_path, '.npmrc'), os.O_WRONLY | os.O_CREAT, mode=0o640), 'w') as f:
- os.truncate(f.fileno(), 0)
- f.write(content)
- if not os.path.exists(download_dir):
- os.makedirs(download_dir)
- with os.fdopen(os.open(os.path.join(download_dir, 'package.json'), os.O_WRONLY | os.O_CREAT, mode=0o640),
- 'w') as f:
- os.truncate(f.fileno(), 0)
- f.write('{}\n')
- npm_path = os.path.join(code_path, "prebuilts/build-tools/common/nodejs/current/bin/npm")
- node_bin_path = os.path.join(code_path, "prebuilts/build-tools/common/nodejs/current/bin")
- os.environ['PATH'] = f"{node_bin_path}:{os.environ['PATH']}"
- subprocess.run(
- [npm_path, 'install', '@ohos/hpm-cli', '--registry', 'https://repo.huaweicloud.com/repository/npm/', '--prefix',
- download_dir])
- symlink_src2dest(os.path.join(download_dir, 'node_modules'), symlink_dir)
-
-
-def process_npm(npm_dict, args):
- code_path = args.code_path
- home_path = args.home_path
- name = npm_dict.get('name')
- npm_download = npm_dict.get('download')
- package_path = os.path.join(code_path, npm_download.get('package_path'))
- package_lock_path = os.path.join(code_path, npm_download.get('package_lock_path'))
- hash_value = \
- subprocess.run(['sha256sum', package_lock_path], capture_output=True, text=True).stdout.strip().split(' ')[0]
- download_dir = os.path.join(home_path, npm_download.get('download_dir'), hash_value)
-
- if '@ohos/hpm-cli' == name:
- symlink = os.path.join(code_path, npm_download.get('symlink'))
- install_hpm(code_path, os.path.join(home_path, download_dir), os.path.join(code_path, symlink), home_path)
- return
-
- copy_file(package_path, download_dir)
- copy_file(package_lock_path, download_dir)
-
- if not os.path.exists(os.path.join(download_dir, "npm-install.js")):
- npm_install_script = os.path.join(os.path.dirname(package_path), "npm-install.js")
- if os.path.exists(npm_install_script):
- shutil.copyfile(npm_install_script, os.path.join(download_dir, "npm-install.js"))
-
- npm_install(download_dir)
-
- if name == 'legacy_bin':
- for link in npm_download.get('symlink', []):
- symlink_src2dest(os.path.join(download_dir, "node_modules"), os.path.join(code_path, link))
- return
-
- symlink = os.path.join(code_path, npm_download.get('symlink'))
-
- if name in ['parse5']:
- copy_folder(os.path.join(download_dir, "node_modules"), symlink)
- return
-
- copy_folder(os.path.join(download_dir, "node_modules"), symlink)
-
- for copy_entry in npm_download.get('copy', []):
- copy_folder(os.path.join(code_path, copy_entry['src']), os.path.join(code_path, copy_entry['dest']))
-
- for copy_ext_entry in npm_download.get('copy_ext', []):
- copy_folder(os.path.join(code_path, copy_ext_entry['src']), os.path.join(code_path, copy_ext_entry['dest']))
-
+sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "prebuilts_service"))
+from prebuilts_service.operater import OperateHanlder
+from prebuilts_service.pool_downloader import PoolDownloader
+from prebuilts_service.config_parser import ConfigParser
+import json
+from prebuilts_service.common_utils import get_code_dir
-def download_url(url, folder_path):
- filename = url.split('/')[-1]
- file_path = os.path.join(folder_path, filename)
- if os.path.exists(file_path):
- if _check_sha256(url, file_path):
- return
- else:
- os.remove(file_path)
- if not os.path.exists(folder_path):
- os.makedirs(folder_path)
- try:
- print("Downloading {}".format(url))
- with urllib.request.urlopen(url) as response, os.fdopen(
- os.open(file_path, os.O_WRONLY | os.O_CREAT, mode=0o640), 'wb') as out_file:
- total_size = int(response.headers['Content-Length'])
- chunk_size = 16 * 1024
- downloaded_size = 0
- print_process(chunk_size, downloaded_size, out_file, response, total_size)
- print("\n{} downloaded successfully".format(url))
- except urllib.error.URLError as e:
- print("Error:", e.reason)
- except socket.timeout:
- print("Timeout error: Connection timed out")
+global_args = None
-def print_process(chunk_size, downloaded_size, out_file, response, total_size):
- while True:
- chunk = response.read(chunk_size)
- if not chunk:
- break
- out_file.write(chunk)
- downloaded_size += len(chunk)
- if total_size != 0:
- if "DISABLE_DOWNLOAD_PROGRESS" not in os.environ:
- progress = downloaded_size / total_size * 50
- print(f'\r[{"=" * int(progress)}{" " * (50 - int(progress))}] {progress * 2:.2f}%', end='', flush=True)
- else:
- print("\r[Error] Total size is zero, unable to calculate progress.", end='', flush=True)
+def _parse_args():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--skip-ssl', action='store_true', help='skip ssl authentication')
+ parser.add_argument('--unsafe-perm', action='store_true', help='add "--unsafe-perm" for npm install')
+ parser.add_argument('--disable-rich', action='store_true', help='disable the rich module')
+ parser.add_argument('--enable-symlink', action='store_true', help='enable symlink while copying node_modules')
+ parser.add_argument('--build-arkuix', action='store_true', help='build ArkUI-X SDK')
+ parser.add_argument('--tool-repo', default='https://repo.huaweicloud.com', help='prebuilt file download source')
+ parser.add_argument('--npm-registry', default='https://repo.huaweicloud.com/repository/npm/',
+ help='npm download source')
+ parser.add_argument('--host-cpu', help='host cpu', required=True)
+ parser.add_argument('--host-platform', help='host platform', required=True)
+ parser.add_argument('--glibc-version', help='glibc version', required=False)
+ parser.add_argument('--config-file', help='prebuilts download config file')
+ parser.add_argument('--type', help='prebuilts download type', default="indep")
+ parser.add_argument('--tag', help='prebuilts download tag', default="base")
+ return parser
-def extract_compress_files(source_file, destination_folder):
- if not os.path.exists(destination_folder):
- os.makedirs(destination_folder, exist_ok=True)
- if source_file.endswith('.zip'):
- command = ['unzip', '-qq', '-o', '-d', destination_folder, source_file]
- elif source_file.endswith('.tar.gz'):
- command = ['tar', '-xzf', source_file, '-C', destination_folder]
- elif source_file.endswith('.tar.xz'):
- command = ['tar', '-xJf', source_file, '-C', destination_folder]
- else:
- print("暂不支持解压此类型压缩文件!")
- command = []
- try:
- subprocess.run(command, check=True)
- print(f"{source_file} extracted to {destination_folder}")
- except subprocess.CalledProcessError as e:
- print(f"Error: {e}")
+def main():
+ parser = _parse_args()
+ global global_args
+ global_args = parser.parse_args()
+ if global_args.skip_ssl:
+ global_args._create_default_https_context = ssl._create_unverified_context
+ global_args.code_dir = get_code_dir()
-def install_python(version, download_dir, one_type, code_path):
- after_extract_folder = os.listdir(os.path.join(download_dir, version))[0]
- copy_folder(os.path.join(download_dir, version, after_extract_folder, one_type.get('copy_src')),
- os.path.join(download_dir, version, after_extract_folder, one_type.get('copy_dest')))
- python3_path = os.path.join(download_dir, version, after_extract_folder, one_type.get('copy_dest'),
- 'bin', 'python3')
- pip3_path = os.path.join(download_dir, version, after_extract_folder, one_type.get('copy_dest'), 'bin',
- 'pip3')
- subprocess.run(
- [python3_path, pip3_path, "install", "--trusted-host", "repo.huaweicloud.com", "-i",
- "http://repo.huaweicloud.com/repository/pypi/simple"] + one_type.get(
- 'pip_install'))
- copy_folder(os.path.join(download_dir, version, after_extract_folder),
- os.path.join(code_path, one_type.get('symlink')))
+ config_file = os.path.join(global_args.code_dir,"build", "prebuilts_config.json")
+ if global_args.config_file:
+ config_file = global_args.config_file
+ config_parser = ConfigParser(config_file, global_args)
+ download_operate, other_operate = config_parser.get_operate()
+
+ prebuilts_path = os.path.join(global_args.code_dir, "prebuilts")
+ if not os.path.exists(prebuilts_path):
+ os.makedirs(prebuilts_path)
+
+ # 使用线程池下载
+ pool_downloader = PoolDownloader(download_operate, global_args)
+ unchanged = pool_downloader.start()
+
+ OperateHanlder.run(other_operate, global_args, unchanged)
-def install_rustc(url, download_dir, version, one_type, code_path):
- part_file_name = url.split('/')[-1].split('linux')[0]
- after_extract_file_list = os.listdir(os.path.join(download_dir, version))
- for file_name in after_extract_file_list:
- if part_file_name in file_name:
- script_path = os.path.join(download_dir, version, file_name, "install.sh")
- subprocess.run([script_path, "--prefix=''",
- "--destdir='{}'".format(os.path.join(code_path, one_type.get('destdir')))])
- break
-
-
-def process_tar(tar_dict, args):
- code_path = args.code_path
- home_path = args.home_path
- os_type = args.target_os
- cpu_type = args.target_cpu
- tar_name = tar_dict.get('name')
- print(tar_name)
- tar_download = tar_dict.get('download')
- for one_type in tar_download:
- download_flag = download_or_not(cpu_type, one_type, os_type)
- if download_flag == True:
- version = one_type.get('version')
- url = os.path.join(args.repo_https, one_type.get('url'))
- download_dir = os.path.join(home_path, one_type.get('download_dir'))
- download_url(url, download_dir)
- extract_compress_files(os.path.join(download_dir, url.split('/')[-1]),
- os.path.join(download_dir, version))
- if tar_name == 'python':
- install_python(version, download_dir, one_type, code_path)
- continue
- if 'rustc' in tar_name:
- install_rustc(url, download_dir, version, one_type, code_path)
- continue
- if tar_name == 'llvm':
- after_extract_folder = os.listdir(os.path.join(download_dir, version))[0]
- symlink_src2dest(os.path.join(download_dir, version, after_extract_folder),
- os.path.join(code_path, one_type.get('symlink')))
- symlink_src2dest(os.path.join(code_path, one_type.get('symlink'), one_type.get('copy_src')),
- os.path.join(code_path, one_type.get('symlink'), one_type.get('copy_dest')))
- continue
- if tar_name in ['ark_tools']:
- after_extract_folder = os.listdir(os.path.join(download_dir, version))[0]
- copy_folder(os.path.join(download_dir, version, after_extract_folder),
- os.path.join(code_path, one_type.get('symlink')))
- continue
- after_extract_file_list = os.listdir(os.path.join(download_dir, version))
- symlink = os.path.join(code_path, one_type.get('symlink'))
- if one_type.get('type') == 'dir':
- deal_tar_dir(after_extract_file_list, download_dir, symlink, tar_name, version)
- else:
- file_name = after_extract_file_list[0]
- symlink_src2dest(os.path.join(download_dir, version, file_name), symlink)
- if tar_name == 'nodejs' and url == os.path.join(args.repo_https,
- "nodejs/v14.21.1/node-v14.21.1-linux-x64.tar.gz"):
- symlink_src2dest(symlink, os.path.join(os.path.dirname(symlink), 'current'))
-
-
-def download_or_not(cpu_type, one_type, os_type):
- download_flag = False
- if cpu_type == 'any':
- if one_type.get('target_os') == os_type:
- download_flag = True
- else:
- if one_type.get('target_os') == os_type and (
- one_type.get('target_cpu') == cpu_type or one_type.get('target_cpu') == ""):
- download_flag = True
- return download_flag
-
-
-def deal_tar_dir(after_extract_file_list, download_dir, symlink, tar_name, version):
- for one_file in after_extract_file_list:
- if tar_name == 'packing_tool':
- symlink_src2dest(os.path.join(download_dir, version, one_file),
- os.path.join(symlink, one_file))
- else:
- symlink_src2dest(os.path.join(download_dir, version, one_file),
- symlink)
-
-
-def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('--code_path', required=True, type=str, help='path of openharmony code')
- parser.add_argument('--home_path', required=True, type=str, help='path of home')
- parser.add_argument('--config_file', required=True, type=str, help='path of prebuilts_config.json')
- parser.add_argument('--repo_https', required=True, type=str, default='https://repo.huaweicloud.com',
- help='path of prebuilts_config.json')
- parser.add_argument('--target_os', required=True, type=str, help='type of os')
- parser.add_argument('--target_cpu', type=str, default='any', help='type of cpu')
- args = parser.parse_args()
- config_file = args.config_file
- with open(config_file, 'r', encoding='utf-8') as r:
- config = json.load(r)
- tar = config['tar']
- for one_tar in tar:
- process_tar(one_tar, args)
- npm = config['npm']
- for one_npm in npm:
- process_npm(one_npm, args)
-
-
-if __name__ == '__main__':
- sys.exit(main())
+if __name__ == "__main__":
+ sys.exit(main())
\ No newline at end of file
diff --git a/prebuilts_config.sh b/prebuilts_config.sh
index 68e1db4122414e40a59dfc47146dcc6ab886a334..61823270055b6026848feade35a938b1aeb92031 100644
--- a/prebuilts_config.sh
+++ b/prebuilts_config.sh
@@ -13,19 +13,49 @@
# limitations under the License.
set -e
-
script_path=$(cd $(dirname $0);pwd)
code_dir=$(dirname ${script_path})
home_path=$HOME
config_file="$script_path/prebuilts_config.json"
-# 获取当前系统类型和CPU类型
-target_os=$(uname -s | tr '[:upper:]' '[:lower:]')
-target_cpu=$(uname -m | tr '[:upper:]' '[:lower:]')
+
+case $(uname -s) in
+ Linux)
+ host_platform=linux
+ glibc_version=$(getconf GNU_LIBC_VERSION | grep -oE '[0-9].[0-9]{2}')
+ ;;
+ Darwin)
+ host_platform=darwin
+ ;;
+ *)
+ echo "Unsupported host platform: $(uname -s)"
+ exit 1
+esac
+
+case $(uname -m) in
+ arm64)
+ host_cpu=arm64
+ host_cpu_prefix=arm64
+ ;;
+ aarch64)
+ host_cpu=arm64
+ host_cpu_prefix=aarch64
+ ;;
+ *)
+ host_cpu=x86_64
+ host_cpu_prefix=x86
+esac
+
+if [[ "${glibc_version}" < "2.35" ]]; then
+ glibc_version="--glibc-version GLIBC2.27"
+else
+ glibc_version="--glibc-version GLIBC2.35"
+fi
+
# 运行Python命令
-python3 "${script_path}/prebuilts_config.py" --code_path $code_dir --home_path $home_path --config_file $config_file --repo_https https://repo.huaweicloud.com --target_os $target_os --target_cpu $target_cpu
+python3 "${script_path}/prebuilts_config.py" $glibc_version --config-file $config_file --host-platform $host_platform --host-cpu $host_cpu
-PYTHON_PATH=$(realpath ${code_dir}/prebuilts/python/${target_os}-*/*/bin | tail -1)
+PYTHON_PATH=$(realpath $code_dir/prebuilts/python/${host_platform}-${host_cpu_prefix}/*/bin | tail -1)
while [ $# -gt 0 ]; do
case "$1" in
diff --git a/prebuilts_service/README_zh.md b/prebuilts_service/README_zh.md
new file mode 100644
index 0000000000000000000000000000000000000000..64615a0223cda6f68db90a9fd1132202a2bb6a33
--- /dev/null
+++ b/prebuilts_service/README_zh.md
@@ -0,0 +1,215 @@
+# 预编译工具配置指南
+- [工具下载配置](#section-download-01)
+ 1. [核心配置说明](#section-download-core-01)
+ 2. [基础配置示例](#section-download-basic-demo)
+ 3. [高级配置示例](#section-download-advanced-demo)
+- [后续处理配置](#advanced-process)
+- [变量查找规则](#value-search)
+
+## 工具下载配置
+下载配置用于配置下载和解压参数
+### 核心配置项说明
+
+|参数|描述|
+|--|--|
+remote_url|远程包下载地址(HTTP/HTTPS)|
+unzip_dir|解压目标路径(绝对或相对路径)|
+unzip_filename|解压后的顶层目录名(用于版本管理和旧文件清理)|
+
+### 基础配置示例
+#### 场景1:指定操作系统与CPU架构
+以 ark_js_prebuilts 工具为例,在 Linux x86_64 环境下的配置如下:
+```json
+{
+ "name": "ark_js_prebuilts",
+ "tag": "base",
+ "type": "src, indep",
+ "config": {
+ "linux": {
+ "x86_64": {
+ "remote_url": "/openharmony/compiler/llvm_prebuilt_libs/ark_js_prebuilts_20230713.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/ark_tools",
+ "unzip_filename": "ark_js_prebuilts"
+ }
+ }
+ }
+}
+```
+
+
+#### 场景2:CPU架构无关配置
+若工具包不依赖CPU架构(如纯脚本工具),可省略架构标识
+``` json
+{
+ "name": "ark_js_prebuilts",
+ "tag": "base",
+ "type": "src, indep",
+ "config": {
+ "linux": {
+ "remote_url": "/openharmony/compiler/llvm_prebuilt_libs/ark_js_prebuilts_20230713.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/ark_tools",
+ "unzip_filename": "ark_js_prebuilts"
+ }
+ }
+}
+```
+
+
+#### 场景3:跨平台配置
+若工具包同时兼容多操作系统和CPU架构,配置进一步简化:
+```json
+{
+ "name": "ark_js_prebuilts",
+ "tag": "base",
+ "type": "src, indep",
+ "remote_url": "/openharmony/compiler/llvm_prebuilt_libs/ark_js_prebuilts_20230713.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/ark_tools",
+ "unzip_filename": "ark_js_prebuilts"
+}
+```
+
+### 高级配置场景
+#### 多版本并行下载(以LLVM为例)
+若需在同一平台下安装多个版本,配置项改为列表形式:
+```json
+{
+ "name": "llvm",
+ "tag": "base",
+ "type": "src, indep",
+ "config": {
+ "linux": {
+ "x86_64": [
+ {
+ "remote_url": "/openharmony/compiler/clang/15.0.4-3cec00/ohos_arm64/clang_ohos-arm64-3cec00-20250320.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/clang/ohos/ohos-arm64",
+ "unzip_filename": "llvm",
+ },
+ {
+ "remote_url": "/openharmony/compiler/clang/15.0.4-3cec00/windows/clang_windows-x86_64-3cec00-20250320.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/clang/ohos/windows-x86_64",
+ "unzip_filename": "llvm",
+ },
+ {
+ "remote_url": "/openharmony/compiler/clang/15.0.4-3cec00/linux/clang_linux-x86_64-3cec00-20250320.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/clang/ohos/linux-x86_64",
+ "unzip_filename": "llvm",
+ }
+ ]
+ }
+ }
+}
+```
+
+
+
+#### 使用公共变量
+当配置中存在值相同的配置项时,可提取公共变量避免冗余:
+**原始冗余配置**
+```json
+{
+ "name": "ark_js_prebuilts",
+ "tag": "base",
+ "type": "src, indep",
+ "config": {
+ "linux": {
+ "x86_64": {
+ "remote_url": "/openharmony/compiler/llvm_prebuilt_libs/ark_js_prebuilts_20230713.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/ark_tools",
+ "unzip_filename": "ark_js_prebuilts"
+ }
+ },
+ "darwin": {
+ "x86_64": {
+ "remote_url": "/openharmony/compiler/llvm_prebuilt_libs/ark_js_prebuilts_darwin_x64_20230209.tar.gz",
+ "unzip_dir": "${code_dir}/prebuilts/ark_tools",
+ "unzip_filename": "ark_js_prebuilts"
+ }
+ }
+ }
+}
+```
+
+**优化后配置**
+```json
+{
+ "name": "ark_js_prebuilts",
+ "tag": "base",
+ "type": "src, indep",
+ "unzip_dir": "${code_dir}/prebuilts/ark_tools",
+ "unzip_filename": "ark_js_prebuilts",
+ "config": {
+ "linux": {
+ "x86_64": {
+ "remote_url": "/openharmony/compiler/llvm_prebuilt_libs/ark_js_prebuilts_20230713.tar.gz"
+ }
+ },
+ "darwin": {
+ "x86_64": {
+ "remote_url": "/openharmony/compiler/llvm_prebuilt_libs/ark_js_prebuilts_darwin_x64_20230209.tar.gz"
+
+ }
+ }
+ }
+}
+```
+
+#### 配置继承规则
+- 工具配置会继承全局配置
+- 平台配置会继承工具配置
+- 内部配置优于继承配置
+
+## 后续处理配置
+工具下载解压完成后可能需要进行后续处理,该部分在handle中配置,handle是一个列表,其中的每一项都代表一个操作
+### handle配置特点
+- 顺序执行:操作按配置顺序依次执行。
+- 变量继承:操作中可引用config和外部的配置参数
+- 灵活控制:可通过handle_index指定执行的操作序号。
+- 容错机制:若操作中的变量解析失败,跳过当前操作。
+
+### 公共操作列表
+
+|操作类型|参数|用途|
+|-|-|-|
+|download| remote_url: 远程下载地
unzip_dir: 本地解压目
unzip_filename: 用于哈希校验和清理
**注:该操作通常而言无需显示声明,脚本会根据平台配置的remote_url自动生成对应的下载作 **| 下载和解压 |
+|symlink| src: 链接源
dest: 目的链接地址| 生成符号链接
+|copy | src: 源
dest: 目的| 复制文件或文件夹 |
+|remove | path:要删除的路径, 可以是字符串,也可以是一个列表 | 删除文件或文件夹 |
+|move | src: 源路径
dest: 目标路径
filetype: 该参数默认不填写,若填写,则只会移动src目录中以filetype为后缀的文件 | 移动文件,若dest是个已存在的目录,则会移动到目录中 |
+|shell | cmd: 命令(列表形式) |执行shell命令
+
+### handle配置示例
+#### 场景: 解压Node工具后创建符号链接:
+```json
+{
+ "name": "node",
+ "tag": "base",
+ "type": "src, indep",
+ "unzip_dir": "${code_dir}/prebuilts/build-tools/common/nodejs",
+ "config": {
+ "linux": {
+ "x86_64": [
+ {
+ "remote_url": "/nodejs/v14.21.1/node-v14.21.1-linux-x64.tar.gz",
+ "unzip_filename": "node-v14.21.1-linux-x64",
+ "symlink_src": "${code_dir}/prebuilts/build-tools/common/nodejs/node-v14.21.1-linux-x64"
+ }
+ ]
+ }
+ },
+ "handle": [
+ {
+ "type": "symlink",
+ "src": "${symlink_src}",
+ "dest": "${code_dir}/prebuilts/build-tools/common/nodejs/current"
+ }
+ ]
+}
+```
+
+
+## 变量查找规则
+- 变量只能使用${var_name}的方式指定
+- 工具配置可以使用自身以及全局配置中的变量
+- 平台配置可以使用自身、工具以及全局配置中的变量
+- handle可以使用自身、平台、工具以及全局配置中的变量
+- 变量只会解析一次,采取就近解析原则
diff --git a/prebuilts_service/common_utils.py b/prebuilts_service/common_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ae16a14c10020aeccfbaed42b5cace4528027c4
--- /dev/null
+++ b/prebuilts_service/common_utils.py
@@ -0,0 +1,300 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# Copyright (c) 2025 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import shutil
+import subprocess
+import pathlib
+import time
+import json
+import importlib
+
+
+def get_code_dir():
+ current_dir = os.path.dirname(__file__)
+ while True:
+ check_path = os.path.join(current_dir, "build", "ohos.gni")
+ if os.path.exists(check_path):
+ return current_dir
+ else:
+ new_dir = os.path.dirname(current_dir)
+ if new_dir == current_dir:
+ raise Exception(f"file {__file__} not in ohos source directory")
+ else:
+ current_dir = new_dir
+
+
+def import_rich_module():
+ module = importlib.import_module("rich.progress")
+ progress = module.Progress(
+ module.TextColumn("[bold blue]{task.fields[filename]}", justify="right"),
+ module.BarColumn(bar_width=None),
+ "[progress.percentage]{task.percentage:>3.1f}%",
+ "•",
+ module.DownloadColumn(),
+ "•",
+ module.TransferSpeedColumn(),
+ "•",
+ module.TimeRemainingColumn(),
+ )
+ return progress
+
+
+def load_config(config_file: str):
+ with open(config_file, "r", encoding="utf-8") as r:
+ config = json.load(r)
+ return config
+
+
+def copy_file(src: str, dest: str):
+ if not os.path.exists(dest):
+ os.makedirs(dest)
+ shutil.copy(src, dest)
+
+
+def remove_dest_path(dest_path: str):
+ if os.path.exists(dest_path) or os.path.islink(dest_path):
+ if os.path.islink(dest_path):
+ os.unlink(dest_path)
+ elif os.path.isdir(dest_path):
+ shutil.rmtree(dest_path)
+ else:
+ os.remove(dest_path)
+
+
+def copy_folder(src: str, dest: str):
+ remove_dest_path(dest)
+ shutil.copytree(src, dest)
+
+
+def symlink_src2dest(src_dir: str, dest_dir: str):
+ remove_dest_path(dest_dir)
+ os.makedirs(os.path.dirname(dest_dir), exist_ok=True)
+ os.symlink(src_dir, dest_dir)
+ print("symlink {} ---> {}".format(src_dir, dest_dir))
+
+
+def run_cmd_live(cmd: list):
+ cmd_str = " ".join(cmd)
+ print(f"run command: {cmd_str}\n")
+ try:
+ process = subprocess.Popen(
+ cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True
+ )
+
+ while True:
+ output = process.stdout.readline()
+ if output == '' and process.poll() is not None:
+ break
+ if output:
+ print(output.strip())
+
+ return_code = process.poll()
+ if return_code != 0:
+ print(f"命令执行失败,返回码: {return_code}")
+ return return_code, ""
+ except Exception as e:
+ print(f"执行命令时出错: {e}")
+ return 1, ""
+
+
+def run_cmd(cmd: list) -> tuple:
+ res = subprocess.Popen(
+ cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ )
+ sout, serr = res.communicate()
+ return sout.rstrip().decode("utf-8"), serr, res.returncode
+
+
+def is_system_component() -> bool:
+ root_dir = get_code_dir()
+ return any(
+ pathlib.Path(root_dir, *components).exists()
+ for components in [
+ ("interface", "sdk-js"),
+ ("foundation", "arkui"),
+ ("arkcompiler",)
+ ]
+ )
+
+
+def install_hpm_in_other_platform(name: str, operate: dict):
+ download_dir = operate.get("download_dir")
+ package_path = operate.get("package_path")
+ package_lock_path = operate.get("package_lock_path")
+ hash_value = (
+ subprocess.run(
+ ["sha256sum", package_lock_path], capture_output=True, text=True
+ )
+ .stdout.strip()
+ .split(" ")[0]
+ )
+ hash_dir = os.path.join(download_dir, hash_value)
+ copy_file(package_path, hash_dir)
+ copy_file(package_lock_path, hash_dir)
+
+ if not os.path.exists(os.path.join(hash_dir, "npm-install.js")):
+ npm_install_script = os.path.join(
+ os.path.dirname(package_path), "npm-install.js"
+ )
+ if os.path.exists(npm_install_script):
+ shutil.copyfile(
+ npm_install_script, os.path.join(hash_dir, "npm-install.js")
+ )
+
+ result = subprocess.run(
+ ["npm", "install", "--prefix", hash_dir], capture_output=True, text=True
+ )
+ if result.returncode == 0:
+ print("npm install completed in the {} directory.".format(hash_dir))
+ else:
+ print("npm dependency installation failed:", result.stderr)
+
+ symlink_src = os.path.join(hash_dir, "node_modules")
+ symlink_dest = operate.get("symlink")
+
+ if name == "legacy_bin":
+ for link in operate.get("symlink", []):
+ symlink_src2dest(symlink_src, link)
+ return
+
+ if name in ["parse5"]:
+ copy_folder(symlink_src, symlink_dest)
+ return
+
+ copy_folder(symlink_src, symlink_dest)
+
+ for copy_entry in operate.get("copy", []):
+ copy_folder(
+ copy_entry["src"], copy_entry["dest"]
+ )
+
+ for copy_ext_entry in operate.get("copy_ext", []):
+ copy_folder(
+ copy_ext_entry["src"], copy_ext_entry["dest"]
+ )
+
+
+def install_hpm(npm_tool_path: str, hpm_install_dir: str):
+ content = """\
+package-lock=true
+registry=http://repo.huaweicloud.com/repository/npm
+strict-ssl=false
+lockfile=false
+"""
+ with os.fdopen(
+ os.open(
+ os.path.join(os.path.expanduser("~"), ".npmrc"),
+ os.O_WRONLY | os.O_CREAT,
+ mode=0o640,
+ ),
+ "w",
+ ) as f:
+ os.truncate(f.fileno(), 0)
+ f.write(content)
+ if not os.path.exists(hpm_install_dir):
+ os.makedirs(hpm_install_dir)
+ with os.fdopen(
+ os.open(
+ os.path.join(hpm_install_dir, "package.json"),
+ os.O_WRONLY | os.O_CREAT,
+ mode=0o640,
+ ),
+ "w",
+ ) as f:
+ os.truncate(f.fileno(), 0)
+ f.write("{}\n")
+ node_bin_path = os.path.dirname(npm_tool_path)
+ os.environ["PATH"] = f"{node_bin_path}:{os.environ['PATH']}"
+ subprocess.run(
+ [
+ npm_tool_path,
+ "install",
+ "@ohos/hpm-cli",
+ "--registry",
+ "https://repo.huaweicloud.com/repository/npm/",
+ "--prefix",
+ hpm_install_dir,
+ ]
+ )
+
+
+def npm_config(npm_tool_path: str, global_args: object) -> tuple:
+ node_path = os.path.dirname(npm_tool_path)
+ os.environ["PATH"] = "{}:{}".format(node_path, os.environ.get("PATH"))
+ if global_args.skip_ssl:
+ skip_ssl_cmd = "{} config set strict-ssl false;".format(npm_tool_path).split()
+ _, err, retcode = run_cmd(skip_ssl_cmd)
+ if retcode != 0:
+ return False, err.decode()
+ npm_clean_cmd = "{} cache clean -f".format(npm_tool_path).split()
+ npm_package_lock_cmd = "{} config set package-lock true".format(npm_tool_path).split()
+ _, err, retcode = run_cmd(npm_clean_cmd)
+ if retcode != 0:
+ return False, err.decode()
+ _, err, retcode = run_cmd(npm_package_lock_cmd)
+ if retcode != 0:
+ return False, err.decode()
+ return True, None
+
+
+def npm_install(operate: dict, global_args: object, success_installed_npm_config: list) -> tuple:
+ install_list = operate.get("npm_install_path")
+ npm_tool_path = os.path.join(global_args.code_dir, "prebuilts/build-tools/common/nodejs/current/bin/npm")
+
+ preset_is_ok, err = npm_config(npm_tool_path, global_args)
+ if not preset_is_ok:
+ return preset_is_ok, err
+
+ print("start npm install, please wait.")
+ for install_path in install_list:
+ if install_path in success_installed_npm_config:
+ continue
+ full_code_path = install_path
+ basename = os.path.basename(full_code_path)
+ node_modules_path = os.path.join(full_code_path, "node_modules")
+ npm_cache_dir = os.path.join("~/.npm/_cacache", basename)
+
+ if os.path.exists(node_modules_path):
+ print("remove node_modules %s" % node_modules_path)
+ run_cmd(("rm -rf {}".format(node_modules_path)).split())
+
+ if os.path.exists(full_code_path):
+ cmd = ["timeout", "-s", "9", "90s", npm_tool_path, "install", "--registry", global_args.npm_registry,
+ "--cache", npm_cache_dir]
+ if global_args.host_platform == "darwin":
+ cmd = [npm_tool_path, "install", "--registry", global_args.npm_registry, "--cache", npm_cache_dir]
+ if global_args.unsafe_perm:
+ cmd.append("--unsafe-perm")
+ proc = subprocess.Popen(
+ cmd, cwd=full_code_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ )
+ # wait proc Popen with 0.1 second
+ time.sleep(0.1)
+ _, err = proc.communicate()
+ if proc.returncode:
+ print("in dir:{}, executing:{}".format(full_code_path, " ".join(cmd)))
+ return False, err.decode()
+ else:
+ success_installed_npm_config.append(install_path)
+ else:
+ raise Exception(
+ "{} not exist, it shouldn't happen, pls check...".format(full_code_path)
+ )
+ print(f"{node_modules_path} install over!")
+ return True, None
\ No newline at end of file
diff --git a/prebuilts_service/config_parser.py b/prebuilts_service/config_parser.py
new file mode 100644
index 0000000000000000000000000000000000000000..50254416e285a05f6eb7a8ec5ab40ced1e3feee0
--- /dev/null
+++ b/prebuilts_service/config_parser.py
@@ -0,0 +1,331 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# Copyright (c) 2025 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import copy
+import re
+import os
+from common_utils import load_config
+
+
+class ConfigParser:
+ def __init__(self, config_file: str, global_args):
+ self.data = load_config(config_file)
+ self.current_cpu = global_args.host_cpu
+ self.current_os = global_args.host_platform
+ self.input_tag = global_args.tag
+ self.input_type = global_args.type
+ self.global_config = {
+ "code_dir": global_args.code_dir,
+ "download_root": self.data["download_root"]
+ }
+ VarParser.parse_vars(self.global_config, [])
+ download_root = self.global_config["download_root"]
+ self.global_config["download_root"] = os.path.abspath(os.path.expanduser(download_root))
+
+ def get_operate(self) -> tuple:
+ download_op = []
+ other_op = []
+ tool_list = self.data["tool_list"]
+ for tool in tool_list:
+ _download, _other = self._get_tool_operate(tool)
+ download_op.extend(_download)
+ other_op.extend(_other)
+ return download_op, other_op
+
+ def _get_tool_operate(self, tool) -> tuple:
+ tool_matched, unified_tool_basic_config = self._is_tool_matched(tool)
+ if not tool_matched:
+ return [], []
+
+ matched_platform_configs = Filter.filter_platform(self.current_os, self.current_cpu, tool.get("config"))
+ for config in matched_platform_configs:
+ VarParser.parse_vars(config, [unified_tool_basic_config, self.global_config])
+ unified_platform_configs = []
+ for conf in matched_platform_configs:
+ unified_platform_configs.append(self._unify_config(self.global_config, unified_tool_basic_config, conf))
+ unified_platform_configs = Filter(unified_platform_configs).apply_filters(self.input_tag, self.input_type)
+
+ handle = tool.get("handle", [])
+
+ if unified_platform_configs:
+ # 有平台配置则只使用平台配置
+ download_operate, other_operate = self._generate_tool_operate(unified_platform_configs, handle)
+ else:
+ # 没有平台配置则使用工具配置
+ download_operate, other_operate = self._generate_tool_operate([unified_tool_basic_config], handle)
+
+ # 删除存在未知变量的配置
+ return VarParser.remove_undefined(download_operate), VarParser.remove_undefined(other_operate)
+
+ def _is_tool_matched(self, tool):
+ tool_basic_config = {key: tool[key] for key in tool if key not in {"config", "handle"}}
+ VarParser.parse_vars(tool_basic_config, [self.global_config])
+ unified_tool_basic_config = self._unify_config(self.global_config, tool_basic_config)
+ if not Filter([unified_tool_basic_config]).apply_filters(self.input_tag, self.input_type):
+ return False, []
+ else:
+ return True, unified_tool_basic_config
+
+ def _generate_tool_operate(self, outer_configs: list, handles: list) -> tuple:
+ if not outer_configs:
+ return [], []
+
+ download_operate = []
+ other_operate = []
+
+ # 根据配置,自动生成下载操作
+ for config in outer_configs:
+ if config.get("remote_url"):
+ download_config = self._generate_download_config(config)
+ download_operate.append(download_config)
+
+ # 如果没有其他操作,则返回
+ if not handles:
+ return download_operate, []
+
+ operates = self._generate_handles(outer_configs, handles)
+ # 区分下载操作和其他操作
+ other_operate = []
+ for operate in operates:
+ if operate["type"] == "download":
+ download_operate.append(operate)
+ else:
+ other_operate.append(operate)
+
+ return download_operate, other_operate
+
+ def _generate_handles(self, outer_configs: list, handles: list):
+ """
+ 为每个配置生成对应的操作列表
+ :param configs: 配置列表
+ :param handles: 操作列表
+ """
+ operate_list = []
+ for config in outer_configs:
+ special_handle = config.get("handle_index")
+ count = 0
+ for index, handle in enumerate(handles):
+ if special_handle and index not in special_handle:
+ continue
+ step_id = "_".join([config.get("name"), os.path.basename(config.get("remote_url", "")), str(count)])
+ count += 1
+ # 不能改变原来的handle
+ new_handle = copy.deepcopy(handle)
+ # 解析handle中的变量
+ VarParser.parse_vars(new_handle, [config])
+ # 生成操作id
+ new_handle["tool_name"] = config.get("name")
+ new_handle["step_id"] = step_id
+ operate_list.append(new_handle)
+ return operate_list
+
+ def _generate_download_config(self, config):
+ try:
+ return {
+ "remote_url": config["remote_url"],
+ "unzip_dir": config["unzip_dir"],
+ "unzip_filename": config["unzip_filename"],
+ "download_dir": config.get("download_dir", config["download_root"]),
+ "operate_type": "download",
+ "name": config.get("name"),
+ }
+ except KeyError as e:
+ print(f"error config: {config}")
+ raise e
+
+ def _unify_config(self, *additional_configs) -> dict:
+ unified_config = dict()
+ for config in additional_configs:
+ unified_config.update(config)
+ return unified_config
+
+
+class Filter:
+ def __init__(self, configs=[]):
+ self.input_configs = copy.deepcopy(configs)
+
+ @classmethod
+ def filter_platform(cls, current_os: str, current_cpu: str, config: dict) -> list:
+ """获取匹配当前操作系统的配置"""
+ if not config:
+ return []
+
+ filtered = []
+
+ for os_key, os_config in config.items():
+ # 逗号分割操作系统名
+ configured_os_list = [o.strip() for o in os_key.split(",")]
+ if current_os in configured_os_list:
+ # 不配cpu场景
+ if isinstance(os_config, list):
+ filtered.extend(os_config)
+ continue
+ # 不配cpu, 仅有一个配置项场景
+ if isinstance(os_config, dict) and "remote_url" in os_config:
+ filtered.extend(os_config)
+ continue
+ # 配cpu场景
+ filtered.extend(cls.filter_cpu(current_cpu, os_config))
+ return filtered
+
+ @classmethod
+ def filter_cpu(cls, current_cpu: str, os_config: dict) -> list:
+ filtered = []
+ for cpu_str in os_config:
+ configured_cpu_list = [c.strip() for c in cpu_str.split(",")]
+ if current_cpu in configured_cpu_list:
+ cpu_config = os_config[cpu_str]
+ # cpu配置内部可以是一个配置,也可以是一个配置列表
+ if not isinstance(cpu_config, list):
+ cpu_config = [cpu_config]
+ filtered.extend(cpu_config)
+ return filtered
+
+ def apply_filters(self, input_tag: str, input_type: str):
+ return self.filter_tag(input_tag).filter_type(input_type).result()
+
+ def filter_tag(self, input_tag: str) -> 'Filter':
+ """过滤tag字段"""
+ filtered = []
+ for config in self.input_configs:
+ tag = config.get("tag")
+ if not tag:
+ filtered.append(config)
+ continue
+ # 配置的tag,转set
+ if isinstance(tag, str):
+ configured_tags = set([t.strip() for t in tag.split(",")])
+ else:
+ configured_tags = set(tag)
+ # 输入的tag,转set
+ input_tags = set([t.strip() for t in input_tag.split(",")])
+
+ # 检查二者是否有交集,有则添加
+ if not input_tags.isdisjoint(configured_tags):
+ filtered.append(config)
+ self.input_configs = filtered
+ return self
+
+ def filter_type(self, input_type: str) -> 'Filter':
+ """过滤type字段"""
+ filtered = []
+ for config in self.input_configs:
+ _type = config.get("type")
+ if not _type:
+ filtered.append(config)
+ continue
+ # 配置的type,转set
+ if isinstance(_type, str):
+ configured_types = set([t.strip() for t in _type.split(",")])
+ else:
+ configured_types = set(_type)
+ # 输入的type,转set
+ input_types = set([t.strip() for t in input_type.split(",")])
+
+ # 检查二者是否有交集,有则添加
+ if not input_types.isdisjoint(configured_types):
+ filtered.append(config)
+ self.input_configs = filtered
+ return self
+
+ def result(self):
+ return self.input_configs
+
+
+class VarParser:
+ var_pattern: re.Pattern = re.compile(r'\$\{.*?\}') # 正则表达式
+
+ @classmethod
+ def remove_undefined(cls, configs: list) -> list:
+ useful_config = []
+ for config in configs:
+ if not cls.has_undefined_var(config):
+ useful_config.append(config)
+ return useful_config
+
+ @classmethod
+ def has_undefined_var(cls, data):
+ try:
+ if isinstance(data, str):
+ return bool(cls.var_pattern.findall(data))
+ elif isinstance(data, list):
+ return any(cls.has_undefined_var(item) for item in data)
+ elif isinstance(data, dict):
+ return any(cls.has_undefined_var(value) for value in data.values())
+ else:
+ return False
+ except AttributeError:
+ print("var_pattern不是有效的正则表达式对象")
+ return False
+
+ @classmethod
+ def parse_vars(cls, data: dict, dictionarys: list):
+ """
+ 解析config中的变量, 先自解析, 再按顺序查字典
+ :param config: 需要进行变量解析的配置
+ :param dictionarys: 字典列表
+ """
+ cls.replace_vars_in_data(data, data)
+ for dic in dictionarys:
+ cls.replace_vars_in_data(data, dic)
+
+ @classmethod
+ def replace_vars_in_data(cls, data: any, dictionary: dict) -> any:
+ """用dictionary字典中的值替换data中的变量,data可以为列表、字典、字符串等类型, 变量使用${var_name}形式"""
+ if isinstance(data, str):
+ return cls.replace_vars_in_string(data, dictionary)
+ elif isinstance(data, dict):
+ for k in list(data.keys()):
+ original_value = data[k]
+ new_value = cls.replace_vars_in_data(original_value, dictionary)
+ if new_value is not original_value: # 仅当original_value为字符串时成立
+ data[k] = new_value
+ elif isinstance(data, list):
+ for i in range(len(data)):
+ original_value = data[i]
+ new_value = cls.replace_vars_in_data(original_value, dictionary)
+ if new_value is not original_value:
+ data[i] = new_value
+ else:
+ return data
+ return data
+
+ @classmethod
+ def replace_vars_in_string(cls, s: str, dictionary: dict) -> str:
+
+ """用dictionary字典中的值替换字符串s中的变量, 变量使用${var_name}形式"""
+
+ replaced_var_names = set() # 避免循环依赖
+
+ while True:
+ try:
+ replaced = cls.var_pattern.sub(
+ lambda matched_var: cls._replace_var_with_dict_value(matched_var, dictionary, replaced_var_names),
+ s)
+ if replaced == s:
+ break
+ s = replaced
+ except ValueError as e:
+ print(f"replace var in string {s} failed")
+ raise e
+ return s
+
+ @classmethod
+ def _replace_var_with_dict_value(cls, matched_var, dictionary, replaced_var_names):
+ var_name = matched_var.group()[2:-1]
+ if var_name in replaced_var_names:
+ raise ValueError(f"Variable \"{var_name}\" is being replaced again.")
+ if dictionary.get(var_name):
+ replaced_var_names.add(var_name)
+ return dictionary.get(var_name, matched_var.group()) # 找得到就替换,找不到就保留原始值
\ No newline at end of file
diff --git a/prebuilts_service/download_util.py b/prebuilts_service/download_util.py
new file mode 100644
index 0000000000000000000000000000000000000000..2fd4b58f761ec60cf68b070d1be3a2b345378b87
--- /dev/null
+++ b/prebuilts_service/download_util.py
@@ -0,0 +1,148 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# Copyright (c) 2025 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import importlib
+import os
+from common_utils import run_cmd
+import threading
+import hashlib
+
+
+remote_sha256_cache = dict()
+_cache_lock = threading.Lock()
+
+
+def import_rich_module():
+ module = importlib.import_module("rich.progress")
+ progress = module.Progress(
+ module.TextColumn("[bold blue]{task.fields[filename]}", justify="right"),
+ module.BarColumn(bar_width=None),
+ "[progress.percentage]{task.percentage:>3.1f}%",
+ "•",
+ module.DownloadColumn(),
+ "•",
+ module.TransferSpeedColumn(),
+ "•",
+ module.TimeRemainingColumn(),
+ )
+ return progress
+
+
+def check_sha256_by_mark(remote_url, unzip_dir: str, unzip_filename: str) -> tuple:
+ """
+ 检查是否存在和远程文件哈希值匹配的解压完成标记文件
+ 标记文件名:远程文件哈希值 + '.' + unzip_filename + '.mark'
+ """
+
+
+ remote_sha256 = get_remote_sha256(remote_url)
+ mark_file_name = remote_sha256 + '.' + unzip_filename + '.mark'
+ mark_file_path = os.path.join(unzip_dir, mark_file_name)
+ return os.path.exists(mark_file_path), mark_file_path
+
+
+def file_sha256(file_path):
+ sha = hashlib.sha256()
+ with open(file_path, "rb") as f:
+ while chunk := f.read(8192): # 分块读取大文件,避免内存问题
+ sha.update(chunk)
+ return sha.hexdigest()
+
+
+def check_sha256(remote_url: str, local_file: str) -> bool:
+ """
+ 检查本地文件的SHA256值是否与远程文件一致
+ """
+
+ remote_sha256 = get_remote_sha256(remote_url)
+ local_sha256 = file_sha256(local_file)
+ if remote_sha256 != local_sha256:
+ print(
+ "remote file {}.sha256 is not found, begin check SHASUMS256.txt".format(
+ remote_url
+ )
+ )
+ remote_sha256 = obtain_sha256_by_sha_sums256(remote_url)
+ return remote_sha256 == local_sha256
+
+
+def get_remote_sha256(remote_url: str) -> str:
+ """
+ 从远程.sha256文件中获取哈希值
+ """
+ with _cache_lock: # 加锁检查缓存
+ if remote_url in remote_sha256_cache:
+ return remote_sha256_cache[remote_url]
+
+ # 在锁外执行耗时操作(如网络请求)
+ check_sha256_cmd = f"curl -s -k {remote_url}.sha256"
+ remote_sha256, _, _ = run_cmd(check_sha256_cmd.split())
+
+ with _cache_lock: # 加锁更新缓存
+ remote_sha256_cache[remote_url] = remote_sha256
+ return remote_sha256
+
+
+def obtain_sha256_by_sha_sums256(remote_url: str) -> str:
+ """
+ 从远程的SHASUMS256.txt中获取SHA256值
+ """
+ sha_sums256 = "SHASUMS256.txt"
+ sha_sums256_path = os.path.join(os.path.dirname(remote_url), sha_sums256)
+ file_name = os.path.basename(remote_url)
+ cmd = "curl -s -k " + sha_sums256_path
+ data_sha_sums256, _, _ = run_cmd(cmd.split())
+ remote_sha256 = None
+ for line in data_sha_sums256.split("\n"):
+ if file_name in line:
+ remote_sha256 = line.split(" ")[0]
+ return remote_sha256
+
+
+def get_local_path(download_root: str, remote_url: str):
+ """根据远程URL生成本地路径,本地文件名为url的MD5值+远程文件名
+ """
+ remote_file_name = os.path.basename(remote_url)
+ remote_url_md5_value = hashlib.md5((remote_url + '\n').encode()).hexdigest()
+ local_path = os.path.join(download_root, '{}.{}'.format(remote_url_md5_value, remote_file_name))
+ return local_path
+
+
+def extract_compress_files_and_gen_mark(source_file: str, unzip_dir: str, mark_file_path: str):
+ """
+ 解压缩文件并生成解压完成标记文件
+ 标记文件名:远程文件哈希值 + '.' + unzip_filename + '.mark'
+ """
+ if not os.path.exists(unzip_dir):
+ os.makedirs(unzip_dir, exist_ok=True)
+ if source_file.endswith(".zip"):
+ command = ["unzip", "-qq", "-o", "-d", unzip_dir, source_file]
+ elif source_file.endswith(".tar.gz"):
+ command = ["tar", "-xzf", source_file, "-C", unzip_dir]
+ elif source_file.endswith(".tar.xz"):
+ command = ["tar", "-xJf", source_file, "-C", unzip_dir]
+ elif source_file.endswith(".tar"):
+ command = ["tar", "-xvf", source_file, "-C", unzip_dir]
+ else:
+ print("暂不支持解压此类型压缩文件!")
+ return
+
+ _, err, retcode = run_cmd(command)
+ if retcode != 0:
+ print("解压失败,错误信息:", err)
+ return
+ else:
+ with open(mark_file_path, "w") as f:
+ f.write("0")
diff --git a/prebuilts_service/operater.py b/prebuilts_service/operater.py
new file mode 100644
index 0000000000000000000000000000000000000000..d7cfe0ca22529f19d62ef0e82b54b8b232ca4a70
--- /dev/null
+++ b/prebuilts_service/operater.py
@@ -0,0 +1,185 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# Copyright (c) 2025 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import shutil
+import subprocess
+from common_utils import (
+ symlink_src2dest,
+ copy_folder,
+ remove_dest_path,
+ run_cmd_live,
+ install_hpm,
+ install_hpm_in_other_platform,
+ npm_install,
+ is_system_component,
+)
+import re
+
+
+class OperateHanlder:
+ global_args = None
+
+ @staticmethod
+ def run(operate_list: list, global_args, unchanged_list: tuple = ()):
+ ignore_list = []
+ OperateHanlder.global_args = global_args
+ pre_process_tool = ""
+ for operate in operate_list:
+ try:
+ current_tool = re.match(r"(.*)_\d$", operate.get("step_id")).group(1)
+ shot_name = re.sub(r"(\.[A-Za-z]+)+$", "", current_tool).strip("_")
+
+ if current_tool != pre_process_tool:
+ print(f"\n==> process {shot_name}")
+ pre_process_tool = current_tool
+
+ if current_tool in ignore_list:
+ continue
+
+ getattr(OperateHanlder, "_" + operate.get("type"))(operate)
+ except Exception as e:
+ if current_tool in unchanged_list:
+ ignore_list.append(current_tool)
+ print(f"<== ignore process {shot_name}")
+ continue
+ else:
+ raise e
+
+ @staticmethod
+ def _symlink(operate: dict):
+ src = operate.get("src")
+ dest = operate.get("dest")
+ symlink_src2dest(src, dest)
+
+ @staticmethod
+ def _copy(operate: dict):
+ src = operate.get("src")
+ dest = operate.get("dest")
+ try:
+ shutil.copy2(src, dest)
+ except IsADirectoryError:
+ copy_folder(src, dest)
+ print(f"copy {src} ---> dest: {dest}")
+
+ @staticmethod
+ def _remove(operate: dict):
+ path = operate.get("path")
+ if isinstance(path, list):
+ for p in path:
+ remove_dest_path(p)
+ else:
+ remove_dest_path(path)
+ print(f"remove {path}")
+
+ @staticmethod
+ def _move(operate: dict):
+ src = operate.get("src")
+ dest = operate.get("dest")
+
+ filetype = operate.get("filetype", None)
+ if filetype:
+ file_list = os.listdir(src)
+ for file in file_list:
+ if file.endswith(filetype):
+ file_path = os.path.join(src, file)
+ shutil.move(file_path, dest)
+ print(f"move {file_path} ---> dest: {dest}")
+ else:
+ shutil.move(src, dest)
+ print(f"move {src} ---> dest: {dest}")
+
+ @staticmethod
+ def _shell(operate: dict):
+ cmd = operate.get("cmd")
+ run_cmd_live(cmd)
+
+
+ @staticmethod
+ def _hpm_download(operate: dict):
+ name = operate.get("name")
+ download_dir = operate.get("download_dir")
+ npm_tool_path = os.path.join(OperateHanlder.global_args.code_dir, "prebuilts/build-tools/common/nodejs/current/bin/npm")
+ symlink_dest = operate.get("symlink")
+ if "@ohos/hpm-cli" == name:
+ install_hpm(npm_tool_path, download_dir)
+ symlink_src2dest(os.path.join(download_dir, "node_modules"), symlink_dest)
+ return
+ else:
+ install_hpm_in_other_platform(name, operate)
+
+ @staticmethod
+ def _npm_install(operate: dict, max_retry_times=2):
+ # 若不是系统组件,直接返回
+ if not is_system_component():
+ return
+ success_installed_npm_config = []
+
+ for retry_times in range(max_retry_times + 1):
+ try:
+ result, error = npm_install(operate, OperateHanlder.global_args, success_installed_npm_config)
+ if result:
+ return
+ print("npm install error, error info: %s", error)
+ except Exception as e:
+ print("An unexpected error occurred during npm install: %s", str(e))
+ error = str(e)
+
+ # 重试次数超过最大限制,处理错误日志
+ for error_info in error.split("\n"):
+ if error_info.endswith("debug.log"):
+ log_path = error_info.split()[-1]
+ try:
+ # 读取日志文件内容
+ result = subprocess.run(
+ ["cat", log_path],
+ capture_output=True,
+ text=True,
+ timeout=60
+ )
+ print("npm debug log content:\n%s", result.stdout)
+ except subprocess.TimeoutExpired:
+ print("Reading npm debug log timed out after 60 seconds.")
+ except Exception as e:
+ print("Error reading npm debug log: %s", str(e))
+ break
+
+ # 抛出最终异常
+ raise Exception("npm install error with three times, prebuilts download exit")
+
+ @staticmethod
+ def _node_modules_copy(operate: dict):
+ if not is_system_component():
+ return
+
+ copy_list = operate.get("copy_list")
+ for copy_config in copy_list:
+ src_dir = copy_config.get("src")
+ if not os.path.exists(src_dir):
+ print(f"{src_dir} not exist, skip node_modules copy.")
+ continue
+ dest_dir = copy_config.get("dest")
+ use_symlink = copy_config.get("use_symlink")
+ if os.path.exists(os.path.dirname(dest_dir)):
+ print("remove", os.path.dirname(dest_dir))
+ shutil.rmtree(os.path.dirname(dest_dir))
+ if use_symlink == "True" and OperateHanlder.global_args.enable_symlink == True:
+ os.makedirs(os.path.dirname(dest_dir), exist_ok=True)
+ os.symlink(src_dir, dest_dir)
+ print(f"symlink {src_dir} ---> dest: {dest_dir}")
+ else:
+ shutil.copytree(src_dir, dest_dir, symlinks=True)
+ print(f"copy {src_dir} ---> dest: {dest_dir}")
+
diff --git a/prebuilts_service/pool_downloader.py b/prebuilts_service/pool_downloader.py
new file mode 100644
index 0000000000000000000000000000000000000000..454c864e78eed280777e357e66d4b6aa269099b8
--- /dev/null
+++ b/prebuilts_service/pool_downloader.py
@@ -0,0 +1,179 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# Copyright (c) 2025 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from download_util import (
+ check_sha256,
+ check_sha256_by_mark,
+ extract_compress_files_and_gen_mark,
+ get_local_path,
+ run_cmd,
+ import_rich_module,
+)
+import os
+import sys
+import re
+import glob
+import traceback
+import threading
+from concurrent.futures import ThreadPoolExecutor, as_completed
+from multiprocessing import cpu_count
+from urllib.request import urlopen
+from functools import partial
+
+
+class PoolDownloader:
+ def __init__(self, download_configs: list, global_args: object = None):
+ if not global_args.disable_rich:
+ self.progress = import_rich_module()
+ else:
+ self.progress = None
+ self.global_args = global_args
+ self.download_configs = download_configs
+ self.lock = threading.Lock()
+ self.unchanged_tool_list = []
+
+ def start(self) -> list:
+ if self.progress:
+ with self.progress:
+ self._run_download_in_thread_pool()
+ else:
+ self._run_download_in_thread_pool()
+ return self.unchanged_tool_list
+
+ def _run_download_in_thread_pool(self):
+ try:
+ cnt = cpu_count()
+ except Exception as e:
+ cnt = 1
+ with ThreadPoolExecutor(max_workers=cnt) as pool:
+ tasks = dict()
+ for config_item in self.download_configs:
+ task = pool.submit(self._process, config_item)
+ tasks[task] = os.path.basename(config_item.get("remote_url"))
+ self._wait_for_download_tasks_complete(tasks)
+
+ def _wait_for_download_tasks_complete(self, tasks: dict):
+ for task in as_completed(tasks):
+ try:
+ _ = task.result()
+ except Exception as e:
+ self._adaptive_print(f"Task {task} generated an exception: {e}", style="red")
+ self._adaptive_print(traceback.format_exc())
+ else:
+ self._adaptive_print(
+ "{}, download and decompress completed".format(tasks.get(task)),
+ style="green",
+ )
+
+ def _adaptive_print(self, msg: str, **kwargs):
+ if self.progress:
+ self.progress.console.log(msg, **kwargs)
+ else:
+ print(msg)
+
+ def _process(self, operate: dict):
+ global_args = self.global_args
+ remote_url = operate.get("remote_url")
+ if "python" in remote_url and global_args.glibc_version is not None:
+ remote_url = re.sub(r"GLIBC[0-9]\.[0-9]{2}", global_args.glibc_version, remote_url)
+ remote_url = global_args.tool_repo + remote_url
+
+ download_root = operate.get("download_dir")
+ unzip_dir = operate.get("unzip_dir")
+ unzip_filename = operate.get("unzip_filename")
+ local_path = get_local_path(download_root, remote_url)
+
+ mark_file_exist, mark_file_path = check_sha256_by_mark(remote_url, unzip_dir, unzip_filename)
+ # 检查解压的文件是否和远程一致
+ if mark_file_exist:
+ self._adaptive_print(
+ "{}, Sha256 markword check OK.".format(remote_url), style="green"
+ )
+ with self.lock:
+ self.unchanged_tool_list.append(operate.get("name") + "_" + os.path.basename(remote_url))
+ else:
+ # 不一致则先删除产物
+ run_cmd(["rm", "-rf"] + glob.glob(f"{unzip_dir}/*.{unzip_filename}.mark", recursive=False))
+ run_cmd(["rm", "-rf", '{}/{}'.format(unzip_dir, unzip_filename)])
+ # 校验压缩包
+ if os.path.exists(local_path):
+ check_result = check_sha256(remote_url, local_path)
+ if check_result:
+ self._adaptive_print(
+ "{}, Sha256 check download OK.".format(local_path),
+ style="green",
+ )
+ else:
+ # 压缩包不一致则删除压缩包,重新下载
+ os.remove(local_path)
+ self._try_download(remote_url, local_path)
+ else:
+ # 压缩包不存在则下载
+ self._try_download(remote_url, local_path)
+
+ # 解压缩包
+ self._adaptive_print("Start decompression {}".format(local_path))
+ extract_compress_files_and_gen_mark(local_path, unzip_dir, mark_file_path)
+ self._adaptive_print(f"{local_path} extracted to {unzip_dir}")
+
+ def _try_download(self, remote_url: str, local_path: str):
+ max_retry_times = 3
+ # 创建下载目录
+ download_dir = os.path.dirname(local_path)
+ os.makedirs(download_dir, exist_ok=True)
+
+ # 获取进度条和任务 ID
+ progress = self.progress
+ progress_task_id = progress.add_task(
+ "download", filename=os.path.basename(remote_url), start=False
+ ) if progress else None
+ self._adaptive_print(f"Downloading {remote_url}")
+ for retry_times in range(max_retry_times):
+ try:
+ self._download_remote_file(remote_url, local_path, progress_task_id)
+ return
+ except Exception as e:
+ error_message = getattr(e, 'code', str(e))
+ self._adaptive_print(
+ f"Failed to open {remote_url}, Error: {error_message}",
+ style="red"
+ )
+
+ # 重试次数达到上限,下载失败
+ self._adaptive_print(
+ f"{local_path}, download failed after {max_retry_times} retries, "
+ "please check network status. Prebuilts download exit."
+ )
+ sys.exit(1)
+
+ def _download_remote_file(self, remote_url: str, local_path: str, progress_task_id):
+ buffer_size = 32768
+ progress = self.progress
+ with urlopen(remote_url) as response:
+ total_size = int(response.info().get("Content-Length", 0))
+
+ if progress:
+ progress.update(progress_task_id, total=total_size)
+ progress.start_task(progress_task_id)
+
+ with open(local_path, "wb") as dest_file:
+ for data in iter(partial(response.read, buffer_size), b""):
+ dest_file.write(data)
+ self._update_progress(progress_task_id, len(data))
+ self._adaptive_print(f"Downloaded {local_path}")
+
+ def _update_progress(self, task_id, advance):
+ if self.progress:
+ self.progress.update(task_id, advance=advance)