Created
November 8, 2024 04:51
-
-
Save zanieb/76c8b7727f148ecbf09691d0a6604dda to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# shellcheck shell=dash | |
# | |
# 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. | |
if [ "$KSH_VERSION" = 'Version JM 93t+ 2010-03-05' ]; then | |
# The version of ksh93 that ships with many illumos systems does not | |
# support the "local" extension. Print a message rather than fail in | |
# subtle ways later on: | |
echo 'this installer does not work with this ksh93 version; please try bash!' >&2 | |
exit 1 | |
fi | |
set -u | |
APP_NAME="uv" | |
APP_VERSION="0.5.0" | |
# 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 "${INSTALLER_DOWNLOAD_URL:-}" ]; then | |
ARTIFACT_DOWNLOAD_URL="$INSTALLER_DOWNLOAD_URL" | |
else | |
ARTIFACT_DOWNLOAD_URL="${INSTALLER_BASE_URL}/astral-sh/uv/releases/download/0.5.0" | |
fi | |
PRINT_VERBOSE=${INSTALLER_PRINT_VERBOSE:-0} | |
PRINT_QUIET=${INSTALLER_PRINT_QUIET:-0} | |
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 | |
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.25.1"},"source":{"app_name":"uv","name":"uv","owner":"astral-sh","release_type":"github"},"version":"0.5.0"} | |
EORECEIPT | |
RECEIPT_HOME="${HOME}/.config/uv" | |
usage() { | |
# print help (this cat/EOF stuff is a "heredoc" string) | |
cat <<EOF | |
uv-installer.sh | |
The installer for uv 0.5.0 | |
This script detects what platform you're on and fetches an appropriate archive from | |
https://github.com/astral-sh/uv/releases/download/0.5.0 | |
then unpacks the binaries and installs them to the first of the following locations | |
\$XDG_BIN_HOME | |
\$XDG_DATA_HOME/../bin | |
\$HOME/.local/bin | |
It will then add that dir to PATH by adding the appropriate line to your shell profiles. | |
USAGE: | |
uv-installer.sh [OPTIONS] | |
OPTIONS: | |
-v, --verbose | |
Enable verbose output | |
-q, --quiet | |
Disable progress output | |
--no-modify-path | |
Don't configure the PATH environment variable | |
-h, --help | |
Print help information | |
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) | |
# user wants to skip the prompt -- | |
# we don't need /dev/tty | |
PRINT_VERBOSE=1 | |
;; | |
q) | |
# user wants to skip the prompt -- | |
# we don't need /dev/tty | |
PRINT_QUIET=1 | |
;; | |
*) | |
err "unknown option -$OPTARG" | |
;; | |
esac | |
done | |
;; | |
esac | |
done | |
get_architecture || return 1 | |
local _true_arch="$RETVAL" | |
assert_nz "$_true_arch" "arch" | |
local _cur_arch="$_true_arch" | |
# Lookup what archives support this platform | |
local _artifact_name | |
_artifact_name="$(select_archive_for_arch "$_true_arch")" || return 1 | |
local _bins | |
local _zip_ext | |
local _arch | |
# try each archive, checking runtime conditions like libc versions | |
# accepting the first one that matches, as it's the best match | |
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="" | |
;; | |
"uv-aarch64-unknown-linux-gnu.tar.gz") | |
_arch="aarch64-unknown-linux-gnu" | |
_zip_ext=".tar.gz" | |
_bins="uv uvx" | |
_bins_js_array='"uv","uvx"' | |
_libs="" | |
_libs_js_array="" | |
_staticlibs="" | |
_staticlibs_js_array="" | |
_updater_name="" | |
_updater_bin="" | |
;; | |
"uv-aarch64-unknown-linux-musl.tar.gz") | |
_arch="aarch64-unknown-linux-musl-static" | |
_zip_ext=".tar.gz" | |
_bins="uv uvx" | |
_bins_js_array='"uv","uvx"' | |
_libs="" | |
_libs_js_array="" | |
_staticlibs="" | |
_staticlibs_js_array="" | |
_updater_name="" | |
_updater_bin="" | |
;; | |
"uv-arm-unknown-linux-musleabihf.tar.gz") | |
_arch="arm-unknown-linux-musl-staticeabihf" | |
_zip_ext=".tar.gz" | |
_bins="uv uvx" | |
_bins_js_array='"uv","uvx"' | |
_libs="" | |
_libs_js_array="" | |
_staticlibs="" | |
_staticlibs_js_array="" | |
_updater_name="" | |
_updater_bin="" | |
;; | |
"uv-armv7-unknown-linux-gnueabihf.tar.gz") | |
_arch="armv7-unknown-linux-gnueabihf" | |
_zip_ext=".tar.gz" | |
_bins="uv uvx" | |
_bins_js_array='"uv","uvx"' | |
_libs="" | |
_libs_js_array="" | |
_staticlibs="" | |
_staticlibs_js_array="" | |
_updater_name="" | |
_updater_bin="" | |
;; | |
"uv-armv7-unknown-linux-musleabihf.tar.gz") | |
_arch="armv7-unknown-linux-musl-staticeabihf" | |
_zip_ext=".tar.gz" | |
_bins="uv uvx" | |
_bins_js_array='"uv","uvx"' | |
_libs="" | |
_libs_js_array="" | |
_staticlibs="" | |
_staticlibs_js_array="" | |
_updater_name="" | |
_updater_bin="" | |
;; | |
"uv-i686-pc-windows-msvc.zip") | |
_arch="i686-pc-windows-msvc" | |
_zip_ext=".zip" | |
_bins="uv.exe uvx.exe" | |
_bins_js_array='"uv.exe","uvx.exe"' | |
_libs="" | |
_libs_js_array="" | |
_staticlibs="" | |
_staticlibs_js_array="" | |
_updater_name="" | |
_updater_bin="" | |
;; | |
"uv-i686-unknown-linux-gnu.tar.gz") | |
_arch="i686-unknown-linux-gnu" | |
_zip_ext=".tar.gz" | |
_bins="uv uvx" | |
_bins_js_array='"uv","uvx"' | |
_libs="" | |
_libs_js_array="" | |
_staticlibs="" | |
_staticlibs_js_array="" | |
_updater_name="" | |
_updater_bin="" | |
;; | |
"uv-i686-unknown-linux-musl.tar.gz") | |
_arch="i686-unknown-linux-musl-static" | |
_zip_ext=".tar.gz" | |
_bins="uv uvx" | |
_bins_js_array='"uv","uvx"' | |
_libs="" | |
_libs_js_array="" | |
_staticlibs="" | |
_staticlibs_js_array="" | |
_updater_name="" | |
_updater_bin="" | |
;; | |
"uv-powerpc64-unknown-linux-gnu.tar.gz") | |
_arch="powerpc64-unknown-linux-gnu" | |
_zip_ext=".tar.gz" | |
_bins="uv uvx" | |
_bins_js_array='"uv","uvx"' | |
_libs="" | |
_libs_js_array="" | |
_staticlibs="" | |
_staticlibs_js_array="" | |
_updater_name="" | |
_updater_bin="" | |
;; | |
"uv-powerpc64le-unknown-linux-gnu.tar.gz") | |
_arch="powerpc64le-unknown-linux-gnu" | |
_zip_ext=".tar.gz" | |
_bins="uv uvx" | |
_bins_js_array='"uv","uvx"' | |
_libs="" | |
_libs_js_array="" | |
_staticlibs="" | |
_staticlibs_js_array="" | |
_updater_name="" | |
_updater_bin="" | |
;; | |
"uv-s390x-unknown-linux-gnu.tar.gz") | |
_arch="s390x-unknown-linux-gnu" | |
_zip_ext=".tar.gz" | |
_bins="uv uvx" | |
_bins_js_array='"uv","uvx"' | |
_libs="" | |
_libs_js_array="" | |
_staticlibs="" | |
_staticlibs_js_array="" | |
_updater_name="" | |
_updater_bin="" | |
;; | |
"uv-x86_64-apple-darwin.tar.gz") | |
_arch="x86_64-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="" | |
;; | |
"uv-x86_64-pc-windows-msvc.zip") | |
_arch="x86_64-pc-windows-msvc" | |
_zip_ext=".zip" | |
_bins="uv.exe uvx.exe" | |
_bins_js_array='"uv.exe","uvx.exe"' | |
_libs="" | |
_libs_js_array="" | |
_staticlibs="" | |
_staticlibs_js_array="" | |
_updater_name="" | |
_updater_bin="" | |
;; | |
"uv-x86_64-unknown-linux-gnu.tar.gz") | |
_arch="x86_64-unknown-linux-gnu" | |
_zip_ext=".tar.gz" | |
_bins="uv uvx" | |
_bins_js_array='"uv","uvx"' | |
_libs="" | |
_libs_js_array="" | |
_staticlibs="" | |
_staticlibs_js_array="" | |
_updater_name="" | |
_updater_bin="" | |
;; | |
"uv-x86_64-unknown-linux-musl.tar.gz") | |
_arch="x86_64-unknown-linux-musl-static" | |
_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 "internal installer error: selected download $_artifact_name doesn't exist!?" | |
;; | |
esac | |
# Replace the placeholder binaries with the calculated array from above | |
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"/)" | |
# download the archive | |
local _url="$ARTIFACT_DOWNLOAD_URL/$_artifact_name" | |
local _dir | |
_dir="$(ensure mktemp -d)" || return 1 | |
local _file="$_dir/input$_zip_ext" | |
say "downloading $APP_NAME $APP_VERSION ${_arch}" 1>&2 | |
say_verbose " from $_url" 1>&2 | |
say_verbose " to $_file" 1>&2 | |
ensure mkdir -p "$_dir" | |
if ! downloader "$_url" "$_file"; then | |
say "failed to download $_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 | |
# ...and then the updater, if it exists | |
if [ -n "$_updater_name" ] && [ "$INSTALL_UPDATER" = "1" ]; then | |
local _updater_url="$ARTIFACT_DOWNLOAD_URL/$_updater_name" | |
# This renames the artifact while doing the download, removing the | |
# target triple and leaving just the appname-update format | |
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 | |
# Add the updater to the list of binaries to install | |
_bins="$_bins $APP_NAME-update" | |
fi | |
# unpack the archive | |
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" | |
# Install the install receipt | |
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" | |
# shellcheck disable=SC2320 | |
local _retval=$? | |
fi | |
else | |
local _retval=0 | |
fi | |
return "$_retval" | |
} | |
# Replaces $HOME with the variable name for display to the user, | |
# only if $HOME is defined. | |
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-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 '{}' | |
;; | |
"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-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 | |
;; | |
"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 | |
;; | |
"aarch64-pc-windows-msvc") | |
_archive="uv-x86_64-pc-windows-msvc.zip" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
_archive="uv-i686-pc-windows-msvc.zip" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"aarch64-unknown-linux-gnu") | |
_archive="uv-aarch64-unknown-linux-gnu.tar.gz" | |
if ! check_glibc "2" "31"; then | |
_archive="" | |
fi | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
_archive="uv-aarch64-unknown-linux-musl.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"aarch64-unknown-linux-musl-dynamic") | |
_archive="uv-aarch64-unknown-linux-musl.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"aarch64-unknown-linux-musl-static") | |
_archive="uv-aarch64-unknown-linux-musl.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"arm-unknown-linux-gnueabihf") | |
_archive="uv-arm-unknown-linux-musleabihf.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"arm-unknown-linux-musl-dynamiceabihf") | |
_archive="uv-arm-unknown-linux-musleabihf.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"arm-unknown-linux-musl-staticeabihf") | |
_archive="uv-arm-unknown-linux-musleabihf.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"armv7-unknown-linux-gnueabihf") | |
_archive="uv-armv7-unknown-linux-gnueabihf.tar.gz" | |
if ! check_glibc "2" "31"; then | |
_archive="" | |
fi | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
_archive="uv-armv7-unknown-linux-musleabihf.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"armv7-unknown-linux-musl-dynamiceabihf") | |
_archive="uv-armv7-unknown-linux-musleabihf.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"armv7-unknown-linux-musl-staticeabihf") | |
_archive="uv-armv7-unknown-linux-musleabihf.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"i686-pc-windows-gnu") | |
_archive="uv-i686-pc-windows-msvc.zip" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"i686-pc-windows-msvc") | |
_archive="uv-i686-pc-windows-msvc.zip" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"i686-unknown-linux-gnu") | |
_archive="uv-i686-unknown-linux-gnu.tar.gz" | |
if ! check_glibc "2" "31"; then | |
_archive="" | |
fi | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
_archive="uv-i686-unknown-linux-musl.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"i686-unknown-linux-musl-dynamic") | |
_archive="uv-i686-unknown-linux-musl.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"i686-unknown-linux-musl-static") | |
_archive="uv-i686-unknown-linux-musl.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"powerpc64-unknown-linux-gnu") | |
_archive="uv-powerpc64-unknown-linux-gnu.tar.gz" | |
if ! check_glibc "2" "31"; then | |
_archive="" | |
fi | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"powerpc64le-unknown-linux-gnu") | |
_archive="uv-powerpc64le-unknown-linux-gnu.tar.gz" | |
if ! check_glibc "2" "31"; then | |
_archive="" | |
fi | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"s390x-unknown-linux-gnu") | |
_archive="uv-s390x-unknown-linux-gnu.tar.gz" | |
if ! check_glibc "2" "31"; then | |
_archive="" | |
fi | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"x86_64-apple-darwin") | |
_archive="uv-x86_64-apple-darwin.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"x86_64-pc-windows-gnu") | |
_archive="uv-x86_64-pc-windows-msvc.zip" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"x86_64-pc-windows-msvc") | |
_archive="uv-x86_64-pc-windows-msvc.zip" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
_archive="uv-i686-pc-windows-msvc.zip" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"x86_64-unknown-linux-gnu") | |
_archive="uv-x86_64-unknown-linux-gnu.tar.gz" | |
if ! check_glibc "2" "31"; then | |
_archive="" | |
fi | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
_archive="uv-x86_64-unknown-linux-musl.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"x86_64-unknown-linux-musl-dynamic") | |
_archive="uv-x86_64-unknown-linux-musl.tar.gz" | |
if [ -n "$_archive" ]; then | |
echo "$_archive" | |
return 0 | |
fi | |
;; | |
"x86_64-unknown-linux-musl-static") | |
_archive="uv-x86_64-unknown-linux-musl.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" | |
# Parsing version out from line 1 like: | |
# ldd (Ubuntu GLIBC 2.35-0ubuntu3.1) 2.35 | |
_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 | |
} | |
# See discussion of late-bound vs early-bound for why we use single-quotes with env vars | |
# shellcheck disable=SC2016 | |
install() { | |
# This code needs to both compute certain paths for itself to write to, and | |
# also write them to shell/rc files so that they can look them up to e.g. | |
# add them to PATH. This requires an active distinction between paths | |
# and expressions that can compute them. | |
# | |
# The distinction lies in when we want env-vars to be evaluated. For instance | |
# if we determine that we want to install to $HOME/.myapp, which do we add | |
# to e.g. $HOME/.profile: | |
# | |
# * early-bound: export PATH="/home/myuser/.myapp:$PATH" | |
# * late-bound: export PATH="$HOME/.myapp:$PATH" | |
# | |
# In this case most people would prefer the late-bound version, but in other | |
# cases the early-bound version might be a better idea. In particular when using | |
# other env-vars than $HOME, they are more likely to be only set temporarily | |
# for the duration of this install script, so it's more advisable to erase their | |
# existence with early-bounding. | |
# | |
# This distinction is handled by "double-quotes" (early) vs 'single-quotes' (late). | |
# | |
# However if we detect that "$SOME_VAR/..." is a subdir of $HOME, we try to rewrite | |
# it to be '$HOME/...' to get the best of both worlds. | |
# | |
# This script has a few different variants, the most complex one being the | |
# CARGO_HOME version which attempts to install things to Cargo's bin dir, | |
# potentially setting up a minimal version if the user hasn't ever installed Cargo. | |
# | |
# In this case we need to: | |
# | |
# * Install to $HOME/.cargo/bin/ | |
# * Create a shell script at $HOME/.cargo/env that: | |
# * Checks if $HOME/.cargo/bin/ is on PATH | |
# * and if not prepends it to PATH | |
# * Edits $HOME/.profile to run $HOME/.cargo/env (if the line doesn't exist) | |
# | |
# To do this we need these 4 values: | |
# The actual path we're going to install to | |
local _install_dir | |
# The directory C dynamic/static libraries install to | |
local _lib_install_dir | |
# The install prefix we write to the receipt. | |
# For organized install methods like CargoHome, which have | |
# subdirectories, this is the root without `/bin`. For other | |
# methods, this is the same as `_install_dir`. | |
local _receipt_install_dir | |
# Path to the an shell script that adds install_dir to PATH | |
local _env_script_path | |
# Potentially-late-bound version of install_dir to write env_script | |
local _install_dir_expr | |
# Potentially-late-bound version of env_script_path to write to rcfiles like $HOME/.profile | |
local _env_script_path_expr | |
# Forces the install to occur at this path, not the default | |
local _force_install_dir | |
# Which install layout to use - "flat" or "hierarchical" | |
local _install_layout="unspecified" | |
# Check the newer app-specific variable before falling back | |
# to the older generic one | |
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" | |
# Workaround for https://github.com/axodotdev/axoupdater/issues/210 | |
# This was manually added to the installer post-release to patch the 0.4.30 -> 0.5.0 upgrade | |
if [ "$_force_install_dir" = "${HOME:-}/.cargo" ] || [ "$_force_install_dir" = "${CARGO_HOME:-}" ]; then | |
_install_layout="cargo-home" | |
else | |
_install_layout="flat" | |
fi | |
elif [ -n "$UNMANAGED_INSTALL" ]; then | |
_force_install_dir="$UNMANAGED_INSTALL" | |
_install_layout="flat" | |
fi | |
# Before actually consulting the configured install strategy, see | |
# if we're overriding it. | |
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" | |
# Install to $XDG_BIN_HOME | |
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" | |
# Install to $XDG_DATA_HOME/../bin | |
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" | |
# Install to $HOME/.local/bin | |
if [ -n "${HOME:-}" ]; then | |
_install_dir="$HOME/.local/bin" | |
_lib_install_dir="$HOME/.local/bin" | |
_receipt_install_dir="$_install_dir" | |
_env_script_path="$HOME/.local/bin/env" | |
_install_dir_expr='$HOME/.local/bin' | |
_env_script_path_expr='$HOME/.local/bin/env' | |
fi | |
fi | |
if [ -z "$_install_dir_expr" ]; then | |
err "could not find a valid path to install to!" | |
fi | |
# Identical to the sh version, just with a .fish file extension | |
# We place it down here to wait until it's been assigned in every | |
# path. | |
_fish_env_script_path="${_env_script_path}.fish" | |
_fish_env_script_path_expr="${_env_script_path_expr}.fish" | |
# Replace the temporary cargo home with the calculated one | |
RECEIPT=$(echo "$RECEIPT" | sed "s,AXO_INSTALL_PREFIX,$_receipt_install_dir,") | |
# Also replace the aliases with the arch-specific one | |
RECEIPT=$(echo "$RECEIPT" | sed "s'\"binary_aliases\":{}'\"binary_aliases\":$(json_binary_aliases "$_arch")'") | |
# And replace the install layout | |
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" | |
# copy all the binaries to the 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" | |
# unzip seems to need this chmod | |
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 | |
# Like the above, but no aliases | |
for _lib_name in $_libs; do | |
local _lib="$_src_dir/$_lib_name" | |
ensure mv "$_lib" "$_lib_install_dir" | |
# unzip seems to need this chmod | |
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" | |
# unzip seems to need this chmod | |
ensure chmod +x "$_lib_install_dir/$_lib_name" | |
say " $_lib_name" | |
done | |
say "everything's installed!" | |
# Avoid modifying the users PATH if they are managing their PATH manually | |
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=$? | |
# This path may not exist by default | |
ensure mkdir -p "$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 | |
} | |
print_home_for_script() { | |
local script="$1" | |
local _home | |
case "$script" in | |
# zsh has a special ZDOTDIR directory, which if set | |
# should be considered instead of $HOME | |
.zsh*) | |
if [ -n "${ZDOTDIR:-}" ]; then | |
_home="$ZDOTDIR" | |
else | |
_home="$HOME" | |
fi | |
;; | |
*) | |
_home="$HOME" | |
;; | |
esac | |
echo "$_home" | |
} | |
add_install_dir_to_ci_path() { | |
# Attempt to do CI-specific rituals to get the install-dir on PATH faster | |
local _install_dir="$1" | |
# If GITHUB_PATH is present, then write install_dir to the file it refs. | |
# After each GitHub Action, the contents will be added to PATH. | |
# So if you put a curl | sh for this script in its own "run" step, | |
# the next step will have this dir on PATH. | |
# | |
# Note that GITHUB_PATH will not resolve any variables, so we in fact | |
# want to write install_dir and not install_dir_expr | |
if [ -n "${GITHUB_PATH:-}" ]; then | |
ensure echo "$_install_dir" >> "$GITHUB_PATH" | |
fi | |
} | |
add_install_dir_to_path() { | |
# Edit rcfiles ($HOME/.profile) to add install_dir to $PATH | |
# | |
# We do this slightly indirectly by creating an "env" shell script which checks if install_dir | |
# is on $PATH already, and prepends it if not. The actual line we then add to rcfiles | |
# is to just source that script. This allows us to blast it into lots of different rcfiles and | |
# have it run multiple times without causing problems. It's also specifically compatible | |
# with the system rustup uses, so that we don't conflict with it. | |
local _install_dir_expr="$1" | |
local _env_script_path="$2" | |
local _env_script_path_expr="$3" | |
local _rcfiles="$4" | |
local _shell="$5" | |
if [ -n "${HOME:-}" ]; then | |
local _target | |
local _home | |
# Find the first file in the array that exists and choose | |
# that as our target to write to | |
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 we didn't find anything, pick the first entry in the | |
# list as the default to create and write to | |
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 | |
# `source x` is an alias for `. x`, and the latter is more portable/actually-posix. | |
# This apparently comes up a lot on freebsd. It's easy enough to always add | |
# the more robust line to rcfiles, but when telling the user to apply the change | |
# to their current shell ". x" is pretty easy to misread/miscopy, so we use the | |
# prettier "source x" line there. Hopefully people with Weird Shells are aware | |
# this is a thing and know to tweak it (or just restart their shell). | |
local _robust_line=". \"$_env_script_path_expr\"" | |
local _pretty_line="source \"$_env_script_path_expr\"" | |
# Add the env script if it doesn't already exist | |
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 | |
# Check if the line is already in the rcfile | |
# grep: 0 if matched, 1 if no match, and 2 if an error occurred | |
# | |
# Ideally we could use quiet grep (-q), but that makes "match" and "error" | |
# have the same behaviour, when we want "no match" and "error" to be the same | |
# (on error we want to create the file, which >> conveniently does) | |
# | |
# We search for both kinds of line here just to do the right thing in more cases. | |
if ! grep -F "$_robust_line" "$_target" > /dev/null 2>/dev/null && \ | |
! grep -F "$_pretty_line" "$_target" > /dev/null 2>/dev/null | |
then | |
# If the script now exists, add the line to source it to the rcfile | |
# (This will also create the rcfile if it doesn't exist) | |
if [ -f "$_env_script_path" ]; then | |
local _line | |
# Fish has deprecated `.` as an alias for `source` and | |
# it will be removed in a later version. | |
# https://fishshell.com/docs/current/cmds/source.html | |
# By contrast, `.` is the traditional syntax in sh and | |
# `source` isn't always supported in all circumstances. | |
if [ "$_shell" = "fish" ]; then | |
_line="$_pretty_line" | |
else | |
_line="$_robust_line" | |
fi | |
say_verbose "adding $_line to $_target" | |
# prepend an extra newline in case the user's file is missing a trailing one | |
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() { | |
# Edit rcfiles ($HOME/.profile) to add install_dir to $PATH | |
# (Shotgun edition - write to all provided files that exist rather than just the first) | |
local _install_dir_expr="$1" | |
local _env_script_path="$2" | |
local _env_script_path_expr="$3" | |
local _rcfiles="$4" | |
local _shell="$5" | |
if [ -n "${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 | |
# Fall through to previous "create + write to first file in list" behavior | |
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() { | |
# write this env script to the given path (this cat/EOF stuff is a "heredoc" string) | |
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() { | |
# write this env script to the given path (this cat/EOF stuff is a "heredoc" string) | |
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 | |
} | |
check_proc() { | |
# Check for /proc by looking for the /proc/self/exe link | |
# This is only run on Linux | |
if ! test -L /proc/self/exe ; then | |
err "fatal: Unable to find /proc/self/exe. Is /proc mounted? Installation cannot proceed without /proc." | |
fi | |
} | |
get_bitness() { | |
need_cmd head | |
# Architecture detection without dependencies beyond coreutils. | |
# ELF files start out "\x7fELF", and the following byte is | |
# 0x01 for 32-bit and | |
# 0x02 for 64-bit. | |
# The printf builtin on some shells like dash only supports octal | |
# escape sequences, so we use those. | |
local _current_exe_head | |
_current_exe_head=$(head -c 5 /proc/self/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() { | |
need_cmd head | |
need_cmd tail | |
# ELF e_machine detection without dependencies beyond coreutils. | |
# Two-byte field at offset 0x12 indicates the CPU, | |
# but we're interested in it being 0x3E to indicate amd64, or not that. | |
local _current_exe_machine | |
_current_exe_machine=$(head -c 19 /proc/self/exe | tail -c 1) | |
[ "$_current_exe_machine" = "$(printf '\076')" ] | |
} | |
get_endianness() { | |
local cputype=$1 | |
local suffix_eb=$2 | |
local suffix_el=$3 | |
# detect endianness without od/hexdump, like get_bitness() does. | |
need_cmd head | |
need_cmd tail | |
local _current_exe_endianness | |
_current_exe_endianness="$(head -c 6 /proc/self/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 | |
} | |
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 | |
# Assume all other linuxes are glibc (even if wrong, static libc fallback will apply) | |
_clibtype="gnu" | |
fi | |
fi | |
if [ "$_ostype" = Darwin ] && [ "$_cputype" = i386 ]; then | |
# Darwin `uname -m` lies | |
if sysctl hw.optional.x86_64 | grep -q ': 1'; then | |
_cputype=x86_64 | |
fi | |
fi | |
if [ "$_ostype" = Darwin ] && [ "$_cputype" = x86_64 ]; then | |
# Rosetta on aarch64 | |
if [ "$(sysctl -n hw.optional.arm64 2>/dev/null)" = "1" ]; then | |
_cputype=aarch64 | |
fi | |
fi | |
if [ "$_ostype" = SunOS ]; then | |
# Both Solaris and illumos presently announce as "SunOS" in "uname -s" | |
# so use "uname -o" to disambiguate. We use the full path to the | |
# system uname in case the user has coreutils uname first in PATH, | |
# which has historically sometimes printed the wrong value here. | |
if [ "$(/usr/bin/uname -o)" = illumos ]; then | |
_ostype=illumos | |
fi | |
# illumos systems have multi-arch userlands, and "uname -m" reports the | |
# machine hardware name; e.g., "i86pc" on both 32- and 64-bit x86 | |
# systems. Check for the native (widest) instruction set on the | |
# running kernel: | |
if [ "$_cputype" = i86pc ]; then | |
_cputype="$(isainfo -n)" | |
fi | |
fi | |
case "$_ostype" in | |
Android) | |
_ostype=linux-android | |
;; | |
Linux) | |
check_proc | |
_ostype=unknown-linux-$_clibtype | |
_bitness=$(get_bitness) | |
;; | |
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 mips '' el) | |
;; | |
mips64) | |
if [ "$_bitness" -eq 64 ]; then | |
# only n64 ABI is supported for now | |
_ostype="${_ostype}abi64" | |
_cputype=$(get_endianness mips64 '' el) | |
fi | |
;; | |
ppc) | |
_cputype=powerpc | |
;; | |
ppc64) | |
_cputype=powerpc64 | |
;; | |
ppc64le) | |
_cputype=powerpc64le | |
;; | |
s390x) | |
_cputype=s390x | |
;; | |
riscv64) | |
_cputype=riscv64gc | |
;; | |
loongarch64) | |
_cputype=loongarch64 | |
;; | |
*) | |
err "unknown CPU type: $_cputype" | |
esac | |
# Detect 64-bit linux with 32-bit userland | |
if [ "${_ostype}" = unknown-linux-gnu ] && [ "${_bitness}" -eq 32 ]; then | |
case $_cputype in | |
x86_64) | |
# 32-bit executable for amd64 = x32 | |
if is_host_amd64_elf; then { | |
err "x32 linux unsupported" | |
}; else | |
_cputype=i686 | |
fi | |
;; | |
mips64) | |
_cputype=$(get_endianness 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 | |
# treat armv7 systems without neon as plain arm | |
if [ "$_ostype" = "unknown-linux-gnueabihf" ] && [ "$_cputype" = armv7 ]; then | |
if ensure grep '^Features' /proc/cpuinfo | grep -q -v neon; then | |
# At least one processor does not have NEON. | |
_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 | |
} | |
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 | |
} | |
# Run a command that should never fail. If the command fails execution | |
# will immediately terminate with an error showing the failing | |
# command. | |
ensure() { | |
if ! "$@"; then err "command failed: $*"; fi | |
} | |
# This is just for indicating that commands' results are being | |
# intentionally ignored. Usually, because it's being executed | |
# as part of error handling. | |
ignore() { | |
"$@" | |
} | |
# This wraps curl or wget. Try curl first, if not installed, | |
# use wget instead. | |
downloader() { | |
if check_cmd curl | |
then _dld=curl | |
elif check_cmd wget | |
then _dld=wget | |
else _dld='curl or wget' # to be used in error message of need_cmd | |
fi | |
if [ "$1" = --check ] | |
then need_cmd "$_dld" | |
elif [ "$_dld" = curl ] | |
then curl -sSfL "$1" -o "$2" | |
elif [ "$_dld" = wget ] | |
then wget "$1" -O "$2" | |
else err "Unknown downloader" # should not reach here | |
fi | |
} | |
download_binary_and_run_installer "$@" || exit 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment