mirror of
https://github.com/wnlen/clash-for-linux.git
synced 2026-10-10 04:03:04 +08:00
Add strict offline asset bundles
This commit is contained in:
@@ -8,6 +8,15 @@
|
||||
# Runtime
|
||||
runtime/
|
||||
|
||||
# Optional offline assets
|
||||
resources/bin/mihomo/
|
||||
resources/bin/clash/
|
||||
resources/bin/yq/
|
||||
resources/bin/subconverter/
|
||||
resources/geo/
|
||||
resources/asset-manifest.env
|
||||
resources/SHA256SUMS
|
||||
|
||||
# Local dashboard unpacked files
|
||||
resources/dashboard/dist/
|
||||
|
||||
|
||||
@@ -312,13 +312,14 @@ MIXED_PORT=7890
|
||||
EXTERNAL_CONTROLLER=0.0.0.0:9090
|
||||
CLASH_CONTROLLER_SECRET=your-secret
|
||||
CLASH_SUBSCRIPTION_URL=https://example.com/sub
|
||||
MIHOMO_VERSION=latest
|
||||
CLASH_VERSION=latest
|
||||
YQ_VERSION=v4.44.3
|
||||
MIHOMO_VERSION=v1.19.23
|
||||
CLASH_VERSION=v1.18.0
|
||||
YQ_VERSION=v4.52.4
|
||||
SUBCONVERTER_VERSION=v0.9.9
|
||||
MIHOMO_DOWNLOAD_BASE=https://github.com/MetaCubeX/mihomo/releases/download
|
||||
CLASH_DOWNLOAD_BASE=https://github.com/WindSpiritSR/clash/releases/download
|
||||
CLASH_BUNDLED_ASSET_ENABLED=true
|
||||
CLASH_OFFLINE=false
|
||||
CLASH_SHELL_AUTO_RESTORE_PROXY=true
|
||||
CLASH_PREDOWNLOAD_GEO=true
|
||||
```
|
||||
@@ -349,9 +350,7 @@ CLASH_GH_PROXY=https://ghfast.top
|
||||
|
||||
当前正式支持的架构为 `amd64`、`arm64`、`armv7`。超出这三种架构时会明确失败,不会伪装成已支持。
|
||||
|
||||
如果安装环境访问 GitHub 很慢,可以把 Mihomo、yq、subconverter 的刚需文件跟随项目一起分发。安装和 `clash upgrade` 会优先读取 `resources/bin` 中与当前版本、架构对应的精确文件名;本地没有对应文件时,会回退到原来的远程下载逻辑,不影响后续升级内核。
|
||||
|
||||
Clash 仅作为兼容内核处理,固定走远程下载,不会命中 `resources/bin` 中的本地资源。
|
||||
如果安装环境访问 GitHub 很慢,可以把 Mihomo/Clash、yq、subconverter 的刚需文件跟随项目一起分发。安装和 `clash upgrade` 会优先读取 `resources/bin` 中与当前版本、架构对应的精确文件名;普通在线模式下,本地没有对应文件时会回退到远程下载。
|
||||
|
||||
推荐路径直接放在分类目录下:
|
||||
|
||||
@@ -359,6 +358,9 @@ Clash 仅作为兼容内核处理,固定走远程下载,不会命中 `resour
|
||||
resources/bin/mihomo/mihomo-linux-amd64-compatible-v1.19.23.gz
|
||||
resources/bin/mihomo/mihomo-linux-arm64-v1.19.23.gz
|
||||
resources/bin/mihomo/mihomo-linux-armv7-v1.19.23.gz
|
||||
resources/bin/clash/clash-linux-amd64-v1.18.0.gz
|
||||
resources/bin/clash/clash-linux-arm64-v1.18.0.gz
|
||||
resources/bin/clash/clash-linux-armv7-v1.18.0.gz
|
||||
resources/bin/yq/yq_linux_amd64.tar.gz
|
||||
resources/bin/yq/yq_linux_arm64.tar.gz
|
||||
resources/bin/yq/yq_linux_arm.tar.gz
|
||||
@@ -372,6 +374,39 @@ resources/geo/Country.mmdb
|
||||
|
||||
也可以设置 `CLASH_BUNDLED_ASSET_ENABLED=false` 强制跳过内置文件,或用 `CLASH_BUNDLED_ASSET_DIR=/path/to/assets` 指向项目外的资源目录。Mihomo、yq、subconverter 兼容旧路径 `resources/bin/<category>/<version>/<file>`。
|
||||
|
||||
#### 离线资源包
|
||||
|
||||
推荐在有代理或网络较好的设备上,按目标主机架构生成资源包:
|
||||
|
||||
```bash
|
||||
# 查看将要下载的文件,不产生网络请求
|
||||
bash scripts/prefetch-assets.sh --arch amd64 --dry-run
|
||||
|
||||
# 生成 amd64 + Mihomo 资源包
|
||||
bash scripts/prefetch-assets.sh \
|
||||
--arch amd64 \
|
||||
--kernel mihomo \
|
||||
--output clash-assets-mihomo-amd64.tar.gz
|
||||
```
|
||||
|
||||
支持的目标架构为 `amd64`、`arm64`、`armv7`。脚本默认包含内核、yq、subconverter 和五个 GEO 文件,只打包 `resources/` 静态资源,不会把本机的订阅、日志、密钥或其他 `runtime/` 状态带入资源包。压缩包同时包含版本/架构清单与 `SHA256SUMS`。
|
||||
|
||||
把项目和资源包复制到目标主机,在项目根目录执行:
|
||||
|
||||
```bash
|
||||
tar -xzf clash-assets-mihomo-amd64.tar.gz
|
||||
bash install.sh --offline
|
||||
```
|
||||
|
||||
`--offline` 等价于本次安装设置 `CLASH_OFFLINE=true`。安装脚本会先集中检查架构、版本、校验和及所有必需文件;有任何缺失都会明确列出并停止,不会静默回退到 GitHub。也可以和安装范围一起使用:
|
||||
|
||||
```bash
|
||||
bash install.sh system --offline
|
||||
bash install.sh user --offline
|
||||
```
|
||||
|
||||
严格离线安装时,订阅也不能使用远程 URL。可暂时不配置订阅,或者提前准备 Clash YAML 并通过 `file:///绝对路径/config.yaml` 导入。使用 `--no-geo` 生成精简资源包时,目标项目还需要设置 `CLASH_PREDOWNLOAD_GEO=false`;若最终配置使用 `GEOIP`,仍须提供 `Country.mmdb`。
|
||||
|
||||
### `runtime/mixin.yaml`(兼容 `config/mixin.yaml`)
|
||||
|
||||
用于对最终运行配置做补丁:
|
||||
|
||||
+13
-2
@@ -12,10 +12,20 @@ source "$PROJECT_DIR/scripts/init/systemd-user.sh"
|
||||
source "$PROJECT_DIR/scripts/init/script.sh"
|
||||
|
||||
init_project_context "$PROJECT_DIR"
|
||||
guard_unsafe_sudo_auto_install "${1:-}"
|
||||
parse_install_options "$@"
|
||||
|
||||
if [ "$INSTALL_SHOW_HELP" = "true" ]; then
|
||||
print_install_usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
guard_unsafe_sudo_auto_install "$INSTALL_REQUESTED_SCOPE"
|
||||
load_env_if_exists
|
||||
if [ "$INSTALL_OFFLINE_REQUESTED" = "true" ]; then
|
||||
export CLASH_OFFLINE="true"
|
||||
fi
|
||||
migrate_env_legacy_compat_fields "$PROJECT_DIR/.env"
|
||||
detect_install_scope "${1:-auto}"
|
||||
detect_install_scope "$INSTALL_REQUESTED_SCOPE"
|
||||
ensure_project_not_wsl_windows_mount
|
||||
|
||||
ensure_openwrt_install_supported
|
||||
@@ -23,6 +33,7 @@ ensure_required_commands
|
||||
|
||||
init_layout
|
||||
ensure_dashboard_deploy_prerequisites
|
||||
preflight_offline_assets
|
||||
|
||||
resolve_geo_assets
|
||||
|
||||
|
||||
+13
-3
@@ -1,8 +1,6 @@
|
||||
# 内置运行依赖
|
||||
|
||||
如果安装时 GitHub 下载太慢,可以把 Mihomo、yq、subconverter 提前放到本目录。安装和 `clash upgrade` 会优先读取这里的文件;没有匹配文件时,仍会回退到原来的下载逻辑。
|
||||
|
||||
Clash 是兼容内核,固定走远程下载,不使用本目录中的本地资源。
|
||||
如果安装时 GitHub 下载太慢,可以把 Mihomo/Clash、yq、subconverter 提前放到本目录。安装和 `clash upgrade` 会优先读取这里的文件;普通在线模式下,没有匹配文件时仍会回退到原来的下载逻辑。
|
||||
|
||||
默认目录结构:
|
||||
|
||||
@@ -12,6 +10,10 @@ resources/bin/
|
||||
mihomo-linux-amd64-compatible-v1.19.23.gz
|
||||
mihomo-linux-arm64-v1.19.23.gz
|
||||
mihomo-linux-armv7-v1.19.23.gz
|
||||
clash/
|
||||
clash-linux-amd64-v1.18.0.gz
|
||||
clash-linux-arm64-v1.18.0.gz
|
||||
clash-linux-armv7-v1.18.0.gz
|
||||
yq/
|
||||
yq_linux_amd64.tar.gz
|
||||
yq_linux_arm64.tar.gz
|
||||
@@ -34,3 +36,11 @@ export CLASH_BUNDLED_ASSET_DIR=/path/to/assets
|
||||
```
|
||||
|
||||
`Country.mmdb` 仍放在 `resources/geo/Country.mmdb` 或 `resources/geo/country.mmdb`。
|
||||
|
||||
推荐通过项目提供的脚本生成完整资源包:
|
||||
|
||||
```bash
|
||||
bash scripts/prefetch-assets.sh --arch amd64 --kernel mihomo
|
||||
```
|
||||
|
||||
将生成的压缩包复制到目标主机并解压到项目根目录后,可执行 `bash install.sh --offline`。严格离线模式会在安装前检查全部资源,缺失时直接失败,不会回退联网下载。资源包只包含 `resources/`,不会包含可能带有订阅、日志或密钥的 `runtime/`。
|
||||
|
||||
+144
-7
@@ -428,16 +428,75 @@ bundled_asset_root() {
|
||||
echo "$RESOURCE_DIR/bin"
|
||||
}
|
||||
|
||||
copy_bundled_asset() {
|
||||
bundled_asset_metadata_root() {
|
||||
if [ -n "${CLASH_BUNDLED_ASSET_DIR:-}" ]; then
|
||||
echo "$CLASH_BUNDLED_ASSET_DIR"
|
||||
return 0
|
||||
fi
|
||||
|
||||
[ -n "${RESOURCE_DIR:-}" ] || return 1
|
||||
echo "$RESOURCE_DIR"
|
||||
}
|
||||
|
||||
bundled_asset_manifest_file() {
|
||||
local root
|
||||
|
||||
root="$(bundled_asset_metadata_root 2>/dev/null || true)"
|
||||
[ -n "${root:-}" ] || return 1
|
||||
echo "$root/asset-manifest.env"
|
||||
}
|
||||
|
||||
bundled_asset_checksums_file() {
|
||||
local root
|
||||
|
||||
root="$(bundled_asset_metadata_root 2>/dev/null || true)"
|
||||
[ -n "${root:-}" ] || return 1
|
||||
echo "$root/SHA256SUMS"
|
||||
}
|
||||
|
||||
read_bundled_asset_manifest_value() {
|
||||
local key="$1"
|
||||
local file
|
||||
|
||||
file="$(bundled_asset_manifest_file 2>/dev/null || true)"
|
||||
[ -n "${file:-}" ] && [ -f "$file" ] || return 1
|
||||
|
||||
sed -nE "s/^[[:space:]]*${key}=['\"]?([^'\"]*)['\"]?$/\1/p" "$file" | head -n 1
|
||||
}
|
||||
|
||||
bundled_asset_manifest_compatible() {
|
||||
local category="$1"
|
||||
local version="$2"
|
||||
local file bundle_arch bundle_version version_key
|
||||
|
||||
file="$(bundled_asset_manifest_file 2>/dev/null || true)"
|
||||
[ -n "${file:-}" ] && [ -f "$file" ] || return 0
|
||||
|
||||
bundle_arch="$(read_bundled_asset_manifest_value "BUNDLE_ARCH" 2>/dev/null || true)"
|
||||
if [ -n "${bundle_arch:-}" ] && [ "$bundle_arch" != "$(get_arch)" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
case "$category" in
|
||||
mihomo) version_key="MIHOMO_VERSION" ;;
|
||||
clash) version_key="CLASH_VERSION" ;;
|
||||
yq) version_key="YQ_VERSION" ;;
|
||||
subconverter) version_key="SUBCONVERTER_VERSION" ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
|
||||
bundle_version="$(read_bundled_asset_manifest_value "$version_key" 2>/dev/null || true)"
|
||||
[ -z "${bundle_version:-}" ] || [ "$bundle_version" = "$version" ]
|
||||
}
|
||||
|
||||
find_bundled_asset() {
|
||||
local category="$1"
|
||||
local version="$2"
|
||||
local file="$3"
|
||||
local out="$4"
|
||||
local asset_name="${5:-$file}"
|
||||
local root candidate
|
||||
|
||||
[ "$category" != "clash" ] || return 1
|
||||
bundled_asset_enabled || return 1
|
||||
bundled_asset_manifest_compatible "$category" "$version" || return 1
|
||||
|
||||
root="$(bundled_asset_root 2>/dev/null || true)"
|
||||
[ -n "${root:-}" ] || return 1
|
||||
@@ -448,16 +507,46 @@ copy_bundled_asset() {
|
||||
"$root/$file" \
|
||||
"$RESOURCE_DIR/$category/$file"; do
|
||||
[ -s "$candidate" ] || continue
|
||||
echo "$candidate"
|
||||
return 0
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
copy_bundled_asset() {
|
||||
local category="$1"
|
||||
local version="$2"
|
||||
local file="$3"
|
||||
local out="$4"
|
||||
local asset_name="${5:-$file}"
|
||||
local candidate
|
||||
|
||||
candidate="$(find_bundled_asset "$category" "$version" "$file" 2>/dev/null || true)"
|
||||
[ -n "${candidate:-}" ] || return 1
|
||||
|
||||
mkdir -p "$(dirname "$out")"
|
||||
if [ "$candidate" != "$out" ]; then
|
||||
cp -f "$candidate" "$out"
|
||||
fi
|
||||
success "${asset_name} 已使用内置资源:$candidate"
|
||||
return 0
|
||||
done
|
||||
}
|
||||
|
||||
return 1
|
||||
offline_mode_enabled() {
|
||||
case "${CLASH_OFFLINE:-false}" in
|
||||
true|1|yes|on|TRUE|YES|ON) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
offline_download_blocked() {
|
||||
local asset_name="$1"
|
||||
local url="${2:-}"
|
||||
local url_hint=""
|
||||
|
||||
[ -n "${url:-}" ] && url_hint=";远程地址:$url"
|
||||
die_state "离线模式禁止下载:${asset_name}${url_hint}" \
|
||||
"请补齐离线资源包后重试,或移除 --offline / CLASH_OFFLINE=true 允许联网下载"
|
||||
}
|
||||
|
||||
download_connect_timeout() {
|
||||
@@ -934,6 +1023,10 @@ download_file() {
|
||||
local tried_urls=""
|
||||
local fetch_tmp
|
||||
|
||||
if offline_mode_enabled; then
|
||||
offline_download_blocked "$asset_name" "$url"
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "$out")"
|
||||
rm -f "$out" 2>/dev/null || true
|
||||
|
||||
@@ -1031,6 +1124,10 @@ download_http_fetch_to_file() {
|
||||
local max_time="${5:-300}"
|
||||
local progress_arg="--progress-bar"
|
||||
|
||||
if offline_mode_enabled; then
|
||||
offline_download_blocked "$(basename "${url%%\?*}")" "$url"
|
||||
fi
|
||||
|
||||
curl_download \
|
||||
"$progress_arg" \
|
||||
--show-error \
|
||||
@@ -1171,6 +1268,46 @@ guard_unsafe_sudo_auto_install() {
|
||||
fi
|
||||
}
|
||||
|
||||
parse_install_options() {
|
||||
local arg
|
||||
|
||||
INSTALL_REQUESTED_SCOPE="auto"
|
||||
INSTALL_OFFLINE_REQUESTED="false"
|
||||
INSTALL_SHOW_HELP="false"
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
system|user|auto)
|
||||
if [ "$INSTALL_REQUESTED_SCOPE" != "auto" ] && [ "$INSTALL_REQUESTED_SCOPE" != "$arg" ]; then
|
||||
die_usage "安装范围不能同时指定为 $INSTALL_REQUESTED_SCOPE 和 $arg" \
|
||||
"用法:bash install.sh [system|user|auto] [--offline]"
|
||||
fi
|
||||
INSTALL_REQUESTED_SCOPE="$arg"
|
||||
;;
|
||||
--offline)
|
||||
INSTALL_OFFLINE_REQUESTED="true"
|
||||
;;
|
||||
-h|--help)
|
||||
INSTALL_SHOW_HELP="true"
|
||||
;;
|
||||
*)
|
||||
die_usage "未知安装参数:$arg" \
|
||||
"用法:bash install.sh [system|user|auto] [--offline]"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
print_install_usage() {
|
||||
cat <<'EOF'
|
||||
用法:
|
||||
bash install.sh [system|user|auto] [--offline]
|
||||
|
||||
选项:
|
||||
--offline 严格离线安装;缺少本地资源时直接失败,不回退联网下载
|
||||
EOF
|
||||
}
|
||||
|
||||
detect_install_scope() {
|
||||
local requested="${1:-auto}"
|
||||
|
||||
|
||||
+261
-47
@@ -13,10 +13,256 @@ GEO_ASSET_DOWNLOADS=(
|
||||
"resources/geo/GeoSite.dat https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat"
|
||||
)
|
||||
|
||||
resolve_geo_assets() {
|
||||
geo_predownload_enabled() {
|
||||
case "${CLASH_PREDOWNLOAD_GEO:-true}" in
|
||||
0|false|no|off|disable|disabled|FALSE|NO|OFF) return 0 ;;
|
||||
0|false|no|off|disable|disabled|FALSE|NO|OFF) return 1 ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
yq_asset_file() {
|
||||
case "$1" in
|
||||
amd64) echo "yq_linux_amd64.tar.gz" ;;
|
||||
arm64) echo "yq_linux_arm64.tar.gz" ;;
|
||||
armv7) echo "yq_linux_arm.tar.gz" ;;
|
||||
*) die "暂不支持的 yq 架构:$1" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
mihomo_asset_file() {
|
||||
local arch="$1"
|
||||
local version="$2"
|
||||
|
||||
case "$arch" in
|
||||
amd64) echo "mihomo-linux-amd64-compatible-${version}.gz" ;;
|
||||
arm64) echo "mihomo-linux-arm64-${version}.gz" ;;
|
||||
armv7) echo "mihomo-linux-armv7-${version}.gz" ;;
|
||||
*) die "暂不支持的 Mihomo 架构:$arch" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
subconverter_asset_file() {
|
||||
case "$1" in
|
||||
amd64) echo "subconverter_linux64.tar.gz" ;;
|
||||
arm64) echo "subconverter_aarch64.tar.gz" ;;
|
||||
armv7) echo "subconverter_armv7.tar.gz" ;;
|
||||
*) die "暂不支持的 subconverter 架构:$1" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
clash_asset_candidates() {
|
||||
local arch="$1"
|
||||
local version="$2"
|
||||
local version_no_v="${version#v}"
|
||||
|
||||
case "$arch" in
|
||||
amd64)
|
||||
printf '%s\n' \
|
||||
"clash-linux-amd64-${version}.gz" \
|
||||
"clash-linux-amd64-v${version_no_v}.gz"
|
||||
;;
|
||||
arm64)
|
||||
printf '%s\n' \
|
||||
"clash-linux-arm64-${version}.gz" \
|
||||
"clash-linux-arm64-v${version_no_v}.gz" \
|
||||
"clash-linux-armv8-${version}.gz" \
|
||||
"clash-linux-armv8-v${version_no_v}.gz"
|
||||
;;
|
||||
armv7)
|
||||
printf '%s\n' \
|
||||
"clash-linux-armv7-${version}.gz" \
|
||||
"clash-linux-armv7-v${version_no_v}.gz"
|
||||
;;
|
||||
*)
|
||||
die "暂不支持的 Clash 架构:$arch"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
verify_offline_asset_bundle_metadata() {
|
||||
local manifest checksums metadata_root actual expected kernel
|
||||
local failed="false"
|
||||
|
||||
manifest="$(bundled_asset_manifest_file 2>/dev/null || true)"
|
||||
checksums="$(bundled_asset_checksums_file 2>/dev/null || true)"
|
||||
metadata_root="$(bundled_asset_metadata_root 2>/dev/null || true)"
|
||||
|
||||
if [ -n "${manifest:-}" ] && [ -f "$manifest" ]; then
|
||||
actual="$(read_bundled_asset_manifest_value "BUNDLE_ARCH" 2>/dev/null || true)"
|
||||
expected="$(get_arch)"
|
||||
if [ -n "${actual:-}" ] && [ "$actual" != "$expected" ]; then
|
||||
error "离线资源包架构不匹配:资源包=$actual,目标=$expected"
|
||||
failed="true"
|
||||
fi
|
||||
|
||||
actual="$(read_bundled_asset_manifest_value "YQ_VERSION" 2>/dev/null || true)"
|
||||
expected="${YQ_VERSION:-$DEFAULT_YQ_VERSION}"
|
||||
if [ -n "${actual:-}" ] && [ "$actual" != "$expected" ]; then
|
||||
error "离线资源包 yq 版本不匹配:资源包=$actual,目标=$expected"
|
||||
failed="true"
|
||||
fi
|
||||
|
||||
actual="$(read_bundled_asset_manifest_value "SUBCONVERTER_VERSION" 2>/dev/null || true)"
|
||||
expected="${SUBCONVERTER_VERSION:-$DEFAULT_SUBCONVERTER_VERSION}"
|
||||
if [ -n "${actual:-}" ] && [ "$actual" != "$expected" ]; then
|
||||
error "离线资源包 subconverter 版本不匹配:资源包=$actual,目标=$expected"
|
||||
failed="true"
|
||||
fi
|
||||
|
||||
kernel="$(runtime_kernel_type)"
|
||||
case "$kernel" in
|
||||
mihomo)
|
||||
actual="$(read_bundled_asset_manifest_value "MIHOMO_VERSION" 2>/dev/null || true)"
|
||||
expected="${MIHOMO_VERSION:-$DEFAULT_MIHOMO_VERSION}"
|
||||
;;
|
||||
clash)
|
||||
actual="$(read_bundled_asset_manifest_value "CLASH_VERSION" 2>/dev/null || true)"
|
||||
expected="${CLASH_VERSION:-$DEFAULT_CLASH_VERSION}"
|
||||
;;
|
||||
*)
|
||||
actual=""
|
||||
expected=""
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -n "${actual:-}" ] && [ "$actual" != "$expected" ]; then
|
||||
error "离线资源包 $kernel 版本不匹配:资源包=$actual,目标=$expected"
|
||||
failed="true"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "${checksums:-}" ] && [ -f "$checksums" ]; then
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
if ! (cd "$metadata_root" && sha256sum -c "$(basename "$checksums")" >/dev/null); then
|
||||
error "离线资源包 SHA256 校验失败:$checksums"
|
||||
failed="true"
|
||||
fi
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
if ! (cd "$metadata_root" && shasum -a 256 -c "$(basename "$checksums")" >/dev/null); then
|
||||
error "离线资源包 SHA256 校验失败:$checksums"
|
||||
failed="true"
|
||||
fi
|
||||
else
|
||||
warn "系统缺少 sha256sum/shasum,已跳过离线资源包完整性校验"
|
||||
fi
|
||||
fi
|
||||
|
||||
[ "$failed" = "false" ]
|
||||
}
|
||||
|
||||
offline_asset_missing_text() {
|
||||
local category="$1"
|
||||
local version="$2"
|
||||
local file="$3"
|
||||
local label="$4"
|
||||
|
||||
if [ -n "${CLASH_BUNDLED_ASSET_DIR:-}" ]; then
|
||||
printf '%s:%s/%s/%s(版本 %s)' \
|
||||
"$label" "${CLASH_BUNDLED_ASSET_DIR%/}" "$category" "$file" "$version"
|
||||
return 0
|
||||
fi
|
||||
|
||||
case "$category" in
|
||||
geo)
|
||||
printf '%s:resources/geo/%s' "$label" "$file"
|
||||
;;
|
||||
*)
|
||||
printf '%s:resources/bin/%s/%s(版本 %s)' "$label" "$category" "$file" "$version"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
preflight_offline_assets() {
|
||||
offline_mode_enabled || return 0
|
||||
|
||||
local arch kernel version file item path
|
||||
local missing=()
|
||||
local candidate_found="false"
|
||||
|
||||
arch="$(get_arch)"
|
||||
kernel="$(runtime_kernel_type)"
|
||||
|
||||
ui_section "离线资源预检"
|
||||
ui_kv "🧩" "目标架构" "$arch"
|
||||
ui_kv "🚀" "目标内核" "$kernel"
|
||||
|
||||
if ! verify_offline_asset_bundle_metadata; then
|
||||
die_state "离线资源包元数据或完整性校验失败" \
|
||||
"请重新生成与当前架构、版本匹配的资源包"
|
||||
fi
|
||||
|
||||
case "$kernel" in
|
||||
mihomo)
|
||||
version="${MIHOMO_VERSION:-$DEFAULT_MIHOMO_VERSION}"
|
||||
file="$(mihomo_asset_file "$arch" "$version")"
|
||||
if [ ! -x "$(mihomo_bin)" ] \
|
||||
&& ! find_bundled_asset "mihomo" "$version" "$file" >/dev/null 2>&1; then
|
||||
missing+=("$(offline_asset_missing_text "mihomo" "$version" "$file" "Mihomo")")
|
||||
fi
|
||||
;;
|
||||
clash)
|
||||
version="${CLASH_VERSION:-$DEFAULT_CLASH_VERSION}"
|
||||
if [ ! -x "$(clash_bin)" ]; then
|
||||
candidate_found="false"
|
||||
while IFS= read -r file; do
|
||||
[ -n "${file:-}" ] || continue
|
||||
if find_bundled_asset "clash" "$version" "$file" >/dev/null 2>&1; then
|
||||
candidate_found="true"
|
||||
break
|
||||
fi
|
||||
done <<EOF
|
||||
$(clash_asset_candidates "$arch" "$version")
|
||||
EOF
|
||||
if [ "$candidate_found" != "true" ]; then
|
||||
file="$(clash_asset_candidates "$arch" "$version" | head -n 1)"
|
||||
missing+=("$(offline_asset_missing_text "clash" "$version" "$file" "Clash")")
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
missing+=("未知内核类型:$kernel")
|
||||
;;
|
||||
esac
|
||||
|
||||
version="${YQ_VERSION:-$DEFAULT_YQ_VERSION}"
|
||||
file="$(yq_asset_file "$arch")"
|
||||
if [ ! -x "$(yq_bin)" ] \
|
||||
&& ! find_bundled_asset "yq" "$version" "$file" >/dev/null 2>&1; then
|
||||
missing+=("$(offline_asset_missing_text "yq" "$version" "$file" "yq")")
|
||||
fi
|
||||
|
||||
version="${SUBCONVERTER_VERSION:-$DEFAULT_SUBCONVERTER_VERSION}"
|
||||
file="$(subconverter_asset_file "$arch")"
|
||||
if ! { [ -x "$(subconverter_bin)" ] \
|
||||
&& [ "$(subconverter_version_file_value)" = "$version" ] \
|
||||
&& subconverter_runtime_layout_ready "$(subconverter_home)"; } \
|
||||
&& ! find_bundled_asset "subconverter" "$version" "$file" >/dev/null 2>&1; then
|
||||
missing+=("$(offline_asset_missing_text "subconverter" "$version" "$file" "subconverter")")
|
||||
fi
|
||||
|
||||
if geo_predownload_enabled; then
|
||||
for item in "${GEO_ASSET_DOWNLOADS[@]}"; do
|
||||
path="${item%% *}"
|
||||
file="$(basename "$path")"
|
||||
if [ ! -s "$RUNTIME_DIR/$file" ] \
|
||||
&& ! find_bundled_asset "geo" "latest" "$file" >/dev/null 2>&1; then
|
||||
missing+=("$(offline_asset_missing_text "geo" "latest" "$file" "$file")")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "${#missing[@]}" -gt 0 ]; then
|
||||
error "离线安装缺少以下资源:"
|
||||
printf ' - %s\n' "${missing[@]}" >&2
|
||||
die_state "离线资源预检失败,共缺少 ${#missing[@]} 项" \
|
||||
"在联网设备执行 scripts/prefetch-assets.sh --arch $arch,再把资源包复制到目标主机并解压到项目根目录"
|
||||
fi
|
||||
|
||||
success "离线资源预检通过"
|
||||
}
|
||||
|
||||
resolve_geo_assets() {
|
||||
geo_predownload_enabled || return 0
|
||||
|
||||
[ -n "${PROJECT_DIR:-}" ] || return 0
|
||||
|
||||
@@ -44,12 +290,7 @@ resolve_yq() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
case "$arch" in
|
||||
amd64) file="yq_linux_amd64.tar.gz" ;;
|
||||
arm64) file="yq_linux_arm64.tar.gz" ;;
|
||||
armv7) file="yq_linux_arm.tar.gz" ;;
|
||||
*) die "暂不支持的 yq 架构:$arch" ;;
|
||||
esac
|
||||
file="$(yq_asset_file "$arch")"
|
||||
|
||||
url="https://github.com/mikefarah/yq/releases/download/${version}/${file}"
|
||||
tmp_dir="$(mktemp -d)"
|
||||
@@ -86,12 +327,7 @@ resolve_mihomo() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
case "$arch" in
|
||||
amd64) file="mihomo-linux-amd64-compatible-${version}.gz" ;;
|
||||
arm64) file="mihomo-linux-arm64-${version}.gz" ;;
|
||||
armv7) file="mihomo-linux-armv7-${version}.gz" ;;
|
||||
*) die "暂不支持的 Mihomo 架构:$arch" ;;
|
||||
esac
|
||||
file="$(mihomo_asset_file "$arch" "$version")"
|
||||
|
||||
if [ -n "${custom_url:-}" ]; then
|
||||
url="$custom_url"
|
||||
@@ -109,12 +345,11 @@ resolve_mihomo() {
|
||||
}
|
||||
|
||||
resolve_clash() {
|
||||
local arch version version_no_v url_base tmp_file url downloaded="false"
|
||||
local arch version url_base tmp_file url downloaded="false"
|
||||
local candidates file
|
||||
|
||||
arch="$(get_arch)"
|
||||
version="${CLASH_VERSION:-$DEFAULT_CLASH_VERSION}"
|
||||
version_no_v="${version#v}"
|
||||
url_base="${CLASH_DOWNLOAD_BASE:-https://github.com/WindSpiritSR/clash/releases/download}"
|
||||
|
||||
if [ -x "$(clash_bin)" ] \
|
||||
@@ -123,36 +358,20 @@ resolve_clash() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
case "$arch" in
|
||||
amd64)
|
||||
candidates="
|
||||
clash-linux-amd64-${version}.gz
|
||||
clash-linux-amd64-v${version_no_v}.gz
|
||||
"
|
||||
;;
|
||||
arm64)
|
||||
candidates="
|
||||
clash-linux-arm64-${version}.gz
|
||||
clash-linux-arm64-v${version_no_v}.gz
|
||||
clash-linux-armv8-${version}.gz
|
||||
clash-linux-armv8-v${version_no_v}.gz
|
||||
"
|
||||
;;
|
||||
armv7)
|
||||
candidates="
|
||||
clash-linux-armv7-${version}.gz
|
||||
clash-linux-armv7-v${version_no_v}.gz
|
||||
"
|
||||
;;
|
||||
*)
|
||||
die "暂不支持的 Clash 架构:$arch"
|
||||
;;
|
||||
esac
|
||||
candidates="$(clash_asset_candidates "$arch" "$version")"
|
||||
|
||||
tmp_file="$(mktemp)"
|
||||
rm -f "$tmp_file"
|
||||
|
||||
for file in $candidates; do
|
||||
if copy_bundled_asset "clash" "$version" "$file" "$tmp_file" "clash"; then
|
||||
downloaded="true"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
for file in $candidates; do
|
||||
[ "$downloaded" = "false" ] || break
|
||||
url="${url_base}/${version}/${file}"
|
||||
|
||||
if download_file "$url" "$tmp_file" "clash"; then
|
||||
@@ -273,12 +492,7 @@ resolve_subconverter() {
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$arch" in
|
||||
amd64) file="subconverter_linux64.tar.gz" ;;
|
||||
arm64) file="subconverter_aarch64.tar.gz" ;;
|
||||
armv7) file="subconverter_armv7.tar.gz" ;;
|
||||
*) die "暂不支持的 subconverter 架构:$arch" ;;
|
||||
esac
|
||||
file="$(subconverter_asset_file "$arch")"
|
||||
|
||||
url="https://github.com/asdlokj1qpi233/subconverter/releases/download/${version}/${file}"
|
||||
tmp_dir="$(mktemp -d)"
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
# shellcheck source=scripts/core/runtime.sh
|
||||
source "$PROJECT_DIR/scripts/core/runtime.sh"
|
||||
|
||||
tmp_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmp_dir"' EXIT
|
||||
|
||||
fixture_project="$tmp_dir/project"
|
||||
RUNTIME_DIR="$fixture_project/runtime"
|
||||
RESOURCE_DIR="$fixture_project/resources"
|
||||
BIN_DIR="$RUNTIME_DIR/bin"
|
||||
LOG_DIR="$RUNTIME_DIR/logs"
|
||||
|
||||
mkdir -p \
|
||||
"$RESOURCE_DIR/bin/mihomo" \
|
||||
"$RESOURCE_DIR/bin/yq" \
|
||||
"$RESOURCE_DIR/bin/subconverter" \
|
||||
"$RESOURCE_DIR/geo" \
|
||||
"$BIN_DIR" \
|
||||
"$LOG_DIR"
|
||||
|
||||
export CLASH_TEST_UNAME_M="amd64"
|
||||
export KERNEL_TYPE="mihomo"
|
||||
export CLASH_OFFLINE="true"
|
||||
export CLASH_PREDOWNLOAD_GEO="true"
|
||||
unset CLASH_BUNDLED_ASSET_DIR
|
||||
unset CLASH_BUNDLED_ASSET_ENABLED
|
||||
|
||||
mihomo_version="${MIHOMO_VERSION:-$DEFAULT_MIHOMO_VERSION}"
|
||||
yq_version="${YQ_VERSION:-$DEFAULT_YQ_VERSION}"
|
||||
subconverter_version="${SUBCONVERTER_VERSION:-$DEFAULT_SUBCONVERTER_VERSION}"
|
||||
|
||||
mihomo_file="$(mihomo_asset_file amd64 "$mihomo_version")"
|
||||
yq_file="$(yq_asset_file amd64)"
|
||||
subconverter_file="$(subconverter_asset_file amd64)"
|
||||
|
||||
printf 'mock\n' > "$RESOURCE_DIR/bin/mihomo/$mihomo_file"
|
||||
printf 'mock\n' > "$RESOURCE_DIR/bin/yq/$yq_file"
|
||||
printf 'mock\n' > "$RESOURCE_DIR/bin/subconverter/$subconverter_file"
|
||||
|
||||
for item in "${GEO_ASSET_DOWNLOADS[@]}"; do
|
||||
geo_path="${item%% *}"
|
||||
printf 'mock\n' > "$RESOURCE_DIR/geo/$(basename "$geo_path")"
|
||||
done
|
||||
|
||||
preflight_offline_assets >/dev/null
|
||||
echo "ok - complete offline asset set passes preflight"
|
||||
|
||||
rm -f "$RESOURCE_DIR/bin/mihomo/$mihomo_file"
|
||||
missing_output="$tmp_dir/missing-output"
|
||||
if (preflight_offline_assets) >"$missing_output" 2>&1; then
|
||||
echo "not ok - missing Mihomo asset unexpectedly passed preflight" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -Fq "Mihomo" "$missing_output"; then
|
||||
echo "not ok - missing asset output did not identify Mihomo" >&2
|
||||
cat "$missing_output" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "ok - missing offline asset fails with an actionable name"
|
||||
|
||||
blocked_output="$tmp_dir/blocked-output"
|
||||
if (download_file "https://example.com/file" "$tmp_dir/downloaded" "fixture") >"$blocked_output" 2>&1; then
|
||||
echo "not ok - offline download unexpectedly succeeded" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -e "$tmp_dir/downloaded" ]; then
|
||||
echo "not ok - offline download created an output file" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -Fq "离线模式禁止下载" "$blocked_output"; then
|
||||
echo "not ok - offline download failure was not explicit" >&2
|
||||
cat "$blocked_output" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "ok - offline mode blocks remote fallback before curl"
|
||||
|
||||
parse_install_options user --offline
|
||||
if [ "$INSTALL_REQUESTED_SCOPE" != "user" ] \
|
||||
|| [ "$INSTALL_OFFLINE_REQUESTED" != "true" ]; then
|
||||
echo "not ok - install option parser lost scope or offline flag" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "ok - install options accept scope and --offline together"
|
||||
|
||||
dry_run_output="$tmp_dir/dry-run-output"
|
||||
bash "$PROJECT_DIR/scripts/prefetch-assets.sh" \
|
||||
--arch arm64 \
|
||||
--kernel mihomo \
|
||||
--dry-run >"$dry_run_output"
|
||||
|
||||
if ! grep -Fq "mihomo-linux-arm64-" "$dry_run_output" \
|
||||
|| ! grep -Fq "subconverter_aarch64.tar.gz" "$dry_run_output" \
|
||||
|| ! grep -Fq "未生成资源包" "$dry_run_output"; then
|
||||
echo "not ok - prefetch dry run did not describe the arm64 bundle" >&2
|
||||
cat "$dry_run_output" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "ok - prefetch dry run resolves target architecture without downloading"
|
||||
@@ -0,0 +1,227 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
# shellcheck source=scripts/core/runtime.sh
|
||||
source "$PROJECT_DIR/scripts/core/runtime.sh"
|
||||
|
||||
prefetch_usage() {
|
||||
cat <<'EOF'
|
||||
用法:
|
||||
bash scripts/prefetch-assets.sh [选项]
|
||||
|
||||
选项:
|
||||
--arch amd64|arm64|armv7 目标主机架构;默认使用当前主机架构
|
||||
--kernel mihomo|clash 要打包的代理内核;默认读取 .env 或使用 mihomo
|
||||
--output FILE 输出文件;默认 clash-assets-<kernel>-<arch>.tar.gz
|
||||
--no-geo 不包含安装期 GEO 资源
|
||||
--dry-run 只显示下载计划,不下载或生成压缩包
|
||||
-h, --help 显示帮助
|
||||
|
||||
资源包复制到目标主机后,在项目根目录执行:
|
||||
tar -xzf clash-assets-<kernel>-<arch>.tar.gz
|
||||
bash install.sh --offline
|
||||
EOF
|
||||
}
|
||||
|
||||
normalize_prefetch_arch() {
|
||||
case "$1" in
|
||||
x86_64|amd64) echo "amd64" ;;
|
||||
aarch64|arm64) echo "arm64" ;;
|
||||
armv7l|armv7) echo "armv7" ;;
|
||||
*) die_usage "不支持的目标架构:$1" "可选值:amd64、arm64、armv7" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
prefetch_sha256_line() {
|
||||
local file="$1"
|
||||
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "$file"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if command -v shasum >/dev/null 2>&1; then
|
||||
shasum -a 256 "$file"
|
||||
return 0
|
||||
fi
|
||||
|
||||
die "生成资源包需要 sha256sum 或 shasum"
|
||||
}
|
||||
|
||||
prefetch_download() {
|
||||
local url="$1"
|
||||
local out="$2"
|
||||
local label="$3"
|
||||
|
||||
mkdir -p "$(dirname "$out")"
|
||||
download_file "$url" "$out" "$label"
|
||||
}
|
||||
|
||||
target_arch=""
|
||||
target_kernel=""
|
||||
output_file=""
|
||||
include_geo="true"
|
||||
dry_run="false"
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--arch)
|
||||
[ "$#" -ge 2 ] || die_usage "--arch 缺少参数" "可选值:amd64、arm64、armv7"
|
||||
target_arch="$2"
|
||||
shift 2
|
||||
;;
|
||||
--kernel)
|
||||
[ "$#" -ge 2 ] || die_usage "--kernel 缺少参数" "可选值:mihomo、clash"
|
||||
target_kernel="$2"
|
||||
shift 2
|
||||
;;
|
||||
--output)
|
||||
[ "$#" -ge 2 ] || die_usage "--output 缺少文件路径" "例如:--output /tmp/clash-assets-amd64.tar.gz"
|
||||
output_file="$2"
|
||||
shift 2
|
||||
;;
|
||||
--no-geo)
|
||||
include_geo="false"
|
||||
shift
|
||||
;;
|
||||
--dry-run)
|
||||
dry_run="true"
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
prefetch_usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
die_usage "未知参数:$1" "执行 bash scripts/prefetch-assets.sh --help 查看用法"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
init_project_context "$PROJECT_DIR"
|
||||
load_env_if_exists
|
||||
|
||||
target_arch="$(normalize_prefetch_arch "${target_arch:-$(get_arch)}")"
|
||||
target_kernel="$(normalize_kernel_type "${target_kernel:-${KERNEL_TYPE:-mihomo}}")"
|
||||
|
||||
case "$target_kernel" in
|
||||
mihomo|clash) ;;
|
||||
*) die_usage "不支持的目标内核:$target_kernel" "可选值:mihomo、clash" ;;
|
||||
esac
|
||||
|
||||
export CLASH_TEST_UNAME_M="$target_arch"
|
||||
export CLASH_OFFLINE="false"
|
||||
|
||||
mihomo_version="${MIHOMO_VERSION:-$DEFAULT_MIHOMO_VERSION}"
|
||||
clash_version="${CLASH_VERSION:-$DEFAULT_CLASH_VERSION}"
|
||||
yq_version="${YQ_VERSION:-$DEFAULT_YQ_VERSION}"
|
||||
subconverter_version="${SUBCONVERTER_VERSION:-$DEFAULT_SUBCONVERTER_VERSION}"
|
||||
|
||||
yq_file="$(yq_asset_file "$target_arch")"
|
||||
subconverter_file="$(subconverter_asset_file "$target_arch")"
|
||||
yq_url="https://github.com/mikefarah/yq/releases/download/${yq_version}/${yq_file}"
|
||||
subconverter_url="https://github.com/asdlokj1qpi233/subconverter/releases/download/${subconverter_version}/${subconverter_file}"
|
||||
|
||||
case "$target_kernel" in
|
||||
mihomo)
|
||||
kernel_file="$(mihomo_asset_file "$target_arch" "$mihomo_version")"
|
||||
if [ -n "${MIHOMO_DOWNLOAD_URL:-}" ]; then
|
||||
kernel_url="$MIHOMO_DOWNLOAD_URL"
|
||||
else
|
||||
kernel_url="${MIHOMO_DOWNLOAD_BASE:-https://github.com/MetaCubeX/mihomo/releases/download}"
|
||||
kernel_url="${kernel_url%/}/${mihomo_version}/${kernel_file}"
|
||||
fi
|
||||
;;
|
||||
clash)
|
||||
kernel_file="$(clash_asset_candidates "$target_arch" "$clash_version" | head -n 1)"
|
||||
kernel_url="${CLASH_DOWNLOAD_BASE:-https://github.com/WindSpiritSR/clash/releases/download}"
|
||||
kernel_url="${kernel_url%/}/${clash_version}/${kernel_file}"
|
||||
;;
|
||||
esac
|
||||
|
||||
ui_section "资源包计划"
|
||||
ui_kv "🧩" "目标架构" "$target_arch"
|
||||
ui_kv "🚀" "目标内核" "$target_kernel"
|
||||
printf ' - %s\n' "$kernel_url"
|
||||
printf ' - %s\n' "$yq_url"
|
||||
printf ' - %s\n' "$subconverter_url"
|
||||
|
||||
if [ "$include_geo" = "true" ]; then
|
||||
for item in "${GEO_ASSET_DOWNLOADS[@]}"; do
|
||||
printf ' - %s\n' "${item#* }"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "$dry_run" = "true" ]; then
|
||||
success "仅显示下载计划,未生成资源包"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
command -v curl >/dev/null 2>&1 || die "当前系统缺少 curl"
|
||||
command -v tar >/dev/null 2>&1 || die "当前系统缺少 tar"
|
||||
|
||||
stage_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "$stage_dir"' EXIT
|
||||
|
||||
RESOURCE_DIR="$stage_dir/resources"
|
||||
RUNTIME_DIR="$stage_dir/runtime"
|
||||
BIN_DIR="$RUNTIME_DIR/bin"
|
||||
LOG_DIR="$RUNTIME_DIR/logs"
|
||||
mkdir -p "$RESOURCE_DIR/bin" "$RESOURCE_DIR/geo" "$RUNTIME_DIR"
|
||||
|
||||
prefetch_download "$kernel_url" "$RESOURCE_DIR/bin/$target_kernel/$kernel_file" "$target_kernel"
|
||||
prefetch_download "$yq_url" "$RESOURCE_DIR/bin/yq/$yq_file" "yq"
|
||||
prefetch_download \
|
||||
"$subconverter_url" \
|
||||
"$RESOURCE_DIR/bin/subconverter/$subconverter_file" \
|
||||
"subconverter"
|
||||
|
||||
if [ "$include_geo" = "true" ]; then
|
||||
for item in "${GEO_ASSET_DOWNLOADS[@]}"; do
|
||||
geo_path="${item%% *}"
|
||||
geo_url="${item#* }"
|
||||
geo_file="$(basename "$geo_path")"
|
||||
prefetch_download "$geo_url" "$RESOURCE_DIR/geo/$geo_file" "$geo_file"
|
||||
done
|
||||
fi
|
||||
|
||||
source_commit="$(git -C "$PROJECT_DIR" rev-parse --verify HEAD 2>/dev/null || echo unknown)"
|
||||
cat > "$RESOURCE_DIR/asset-manifest.env" <<EOF
|
||||
BUNDLE_FORMAT="1"
|
||||
BUNDLE_ARCH="$target_arch"
|
||||
KERNEL_TYPE="$target_kernel"
|
||||
MIHOMO_VERSION="$mihomo_version"
|
||||
CLASH_VERSION="$clash_version"
|
||||
YQ_VERSION="$yq_version"
|
||||
SUBCONVERTER_VERSION="$subconverter_version"
|
||||
GEO_INCLUDED="$include_geo"
|
||||
SOURCE_COMMIT="$source_commit"
|
||||
GENERATED_AT="$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
|
||||
EOF
|
||||
|
||||
(
|
||||
cd "$RESOURCE_DIR"
|
||||
while IFS= read -r asset_file; do
|
||||
prefetch_sha256_line "$asset_file"
|
||||
done < <(
|
||||
find bin geo -type f -print
|
||||
printf '%s\n' "asset-manifest.env"
|
||||
) | LC_ALL=C sort -k2
|
||||
) > "$RESOURCE_DIR/SHA256SUMS"
|
||||
|
||||
if [ -z "${output_file:-}" ]; then
|
||||
output_file="$PWD/clash-assets-${target_kernel}-${target_arch}.tar.gz"
|
||||
else
|
||||
output_dir="$(dirname "$output_file")"
|
||||
output_name="$(basename "$output_file")"
|
||||
mkdir -p "$output_dir"
|
||||
output_file="$(cd "$output_dir" && pwd)/$output_name"
|
||||
fi
|
||||
|
||||
tar -czf "$output_file" -C "$stage_dir" resources
|
||||
|
||||
success "资源包已生成:$output_file"
|
||||
ui_next "复制到目标主机的项目目录,解压后执行:bash install.sh --offline"
|
||||
Reference in New Issue
Block a user