Skip to content

Instantly share code, notes, and snippets.

@dotysan
Last active July 7, 2025 16:22
Show Gist options
  • Save dotysan/fdbfc77b924a08ceab7197d010280dac to your computer and use it in GitHub Desktop.
Save dotysan/fdbfc77b924a08ceab7197d010280dac to your computer and use it in GitHub Desktop.
Simple non-POSIX UV installer.
#! /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