UV-苹果系统M系列芯片安装(可用于Python多环境管理的工具)

独立安装器:

  • macOS/Linux:curl -LsSf https://astral.sh/uv/install.sh | sh
  • Windows:powershell -ExecutionPolicy ByPass -c “irm https://astral.sh/uv/install.ps1 | iex”
  • 通过 PyPI:
  • pip install uv 或 pipx install uv
  • 自我更新:通过独立安装器安装后,可使用 uv self update 更新到最新版本。

这里着重介绍一下因墙太高或者网络问题导致使用 curl -LsSf https://astral.sh/uv/install.sh | sh命令安装失败的方式:
手动下载版本,然后将install.sh与下载的东西放在同一目录下,执行sudo sh install.sh即可,效果和使用 curl -LsSf https://astral.sh/uv/install.sh | sh命令一样,也可以自动更新,这也是最切合官方的方式。
当前最新版本是v0.8.22,其他版本只改一下脚本中的名称即可。

执行过程中会有apple不信任提示,

在这里插入图片描述

解决方法是点完成后到系统设置中-隐私与安全性
在这里插入图片描述
点仍要打开。
shell脚本会继续执行。

附:install.sh脚本不让传,直接放代码吧
uv的下载链接传到资源中了。
后面有时间补一个阿里云盘的下载链接

#!/bin/sh
# shellcheck shell=dash
# shellcheck disable=SC2039  # local is non-POSIX
#
# Licensed under the MIT license
# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
# This runs on Unix shells like bash/dash/ksh/zsh. It uses the common `local`
# extension. Note: Most shells limit `local` to 1 var per line, contra bash.
# Some versions of ksh have no `local` keyword. Alias it to `typeset`, but
# beware this makes variables global with f()-style function syntax in ksh93.
# mksh has this alias by default.
has_local() {
    # shellcheck disable=SC2034  # deliberately unused
    local _has_local
}
has_local 2>/dev/null || alias local=typeset
set -u
APP_NAME="uv"
APP_VERSION="0.8.22"
# Look for GitHub Enterprise-style base URL first (保留原逻辑,未修改)
if [ -n "${UV_INSTALLER_GHE_BASE_URL:-}" ]; then
    INSTALLER_BASE_URL="$UV_INSTALLER_GHE_BASE_URL"
else
    INSTALLER_BASE_URL="${UV_INSTALLER_GITHUB_BASE_URL:-https://github.com}"
fi
if [ -n "${UV_DOWNLOAD_URL:-}" ]; then
    ARTIFACT_DOWNLOAD_URL="$UV_DOWNLOAD_URL"
elif [ -n "${INSTALLER_DOWNLOAD_URL:-}" ]; then
    ARTIFACT_DOWNLOAD_URL="$INSTALLER_DOWNLOAD_URL"
else
    ARTIFACT_DOWNLOAD_URL="${INSTALLER_BASE_URL}/astral-sh/uv/releases/download/0.8.22"
fi
if [ -n "${UV_PRINT_VERBOSE:-}" ]; then
    PRINT_VERBOSE="$UV_PRINT_VERBOSE"
else
    PRINT_VERBOSE=${INSTALLER_PRINT_VERBOSE:-0}
fi
if [ -n "${UV_PRINT_QUIET:-}" ]; then
    PRINT_QUIET="$UV_PRINT_QUIET"
else
    PRINT_QUIET=${INSTALLER_PRINT_QUIET:-0}
fi
if [ -n "${UV_NO_MODIFY_PATH:-}" ]; then
    NO_MODIFY_PATH="$UV_NO_MODIFY_PATH"
else
    NO_MODIFY_PATH=${INSTALLER_NO_MODIFY_PATH:-0}
fi
if [ "${UV_DISABLE_UPDATE:-0}" = "1" ]; then
    INSTALL_UPDATER=0
else
    INSTALL_UPDATER=1
fi
UNMANAGED_INSTALL="${UV_UNMANAGED_INSTALL:-}"
if [ -n "${UNMANAGED_INSTALL}" ]; then
    NO_MODIFY_PATH=1
    INSTALL_UPDATER=0
fi
AUTH_TOKEN="${UV_GITHUB_TOKEN:-}"
read -r RECEIPT <<EORECEIPT
{"binaries":["CARGO_DIST_BINS"],"binary_aliases":{},"cdylibs":["CARGO_DIST_DYLIBS"],"cstaticlibs":["CARGO_DIST_STATICLIBS"],"install_layout":"unspecified","install_prefix":"AXO_INSTALL_PREFIX","modify_path":true,"provider":{"source":"cargo-dist","version":"0.30.0"},"source":{"app_name":"uv","name":"uv","owner":"astral-sh","release_type":"github"},"version":"0.8.22"}
EORECEIPT
# Some Linux distributions don't set HOME (保留原逻辑,未修改)
# https://github.com/astral-sh/uv/issues/6965#issuecomment-2915796022
get_home() {
    if [ -n "${HOME:-}" ]; then
        echo "$HOME"
    elif [ -n "${USER:-}" ]; then
        getent passwd "$USER" | cut -d: -f6
    else
        getent passwd "$(id -un)" | cut -d: -f6
    fi
}
# The HOME reference to show in user output. If `$HOME` isn't set, we show the absolute path instead.
get_home_expression() {
    if [ -n "${HOME:-}" ]; then
        # shellcheck disable=SC2016
        echo '$HOME'
    elif [ -n "${USER:-}" ]; then
        getent passwd "$USER" | cut -d: -f6
    else
        getent passwd "$(id -un)" | cut -d: -f6
    fi
}
INFERRED_HOME=$(get_home)
# shellcheck disable=SC2034
INFERRED_HOME_EXPRESSION=$(get_home_expression)
RECEIPT_HOME="${XDG_CONFIG_HOME:-$INFERRED_HOME/.config}/uv"
usage() {
    # print help (保留原逻辑,未修改)
    cat <<EOF
uv-installer.sh (本地安装版)
The installer for uv 0.8.22 (适配 M 系列芯片 macOS)
本脚本已修改为使用本地压缩包:uv-aarch64-apple-darwin.tar.gz
请确保以下文件在同一目录:
    - install.sh (本脚本)
    - uv-aarch64-apple-darwin.tar.gz (本地下载的压缩包)
安装路径优先级:
    \$XDG_BIN_HOME → \$XDG_DATA_HOME/../bin → \$HOME/.local/bin
USAGE:
    ./install.sh [OPTIONS]
OPTIONS:
    -v, --verbose
            显示详细安装日志
    -q, --quiet
            关闭进度输出
        --no-modify-path
            不自动配置 PATH 环境变量(已废弃,建议用 UV_NO_MODIFY_PATH=1)
    -h, --help
            显示帮助信息
EOF
}
download_binary_and_run_installer() {
    downloader --check
    need_cmd uname
    need_cmd mktemp
    need_cmd chmod
    need_cmd mkdir
    need_cmd rm
    need_cmd tar
    need_cmd grep
    need_cmd cat
    # 处理命令行参数(保留原逻辑,未修改)
    for arg in "$@"; do
        case "$arg" in
            --help)
                usage
                exit 0
                ;;
            --quiet)
                PRINT_QUIET=1
                ;;
            --verbose)
                PRINT_VERBOSE=1
                ;;
            --no-modify-path)
                say "--no-modify-path has been deprecated; please set UV_NO_MODIFY_PATH=1 in the environment"
                NO_MODIFY_PATH=1
                ;;
            *)
                OPTIND=1
                if [ "${arg%%--*}" = "" ]; then
                    err "unknown option $arg"
                fi
                while getopts :hvq sub_arg "$arg"; do
                    case "$sub_arg" in
                        h)
                            usage
                            exit 0
                            ;;
                        v)
                            PRINT_VERBOSE=1
                            ;;
                        q)
                            PRINT_QUIET=1
                            ;;
                        *)
                            err "unknown option -$OPTARG"
                            ;;
                        esac
                done
                ;;
        esac
    done

    ###########################################################################
    # 关键修改1:强制指定架构(M系列芯片macOS → aarch64-apple-darwin)
    ###########################################################################
    local _true_arch="aarch64-apple-darwin"  # 固定架构,避免自动检测错误
    assert_nz "$_true_arch" "arch"
    local _cur_arch="$_true_arch"
    # 固定压缩包名称(与本地下载的文件名完全一致)
    local _artifact_name="uv-aarch64-apple-darwin.tar.gz"

    ###########################################################################
    # 关键修改2:解析压缩包信息(与本地文件匹配,无需修改)
    ###########################################################################
    local _bins
    local _zip_ext
    local _arch
    local _checksum_style
    local _checksum_value
    case "$_artifact_name" in 
        "uv-aarch64-apple-darwin.tar.gz")
            _arch="aarch64-apple-darwin"
            _zip_ext=".tar.gz"
            _bins="uv uvx"
            _bins_js_array='"uv","uvx"'
            _libs=""
            _libs_js_array=""
            _staticlibs=""
            _staticlibs_js_array=""
            _updater_name=""
            _updater_bin=""
            ;;
        *)
            err "内部错误:指定的压缩包名称不匹配!请确认本地文件是 uv-aarch64-apple-darwin.tar.gz"
            ;;
    esac
    # 替换收据中的占位符(保留原逻辑,未修改)
    RECEIPT="$(echo "$RECEIPT" | sed s/'"CARGO_DIST_BINS"'/"$_bins_js_array"/)"
    RECEIPT="$(echo "$RECEIPT" | sed s/'"CARGO_DIST_DYLIBS"'/"$_libs_js_array"/)"
    RECEIPT="$(echo "$RECEIPT" | sed s/'"CARGO_DIST_STATICLIBS"'/"$_staticlibs_js_array"/)"

    ###########################################################################
    # 关键修改3:使用本地压缩包,跳过远程下载(核心修改部分)
    ###########################################################################
    # 1. 定义本地压缩包路径(与install.sh同目录,自动获取脚本所在目录)
    local _local_archive="$(dirname "$0")/uv-aarch64-apple-darwin.tar.gz"
    # 检查本地文件是否存在
    if [ ! -f "$_local_archive" ]; then
        err "本地压缩包不存在!请执行以下操作:
1. 确认下载的文件名为:uv-aarch64-apple-darwin.tar.gz
2. 将该文件与 install.sh 放在同一目录
3. 重新运行本脚本"
    fi
    # 2. 创建临时解压目录(与原逻辑一致)
    local _dir
    _dir="$(ensure mktemp -d)" || return 1
    local _file="$_dir/input$_zip_ext"  # 临时文件路径,保持原解压逻辑
    say "使用本地压缩包安装 $APP_NAME $APP_VERSION (架构: $_arch)" 1>&2
    say_verbose "  本地文件路径: $_local_archive" 1>&2
    say_verbose "  临时解压路径: $_file" 1>&2
    ensure mkdir -p "$_dir"
    # 3. 复制本地压缩包到临时目录(替代原远程下载)
    if ! cp "$_local_archive" "$_file"; then
        err "复制本地压缩包失败!可能原因:
