Last active
July 7, 2025 16:22
-
-
Save dotysan/fdbfc77b924a08ceab7197d010280dac to your computer and use it in GitHub Desktop.
Simple non-POSIX UV installer.
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
#! /usr/bin/env bash | |
# | |
# Simple non-POSIX UV installer. | |
# | |
# You can download and run it. Or just run it off the web with: | |
# $ curl --location https://gist.github.com/dotysan/fdbfc77b924a08ceab7197d010280dac/raw/uv-install.sh |bash | |
# | |
# If you want to see what it does, before running: | |
# $ export DEBUG=yes | |
# | |
# optional | |
#DEBUG=yep | |
main() { | |
chk_deps | |
get_uv | |
} | |
#======================================================================= | |
chk_deps() { | |
chkadep curl | |
chkadep uname | |
} | |
get_uv() { | |
# Most modern linux distros will add ~/.local/bin to the $PATH on | |
# next login--as soon as it exists. But if we're creating it here, | |
# inject the $PATH now, so we don't need to log out & back in! | |
if ! grep -qE "(^|:)$HOME/.local/bin:" <<<"$PATH" | |
then export PATH="$HOME/.local/bin:$PATH" | |
fi | |
if ! chkadep uv || ! chkadep uvx | |
then | |
get_github_latest astral-sh uv | |
create_uv_receipt | |
fi | |
uv self update | |
} | |
#----------------------------------------------------------------------- | |
chkadep() { | |
if ! hash "$@" | |
then | |
echo "ERROR: Must install $@ to use this script." | |
return 1 | |
fi >&2 | |
} | |
get_github_latest() { | |
local owner="$1" | |
local repo="$2" | |
local os=$(uname --operating-system) | |
if ! [[ ${os,,} =~ linux ]] | |
then | |
echo "ERROR: OS:$os This script only understands linux." | |
return 1 | |
fi >&2 | |
VERS=$(github_latest_tag "$owner" "$repo") | |
VERS="${VERS#https://github.com/$owner/$repo/releases/tag/}" | |
local machine=$(uname --machine) | |
local asset="https://github.com/$owner/$repo/releases/download/$VERS/$repo-$machine-unknown-linux-gnu.tar.gz" | |
mkdir --parents "$HOME/.local/bin" | |
curl --silent --location "$asset" |\ | |
tar --extract --gzip --directory="$HOME/.local/bin" --strip-components=1 | |
} | |
github_latest_tag() { | |
local owner="$1" | |
local repo="$2" | |
curl --fail --silent --show-error --location --head \ | |
--output /dev/null --write-out '%{url_effective}' \ | |
"https://github.com/$owner/$repo/releases/latest" | |
} | |
create_uv_receipt() { | |
mkdir --parents "$HOME/.config/uv" | |
cat >"$HOME/.config/uv/uv-receipt.json" <<-EOF | |
{ | |
"binaries": ["uv", "uvx"], | |
"install_layout": "flat", | |
"install_prefix": "$HOME/.local/bin", | |
"modify_path": false, | |
"provider": { | |
"source": "dotysan", | |
"version": "0.1.0" | |
}, | |
"source": { | |
"app_name": "uv", | |
"name": "uv", | |
"owner": "astral-sh", | |
"release_type": "github" | |
}, | |
"version": "$VERS" | |
} | |
EOF | |
} | |
# ====================================================================== | |
# shellcheck disable=SC2128 | |
if [ -z "$BASH_VERSINFO" ] || [[ ${BASH_VERSINFO[0]} -lt 4 ]] | |
then | |
echo "ERROR: Only tested on Bourne-Again SHell v4/v5." | |
exit 1 | |
fi >&2 | |
# poor man's __main__ | |
return 2>/dev/null ||: | |
if [ "$(type -t "$1")" = "function" ] | |
then | |
func="$1" | |
shift 1 | |
"$func" "$@" | |
exit 0 | |
fi | |
set -o errtrace | |
set -o errexit | |
set -o nounset | |
set -o pipefail | |
if [[ "${DEBUG:-}" ]] | |
then | |
PS4func() { | |
local normal="\033[0m" | |
#local red="\033[0;31m" | |
#local green="\033[0;32m" | |
local yellow="\033[0;33m" | |
#local blue="\033[0;34m" | |
#local magenta="\033[0;35m" | |
local cyan="\033[0;36m" | |
local i caller_idx=-1 | |
# walk the call stack to see if we are sourced and from where | |
if [[ ${#BASH_SOURCE[@]} -gt 2 ]] | |
then | |
for (( i=2; i<${#BASH_SOURCE[@]}; i++ )) | |
do | |
if [[ ${BASH_SOURCE[1]} != "${BASH_SOURCE[i]}" ]] | |
then | |
caller_idx=$i | |
break | |
fi | |
done | |
fi | |
local src func='' | |
local caller deep | |
if [[ $caller_idx -ne -1 ]] | |
then # we're in a sourced script | |
if [[ ${BASH_SOURCE[0]} == main ]] | |
then caller='<stdin>' | |
else caller="${BASH_SOURCE[0]##*/}" | |
fi | |
src="$caller:${BASH_LINENO[caller_idx-1]}${cyan}source->$yellow${BASH_SOURCE[1]##*/}:${BASH_LINENO[0]}" | |
if [[ ${FUNCNAME[-2]} == main && ${FUNCNAME[-1]} == main ]] | |
then deep=$((${#FUNCNAME[@]}-5)) | |
else deep=$((${#FUNCNAME[@]}-4)) | |
fi | |
elif [[ ${BASH_SOURCE[0]} == main ]] | |
then # reading from standard input instead of a script file | |
src="<stdin>:${BASH_LINENO[0]}" | |
deep=$((${#FUNCNAME[@]}-1)) | |
else # a normal script file | |
src="${BASH_SOURCE[0]##*/}:${BASH_LINENO[0]}" | |
deep=$((${#FUNCNAME[@]}-2)) | |
fi | |
if (( deep >= 1 )) | |
then | |
if [[ ${FUNCNAME[1]} != source ]] | |
then func+="${FUNCNAME[1]}()" | |
fi | |
fi | |
# local lines="${BASH_LINENO[@]}" | |
# local sources="${BASH_SOURCE[@]##*/}" | |
# local funcs="${FUNCNAME[@]}" | |
# printf "${red}sources(%d): %s\nlines(%d): %s | funcs(%d): %s|%b" \ | |
# "${#BASH_SOURCE[@]}" "$sources" \ | |
# "${#BASH_LINENO[@]}" "$lines" \ | |
# "${#FUNCNAME[@]}" "$funcs" \ | |
# "$yellow$src$cyan$func$normal " | |
# run the above to debug your stacks | |
printf "%b" "$yellow$src$cyan$func$normal " | |
} | |
PS4='\r$(PS4func)' | |
set -o xtrace | |
fi | |
main "$@" | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment