uv/scripts/bootstrap/install

100 lines
2.8 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Download required Python versions and install to `bin`
# Uses prebuilt Python distributions from indygreg/python-build-standalone
#
# Requirements
#
# macOS
#
# brew install zstd coreutils
#
# Ubuntu
#
# apt install zstd
#
# Arch Linux
#
# pacman -S zstd
#
# Usage
#
# ./scripts/bootstrap/install
#
# The Python versions are installed from `.python_versions`.
# Python versions are linked in-order such that the _last_ defined version will be the default.
#
# Version metadata can be updated with `fetch-versions` which requires Python 3.12
set -eu pipefail
function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
# Setup some file paths
this_dir=$(realpath "$(dirname "$0")")
root_dir=$(dirname "$(dirname "$this_dir")")
bin_dir="$root_dir/bin"
install_dir="$bin_dir/versions"
versions_file="$root_dir/.python-versions"
versions_metadata="$this_dir/versions.json"
# Determine system metadata
os=$(uname | tr '[:upper:]' '[:lower:]')
arch=$(arch)
interpreter='cpython'
# macOS is horrible
realpath="$(which grealpath || which realpath)"
# Read requested versions into an array
readarray -t versions < "$versions_file"
# Install each version
for version in "${versions[@]}"; do
key="$interpreter-$version-$os-$arch"
echo "Installing $key"
url=$(cat "$versions_metadata" | jq --arg key "$key" '.[$key] | .url' -r)
if [ "$url" == 'null' ]; then
echo "No matching download for $key"
exit 1
fi
filename=$(basename $url)
echo "Downloading $(urldecode $filename)"
curl -L --progress-bar -o $filename $url --output-dir "$this_dir"
expected_sha=$(cat "$versions_metadata" | jq --arg key "$key" '.[$key] | .sha256' -r)
if [ "$expected_sha" == 'null' ]; then
echo "WARNING: no checksum for $key"
else
echo -n "Verifying checksum..."
echo "$expected_sha $this_dir/$filename" | sha256sum -c --quiet
echo " OK"
fi
install_key="$install_dir/$interpreter@$version"
rm -rf "$install_key"
echo "Extracting to $($realpath --relative-to=$root_dir $install_key)"
mkdir -p "$install_key"
zstd -d "$this_dir/$filename" --stdout | tar -x -C "$install_key"
# Setup the installation
mv "$install_key/python/"* "$install_key"
link=$($realpath --relative-to=$bin_dir "$install_key/install/bin/python3")
minor=$(cat "$versions_metadata" | jq --arg key "$key" '.[$key] | .minor' -r)
# Link as all version tuples, later versions in the file will take precedence
ln -sf "./$link" "$bin_dir/python$version"
ln -sf "./$link" "$bin_dir/python3.$minor"
ln -sf "./$link" "$bin_dir/python3"
ln -sf "./$link" "$bin_dir/python"
echo "Installed as python$version"
# Cleanup
rmdir "$install_key/python/"
rm "$this_dir/$filename"
done
echo "Done!"