- 文件权限不足(尝试用 sudo ./install.sh 执行)
- 本地文件损坏(重新下载 uv-aarch64-apple-darwin.tar.gz)"
        exit 1
    fi
    # 跳过校验和验证(本地文件已手动下载,无需校验)
    say "跳过校验和验证(本地文件模式)"

    ###########################################################################
    # 以下为原脚本逻辑(未修改):解压、安装、配置环境变量
    ###########################################################################
    # ...and then the updater, if it exists (无更新器,跳过)
    if [ -n "$_updater_name" ] && [ "$INSTALL_UPDATER" = "1" ]; then
        local _updater_url="$ARTIFACT_DOWNLOAD_URL/$_updater_name"
        local _updater_file="$_dir/$APP_NAME-update"
        if ! downloader "$_updater_url" "$_updater_file"; then
          say "failed to download $_updater_url"
          say "this may be a standard network error, but it may also indicate"
          say "that $APP_NAME's release process is not working. When in doubt"
          say "please feel free to open an issue!"
          exit 1
        fi
        _bins="$_bins $APP_NAME-update"
    fi
    # 解压压缩包
    case "$_zip_ext" in
        ".zip")
            ensure unzip -q "$_file" -d "$_dir"
            ;;
        ".tar."*)
            ensure tar xf "$_file" --strip-components 1 -C "$_dir"
            ;;
        *)
            err "unknown archive format: $_zip_ext"
            ;;
    esac
    # 执行安装
    install "$_dir" "$_bins" "$_libs" "$_staticlibs" "$_arch" "$@"
    local _retval=$?
    if [ "$_retval" != 0 ]; then
        return "$_retval"
    fi
    # 清理临时目录
    ignore rm -rf "$_dir"
    # 生成安装收据
    if [ "$INSTALL_UPDATER" = "1" ]; then
        if ! mkdir -p "$RECEIPT_HOME"; then
            err "unable to create receipt directory at $RECEIPT_HOME"
        else
            echo "$RECEIPT" > "$RECEIPT_HOME/$APP_NAME-receipt.json"
            local _retval=$?
        fi
    else
        local _retval=0
    fi
    return "$_retval"
}
# Replaces $HOME with the variable name for display to the user (保留原逻辑)
replace_home() {
    local _str="$1"
    if [ -n "${HOME:-}" ]; then
        echo "$_str" | sed "s,$HOME,\$HOME,"
    else
        echo "$_str"
    fi
}
json_binary_aliases() {
    local _arch="$1"
    case "$_arch" in 
    "aarch64-apple-darwin")
        echo '{}'
        ;;
    "aarch64-pc-windows-gnu")
        echo '{}'
        ;;
    "aarch64-unknown-linux-gnu")
        echo '{}'
        ;;
    "aarch64-unknown-linux-musl-dynamic")
        echo '{}'
        ;;
    "aarch64-unknown-linux-musl-static")
        echo '{}'
        ;;
    "arm-unknown-linux-gnueabihf")
        echo '{}'
        ;;
    "arm-unknown-linux-musl-dynamiceabihf")
        echo '{}'
        ;;
    "arm-unknown-linux-musl-staticeabihf")
        echo '{}'
        ;;
    "armv7-unknown-linux-gnueabihf")
        echo '{}'
        ;;
    "armv7-unknown-linux-musl-dynamiceabihf")
        echo '{}'
        ;;
    "armv7-unknown-linux-musl-staticeabihf")
        echo '{}'
        ;;
    "i686-pc-windows-gnu")
        echo '{}'
        ;;
    "i686-unknown-linux-gnu")
        echo '{}'
        ;;
    "i686-unknown-linux-musl-dynamic")
        echo '{}'
        ;;
    "i686-unknown-linux-musl-static")
        echo '{}'
        ;;
    "powerpc64-unknown-linux-gnu")
        echo '{}'
        ;;
    "powerpc64le-unknown-linux-gnu")
        echo '{}'
        ;;
    "riscv64gc-unknown-linux-gnu")
        echo '{}'
        ;;
    "s390x-unknown-linux-gnu")
        echo '{}'
        ;;
    "x86_64-apple-darwin")
        echo '{}'
        ;;
    "x86_64-pc-windows-gnu")
        echo '{}'
        ;;
    "x86_64-unknown-linux-gnu")
        echo '{}'
        ;;
    "x86_64-unknown-linux-musl-dynamic")
        echo '{}'
        ;;
    "x86_64-unknown-linux-musl-static")
        echo '{}'
        ;;
    *)
        echo '{}'
        ;;
    esac
}
aliases_for_binary() {
    local _bin="$1"
    local _arch="$2"
    case "$_arch" in 
    "aarch64-apple-darwin")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "aarch64-pc-windows-gnu")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "aarch64-unknown-linux-gnu")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "aarch64-unknown-linux-musl-dynamic")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "aarch64-unknown-linux-musl-static")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "arm-unknown-linux-gnueabihf")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "arm-unknown-linux-musl-dynamiceabihf")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "arm-unknown-linux-musl-staticeabihf")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "armv7-unknown-linux-gnueabihf")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "armv7-unknown-linux-musl-dynamiceabihf")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "armv7-unknown-linux-musl-staticeabihf")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "i686-pc-windows-gnu")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "i686-unknown-linux-gnu")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "i686-unknown-linux-musl-dynamic")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "i686-unknown-linux-musl-static")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "powerpc64-unknown-linux-gnu")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "powerpc64le-unknown-linux-gnu")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "riscv64gc-unknown-linux-gnu")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "s390x-unknown-linux-gnu")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "x86_64-apple-darwin")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "x86_64-pc-windows-gnu")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "x86_64-unknown-linux-gnu")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "x86_64-unknown-linux-musl-dynamic")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    "x86_64-unknown-linux-musl-static")
        case "$_bin" in
        *)
            echo ""
            ;;
        esac
        ;;
    *)
        echo ""
        ;;
    esac
}
select_archive_for_arch() {
    local _true_arch="$1"
    local _archive
    case "$_true_arch" in 
        "aarch64-apple-darwin")
            _archive="uv-aarch64-apple-darwin.tar.gz"
            if [ -n "$_archive" ]; then
                echo "$_archive"
                return 0
            fi
            _archive="uv-x86_64-apple-darwin.tar.gz"
            if [ -n "$_archive" ]; then
                echo "$_archive"
                return 0
            fi
            ;;
        *)
            err "there isn't a download for your platform $_true_arch"
            ;;
    esac
    err "no compatible downloads were found for your platform $_true_arch"
}
check_glibc() {
    local _min_glibc_major="$1"
    local _min_glibc_series="$2"
    _local_glibc="$(ldd --version | awk -F' ' '{ if (FNR<=1) print $NF }')"
    if [ "$(echo "${_local_glibc}" | awk -F. '{ print $1 }')" = "$_min_glibc_major" ] && [ "$(echo "${_local_glibc}" | awk -F. '{ print $2 }')" -ge "$_min_glibc_series" ]; then
        return 0
    else
        say "System glibc version (\`${_local_glibc}') is too old; checking alternatives" >&2
        return 1
    fi
}
# 安装核心逻辑(保留原脚本,未修改)
install() {
    local _install_dir
    local _lib_install_dir
    local _receipt_install_dir
    local _env_script_path
    local _install_dir_expr
    local _env_script_path_expr
    local _force_install_dir
    local _install_layout="unspecified"
    local _shadowed_bins=""
    if [ -n "${UV_INSTALL_DIR:-}" ]; then
        _force_install_dir="$UV_INSTALL_DIR"
        _install_layout="flat"
    elif [ -n "${CARGO_DIST_FORCE_INSTALL_DIR:-}" ]; then
        _force_install_dir="$CARGO_DIST_FORCE_INSTALL_DIR"
        _install_layout="flat"
    elif [ -n "$UNMANAGED_INSTALL" ]; then
        _force_install_dir="$UNMANAGED_INSTALL"
        _install_layout="flat"
    fi
    if [ -n "${_force_install_dir:-}" ]; then
        if [ "$_install_layout" = "flat" ]; then
            if [ "$_force_install_dir" = "${CARGO_HOME:-${INFERRED_HOME:-}/.cargo}" ]; then
                _install_layout="cargo-home"
            fi
        fi
     fi
    if [ -n "${_force_install_dir:-}" ]; then
        case "$_install_layout" in
            "hierarchical")
                _install_dir="$_force_install_dir/bin"
                _lib_install_dir="$_force_install_dir/lib"
                _receipt_install_dir="$_force_install_dir"
                _env_script_path="$_force_install_dir/env"
                _install_dir_expr="$(replace_home "$_force_install_dir/bin")"
                _env_script_path_expr="$(replace_home "$_force_install_dir/env")"
                ;;
            "cargo-home")
                _install_dir="$_force_install_dir/bin"
                _lib_install_dir="$_force_install_dir/bin"
                _receipt_install_dir="$_force_install_dir"
                _env_script_path="$_force_install_dir/env"
                _install_dir_expr="$(replace_home "$_force_install_dir/bin")"
                _env_script_path_expr="$(replace_home "$_force_install_dir/env")"
                ;;
            "flat")
                _install_dir="$_force_install_dir"
                _lib_install_dir="$_force_install_dir"
                _receipt_install_dir="$_install_dir"
                _env_script_path="$_force_install_dir/env"
                _install_dir_expr="$(replace_home "$_force_install_dir")"
                _env_script_path_expr="$(replace_home "$_force_install_dir/env")"
                ;;
            *)
                err "Unrecognized install layout: $_install_layout"
                ;;
        esac
    fi
    if [ -z "${_install_dir:-}" ]; then
        _install_layout="flat"
        if [ -n "${XDG_BIN_HOME:-}" ]; then
            _install_dir="$XDG_BIN_HOME"
            _lib_install_dir="$_install_dir"
            _receipt_install_dir="$_install_dir"
            _env_script_path="$XDG_BIN_HOME/env"
            _install_dir_expr="$(replace_home "$_install_dir")"
            _env_script_path_expr="$(replace_home "$_env_script_path")"
        fi
    fi
    if [ -z "${_install_dir:-}" ]; then
        _install_layout="flat"
        if [ -n "${XDG_DATA_HOME:-}" ]; then
            _install_dir="$XDG_DATA_HOME/../bin"
            _lib_install_dir="$_install_dir"
            _receipt_install_dir="$_install_dir"
            _env_script_path="$XDG_DATA_HOME/../bin/env"
            _install_dir_expr="$(replace_home "$_install_dir")"
            _env_script_path_expr="$(replace_home "$_env_script_path")"
        fi
    fi
    if [ -z "${_install_dir:-}" ]; then
        _install_layout="flat"
        if [ -n "${INFERRED_HOME:-}" ]; then
            _install_dir="$INFERRED_HOME/.local/bin"
            _lib_install_dir="$INFERRED_HOME/.local/bin"
            _receipt_install_dir="$_install_dir"
            _env_script_path="$INFERRED_HOME/.local/bin/env"
            _install_dir_expr="$INFERRED_HOME_EXPRESSION/.local/bin"
            _env_script_path_expr="$INFERRED_HOME_EXPRESSION/.local/bin/env"
        fi
    fi
    if [ -z "$_install_dir_expr" ]; then
        err "could not find a valid path to install to!"
    fi
    _fish_env_script_path="${_env_script_path}.fish"
    _fish_env_script_path_expr="${_env_script_path_expr}.fish"
    RECEIPT=$(echo "$RECEIPT" | sed "s,AXO_INSTALL_PREFIX,$_receipt_install_dir,")
    RECEIPT=$(echo "$RECEIPT" | sed "s'\"binary_aliases\":{}'\"binary_aliases\":$(json_binary_aliases "$_arch")'")
    RECEIPT=$(echo "$RECEIPT" | sed "s'\"install_layout\":\"unspecified\"'\"install_layout\":\"$_install_layout\"'")
    if [ "$NO_MODIFY_PATH" = "1" ]; then
        RECEIPT=$(echo "$RECEIPT" | sed "s'\"modify_path\":true'\"modify_path\":false'")
    fi
    say "installing to $_install_dir"
    ensure mkdir -p "$_install_dir"
    ensure mkdir -p "$_lib_install_dir"
    local _src_dir="$1"
    local _bins="$2"
    local _libs="$3"
    local _staticlibs="$4"
    local _arch="$5"
    for _bin_name in $_bins; do
        local _bin="$_src_dir/$_bin_name"
        ensure mv "$_bin" "$_install_dir"
        ensure chmod +x "$_install_dir/$_bin_name"
        for _dest in $(aliases_for_binary "$_bin_name" "$_arch"); do
            ln -sf "$_install_dir/$_bin_name" "$_install_dir/$_dest"
        done
        say "  $_bin_name"
    done
    for _lib_name in $_libs; do
        local _lib="$_src_dir/$_lib_name"
        ensure mv "$_lib" "$_lib_install_dir"
        ensure chmod +x "$_lib_install_dir/$_lib_name"
        say "  $_lib_name"
    done
    for _lib_name in $_staticlibs; do
        local _lib="$_src_dir/$_lib_name"
        ensure mv "$_lib" "$_lib_install_dir"
        ensure chmod +x "$_lib_install_dir/$_lib_name"
        say "  $_lib_name"
    done
    say "everything's installed!"
    case :$PATH:
      in *:$_install_dir:*) NO_MODIFY_PATH=1 ;;
         *) ;;
    esac
    if [ "0" = "$NO_MODIFY_PATH" ]; then
        add_install_dir_to_ci_path "$_install_dir"
        add_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" ".profile" "sh"
        exit1=$?
        shotgun_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" ".profile .bashrc .bash_profile .bash_login" "sh"
        exit2=$?
        add_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" ".zshrc .zshenv" "sh"
        exit3=$?
        ensure mkdir -p "$INFERRED_HOME/.config/fish/conf.d"
        exit4=$?
        add_install_dir_to_path "$_install_dir_expr" "$_fish_env_script_path" "$_fish_env_script_path_expr" ".config/fish/conf.d/$APP_NAME.env.fish" "fish"
        exit5=$?
        if [ "${exit1:-0}" = 1 ] || [ "${exit2:-0}" = 1 ] || [ "${exit3:-0}" = 1 ] || [ "${exit4:-0}" = 1 ] || [ "${exit5:-0}" = 1 ]; then
            say ""
            say "To add $_install_dir_expr to your PATH, either restart your shell or run:"
            say ""
            say "    source $_env_script_path_expr (sh, bash, zsh)"
            say "    source $_fish_env_script_path_expr (fish)"
        fi
    fi
    _shadowed_bins="$(check_for_shadowed_bins "$_install_dir" "$_bins")"
    if [ -n "$_shadowed_bins" ]; then
        warn "The following commands are shadowed by other commands in your PATH:$_shadowed_bins"
    fi
}
check_for_shadowed_bins() {
    local _install_dir="$1"
    local _bins="$2"
    local _shadow
    for _bin_name in $_bins; do
        _shadow="$(command -v "$_bin_name")"
        if [ -n "$_shadow" ] && [ "$_shadow" != "$_install_dir/$_bin_name" ]; then
            _shadowed_bins="$_shadowed_bins $_bin_name"
        fi
    done
    echo "$_shadowed_bins"
}
print_home_for_script() {
    local script="$1"
    local _home
    case "$script" in
        .zsh*)
            if [ -n "${ZDOTDIR:-}" ]; then
                _home="$ZDOTDIR"
            else
                _home="$INFERRED_HOME"
            fi
            ;;
        *)
            _home="$INFERRED_HOME"
            ;;
    esac
    echo "$_home"
}
add_install_dir_to_ci_path() {
    local _install_dir="$1"
    if [ -n "${GITHUB_PATH:-}" ]; then
        ensure echo "$_install_dir" >> "$GITHUB_PATH"
    fi
}
add_install_dir_to_path() {
    local _install_dir_expr="$1"
    local _env_script_path="$2"
    local _env_script_path_expr="$3"
    local _rcfiles="$4"
    local _shell="$5"
    if [ -n "${INFERRED_HOME:-}" ]; then
        local _target
        local _home
        for _rcfile_relative in $_rcfiles; do
            _home="$(print_home_for_script "$_rcfile_relative")"
            local _rcfile="$_home/$_rcfile_relative"
            if [ -f "$_rcfile" ]; then
                _target="$_rcfile"
                break
            fi
        done
        if [ -z "${_target:-}" ]; then
            local _rcfile_relative
            _rcfile_relative="$(echo "$_rcfiles" | awk '{ print $1 }')"
            _home="$(print_home_for_script "$_rcfile_relative")"
            _target="$_home/$_rcfile_relative"
        fi
        local _robust_line=". \"$_env_script_path_expr\""
        local _pretty_line="source \"$_env_script_path_expr\""
        if [ ! -f "$_env_script_path" ]; then
            say_verbose "creating $_env_script_path"
            if [ "$_shell" = "sh" ]; then
                write_env_script_sh "$_install_dir_expr" "$_env_script_path"
            else
                write_env_script_fish "$_install_dir_expr" "$_env_script_path"
            fi
        else
            say_verbose "$_env_script_path already exists"
        fi
        if ! grep -F "$_robust_line" "$_target" > /dev/null 2>/dev/null && \
           ! grep -F "$_pretty_line" "$_target" > /dev/null 2>/dev/null
        then
            if [ -f "$_env_script_path" ]; then
                local _line
                if [ "$_shell" = "fish" ]; then
                    _line="$_pretty_line"
                else
                    _line="$_robust_line"
                fi
                say_verbose "adding $_line to $_target"
                ensure echo "" >> "$_target"
                ensure echo "$_line" >> "$_target"
                return 1
            fi
        else
            say_verbose "$_install_dir already on PATH"
        fi
    fi
}
shotgun_install_dir_to_path() {
    local _install_dir_expr="$1"
    local _env_script_path="$2"
    local _env_script_path_expr="$3"
    local _rcfiles="$4"
    local _shell="$5"
    if [ -n "${INFERRED_HOME:-}" ]; then
        local _found=false
        local _home
        for _rcfile_relative in $_rcfiles; do
            _home="$(print_home_for_script "$_rcfile_relative")"
            local _rcfile_abs="$_home/$_rcfile_relative"
            if [ -f "$_rcfile_abs" ]; then
                _found=true
                add_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" "$_rcfile_relative" "$_shell"
            fi
        done
	    if [ "$_found" = false ]; then
            add_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" "$_rcfiles" "$_shell"
        fi
    fi
}
write_env_script_sh() {
    local _install_dir_expr="$1"
    local _env_script_path="$2"
    ensure cat <<EOF > "$_env_script_path"
#!/bin/sh
# add binaries to PATH if they aren't added yet
# affix colons on either side of \$PATH to simplify matching
case ":\${PATH}:" in
    *:"$_install_dir_expr":*)
        ;;
    *)
        # Prepending path in case a system-installed binary needs to be overridden
        export PATH="$_install_dir_expr:\$PATH"
        ;;
esac
EOF
}
write_env_script_fish() {
    local _install_dir_expr="$1"
    local _env_script_path="$2"
    ensure cat <<EOF > "$_env_script_path"
if not contains "$_install_dir_expr" \$PATH
    # Prepending path in case a system-installed binary needs to be overridden
    set -x PATH "$_install_dir_expr" \$PATH
end
EOF
}
get_current_exe() {
    local _current_exe
    if test -L /proc/self/exe ; then
        _current_exe=/proc/self/exe
    else
        warn "Unable to find /proc/self/exe. System architecture detection might be inaccurate."
        if test -n "$SHELL" ; then
            _current_exe=$SHELL
        else
            need_cmd /bin/sh
            _current_exe=/bin/sh
        fi
        warn "Falling back to $_current_exe."
    fi
    echo "$_current_exe"
}
get_bitness() {
    need_cmd head
    local _current_exe=$1
    local _current_exe_head
    _current_exe_head=$(head -c 5 "$_current_exe")
    if [ "$_current_exe_head" = "$(printf '\177ELF\001')" ]; then
        echo 32
    elif [ "$_current_exe_head" = "$(printf '\177ELF\002')" ]; then
        echo 64
    else
        err "unknown platform bitness"
    fi
}
is_host_amd64_elf() {
    local _current_exe=$1
    need_cmd head
    need_cmd tail
    local _current_exe_machine
    _current_exe_machine=$(head -c 19 "$_current_exe" | tail -c 1)
    [ "$_current_exe_machine" = "$(printf '\076')" ]
}
get_endianness() {
    local _current_exe=$1
    local cputype=$2
    local suffix_eb=$3
    local suffix_el=$4
    need_cmd head
    need_cmd tail
    local _current_exe_endianness
    _current_exe_endianness="$(head -c 6 "$_current_exe" | tail -c 1)"
    if [ "$_current_exe_endianness" = "$(printf '\001')" ]; then
        echo "${cputype}${suffix_el}"
    elif [ "$_current_exe_endianness" = "$(printf '\002')" ]; then
        echo "${cputype}${suffix_eb}"
    else
        err "unknown platform endianness"
    fi
}
check_loongarch_uapi() {
    need_cmd base64
    local _tmp
    if ! _tmp="$(ensure mktemp)"; then
        return 1
    fi
    ignore base64 -d > "$_tmp" <<EOF
f0VMRgIBAQAAAAAAAAAAAAIAAgEBAAAAeAAgAAAAAABAAAAAAAAAAAAAAAAAAAAAQQAAAEAAOAAB
AAAAAAAAAAEAAAAFAAAAAAAAAAAAAAAAACAAAAAAAAAAIAAAAAAAJAAAAAAAAAAkAAAAAAAAAAAA
AQAAAAAABCiAAwUAFQAGABUAByCAAwsYggMAACsAC3iBAwAAKwAxen0n
EOF
    ignore chmod u+x "$_tmp"
    if [ ! -x "$_tmp" ]; then
        ignore rm "$_tmp"
        return 1
    fi
    "$_tmp"
    local _retval=$?
    ignore rm "$_tmp"
    return "$_retval"
}
ensure_loongarch_uapi() {
    check_loongarch_uapi
    case $? in
        0)
            return 0
            ;;
        234)
            err 'Your Linux kernel does not provide the ABI required by this distribution.'
            ;;
        *)
            warn "Cannot determine current system's ABI flavor, continuing anyway."
            warn 'Note that the official distribution only works with the upstream kernel ABI.'
            warn 'Installation will fail if your running kernel happens to be incompatible.'
            ;;
    esac
}
get_architecture() {
    local _ostype
    local _cputype
    _ostype="$(uname -s)"
    _cputype="$(uname -m)"
    local _clibtype="gnu"
    local _local_glibc
    if [ "$_ostype" = Linux ]; then
        if [ "$(uname -o)" = Android ]; then
            _ostype=Android
        fi
        if ldd --version 2>&1 | grep -q 'musl'; then
            _clibtype="musl-dynamic"
        else
            _clibtype="gnu"
        fi
    fi
    if [ "$_ostype" = Darwin ]; then
        if [ "$_cputype" = i386 ]; then
            if sysctl hw.optional.x86_64 2> /dev/null || true | grep -q ': 1'; then
                _cputype=x86_64
            fi
        elif [ "$_cputype" = x86_64 ]; then
            if sysctl hw.optional.arm64 2> /dev/null || true | grep -q ': 1'; then
                _cputype=arm64
            fi
        fi
    fi
    if [ "$_ostype" = SunOS ]; then
        if [ "$(/usr/bin/uname -o)" = illumos ]; then
            _ostype=illumos
        fi
        if [ "$_cputype" = i86pc ]; then
            _cputype="$(isainfo -n)"
        fi
    fi
    local _current_exe
    case "$_ostype" in
        Android)
            _ostype=linux-android
            ;;
        Linux)
            _current_exe=$(get_current_exe)
            _ostype=unknown-linux-$_clibtype
            _bitness=$(get_bitness "$_current_exe")
            ;;
        FreeBSD)
            _ostype=unknown-freebsd
            ;;
        NetBSD)
            _ostype=unknown-netbsd
            ;;
        DragonFly)
            _ostype=unknown-dragonfly
            ;;
        Darwin)
            _ostype=apple-darwin
            ;;
        illumos)
            _ostype=unknown-illumos
            ;;
        MINGW* | MSYS* | CYGWIN* | Windows_NT)
            _ostype=pc-windows-gnu
            ;;
        *)
            err "unrecognized OS type: $_ostype"
            ;;
    esac
    case "$_cputype" in
        i386 | i486 | i686 | i786 | x86)
            _cputype=i686
            ;;
        xscale | arm)
            _cputype=arm
            if [ "$_ostype" = "linux-android" ]; then
                _ostype=linux-androideabi
            fi
            ;;
        armv6l)
            _cputype=arm
            if [ "$_ostype" = "linux-android" ]; then
                _ostype=linux-androideabi
            else
                _ostype="${_ostype}eabihf"
            fi
            ;;
        armv7l | armv8l)
            _cputype=armv7
            if [ "$_ostype" = "linux-android" ]; then
                _ostype=linux-androideabi
            else
                _ostype="${_ostype}eabihf"
            fi
            ;;
        aarch64 | arm64)
            _cputype=aarch64
            ;;
        x86_64 | x86-64 | x64 | amd64)
            _cputype=x86_64
            ;;
        mips)
            _cputype=$(get_endianness "$_current_exe" mips '' el)
            ;;
        mips64)
            if [ "$_bitness" -eq 64 ]; then
                _ostype="${_ostype}abi64"
                _cputype=$(get_endianness "$_current_exe" mips64 '' el)
            fi
            ;;
        ppc)
            _cputype=powerpc
            ;;
        ppc64)
            _cputype=powerpc64
            ;;
        ppc64le)
            _cputype=powerpc64le
            ;;
        s390x)
            _cputype=s390x
            ;;
        riscv64)
            _cputype=riscv64gc
            ;;
        loongarch64)
            _cputype=loongarch64
            ensure_loongarch_uapi
            ;;
        *)
            err "unknown CPU type: $_cputype"
    esac
    if [ "${_ostype}" = unknown-linux-gnu ] && [ "${_bitness}" -eq 32 ]; then
        case $_cputype in
            x86_64)
                if is_host_amd64_elf "$_current_exe"; then {
                    err "x32 linux unsupported"
                }; else
                    _cputype=i686
                fi
                ;;
            mips64)
                _cputype=$(get_endianness "$_current_exe" mips '' el)
                ;;
            powerpc64)
                _cputype=powerpc
                ;;
            aarch64)
                _cputype=armv7
                if [ "$_ostype" = "linux-android" ]; then
                    _ostype=linux-androideabi
                else
                    _ostype="${_ostype}eabihf"
                fi
                ;;
            riscv64gc)
                err "riscv64 with 32-bit userland unsupported"
                ;;
        esac
    fi
    if [ "$_ostype" = "unknown-linux-gnueabihf" ] && [ "$_cputype" = armv7 ]; then
        if ! (ensure grep '^Features' /proc/cpuinfo | grep -E -q 'neon|simd') ; then
            _cputype=arm
        fi
    fi
    _arch="${_cputype}-${_ostype}"
    RETVAL="$_arch"
}
say() {
    if [ "0" = "$PRINT_QUIET" ]; then
        echo "$1"
    fi
}
say_verbose() {
    if [ "1" = "$PRINT_VERBOSE" ]; then
        echo "$1"
    fi
}
warn() {
    if [ "0" = "$PRINT_QUIET" ]; then
        local red
        local reset
        red=$(tput setaf 1 2>/dev/null || echo '')
        reset=$(tput sgr0 2>/dev/null || echo '')
        say "${red}WARN${reset}: $1" >&2
    fi
}
err() {
    if [ "0" = "$PRINT_QUIET" ]; then
        local red
        local reset
        red=$(tput setaf 1 2>/dev/null || echo '')
        reset=$(tput sgr0 2>/dev/null || echo '')
        say "${red}ERROR${reset}: $1" >&2
    fi
    exit 1
}
need_cmd() {
    if ! check_cmd "$1"
    then err "need '$1' (command not found)"
    fi
}
check_cmd() {
    command -v "$1" > /dev/null 2>&1
    return $?
}
assert_nz() {
    if [ -z "$1" ]; then err "assert_nz $2"; fi
}
ensure() {
    if ! "$@"; then err "command failed: $*"; fi
}
ignore() {
    "$@"
}
downloader() {
    _snap_curl=0
    if command -v curl > /dev/null 2>&1; then
      _curl_path=$(command -v curl)
      if echo "$_curl_path" | grep "/snap/" > /dev/null 2>&1; then
        _snap_curl=1
      fi
    fi
    if check_cmd curl && [ "$_snap_curl" = "0" ]
    then _dld=curl
    elif check_cmd wget
    then _dld=wget
    elif [ "$_snap_curl" = "1" ]
    then
      say "curl installed with snap cannot be used to install $APP_NAME"
      say "due to missing permissions. Please uninstall it and"
      say "reinstall curl with a different package manager (e.g., apt)."
      say "See https://github.com/boukendesho/curl-snap/issues/1"
      exit 1
    else _dld='curl or wget'
    fi
    if [ "$1" = --check ]
    then need_cmd "$_dld"
    elif [ "$_dld" = curl ]; then
        if [ -n "${AUTH_TOKEN:-}" ]; then
            curl -sSfL --header "Authorization: Bearer ${AUTH_TOKEN}" "$1" -o "$2"
        else
            curl -sSfL "$1" -o "$2"
        fi
    elif [ "$_dld" = wget ]; then
        if [ -n "${AUTH_TOKEN:-}" ]; then
            wget --header "Authorization: Bearer ${AUTH_TOKEN}" "$1" -O "$2"
        else
            wget "$1" -O "$2"
        fi
    else err "Unknown downloader"
    fi
}
verify_checksum() {
    local _file="$1"
    local _checksum_style="$2"
    local _checksum_value="$3"
    local _calculated_checksum
    if [ -z "$_checksum_value" ]; then
        return 0
    fi
    case "$_checksum_style" in
        sha256)
            if ! check_cmd sha256sum; then
                say "skipping sha256 checksum verification (it requires the 'sha256sum' command)"
                return 0
            fi
            _calculated_checksum="$(sha256sum -b "$_file" | awk '{printf $1}')"
            ;;
        sha512)
            if ! check_cmd sha512sum; then
                say "skipping sha512 checksum verification (it requires the 'sha512sum' command)"
                return 0
            fi
            _calculated_checksum="$(sha512sum -b "$_file" | awk '{printf $1}')"
            ;;
        sha3-256)
            if ! check_cmd openssl; then
                say "skipping sha3-256 checksum verification (it requires the 'openssl' command)"
                return 0
            fi
            _calculated_checksum="$(openssl dgst -sha3-256 "$_file" | awk '{printf $NF}')"
            ;;
        sha3-512)
            if ! check_cmd openssl; then
                say "skipping sha3-512 checksum verification (it requires the 'openssl' command)"
                return 0
            fi
            _calculated_checksum="$(openssl dgst -sha3-512 "$_file" | awk '{printf $NF}')"
            ;;
        blake2s)
            if ! check_cmd b2sum; then
                say "skipping blake2s checksum verification (it requires the 'b2sum' command)"
                return 0
            fi
            local _well_known_blake2s_checksum="93314a61f470985a40f8da62df10ba0546dc5216e1d45847bf1dbaa42a0e97af"
            local _test_blake2s
            _test_blake2s="$(printf "can do blake2s" | b2sum -a blake2s | awk '{printf $1}')" || _test_blake2s=""
            if [ "X$_test_blake2s" = "X$_well_known_blake2s_checksum" ]; then
                _calculated_checksum="$(b2sum -a blake2s "$_file" | awk '{printf $1}')" || _calculated_checksum=""
            else
                say "skipping blake2s checksum verification (installed b2sum doesn't support blake2s)"
                return 0
            fi
            ;;
        blake2b)
            if ! check_cmd b2sum; then
                say "skipping blake2b checksum verification (it requires the 'b2sum' command)"
                return 0
            fi
            _calculated_checksum="$(b2sum "$_file" | awk '{printf $1}')"
            ;;
        false)
            ;;
        *)
            say "skipping unknown checksum style: $_checksum_style"
            return 0
            ;;
    esac
    if [ "$_calculated_checksum" != "$_checksum_value" ]; then
        err "checksum mismatch
            want: $_checksum_value
            got:  $_calculated_checksum"
    fi
}
# 执行安装(保留原逻辑)
download_binary_and_run_installer "$@" || exit 1

文档与支持

  • 官方文档:docs.astral.sh/uv
  • 命令行帮助:uv help
  • 由 Astral 开发支持,该公司也是 Python 工具 Ruff 的创作者。

技术架构

  • 基于 Rust 开发,从代码结构看包含多个核心 crate(如 uv-git 处理 Git 仓库交互、uv-resolver 负责依赖解析、uv-distribution 处理分发逻辑等),整体设计注重性能和跨平台兼容性。
  • 支持 Git 仓库作为依赖源,包含对 GitHub 等平台的适配逻辑,以及缓存、校验等机制。
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