Skip to content

Instantly share code, notes, and snippets.

@snydergd
Last active May 28, 2023 23:05
Show Gist options
  • Save snydergd/abd38cdcb459944a5a0470185056890c to your computer and use it in GitHub Desktop.
Save snydergd/abd38cdcb459944a5a0470185056890c to your computer and use it in GitHub Desktop.
Python downloader/installer
#!/bin/bash
#
# Summary: Installs/upgrades python installations on your machine.
#
# Prerequisites:
# - jq and curl to be installed and in a folder on the PATH environment variable
# - PLATFORM and STORAGE_FOLDER variables below to be set correctly (did not take time to automatically pick)
#
usage() {
echo "Usage: $0 [-v | --version <version prefix>] [-a | --additional-version] [-h | --help]" >&2;
echo " -v <version> -- What version to install (e.g., '3', '3.10', '3.10.0') - latest with prefix is installed" >&2;
echo " -a -- Don't replace current version - install additional" >&2;
echo " -u -- Upgrade if available -- or do nothing if already installed" >&2;
echo " -h -- Show this help and exit" >&2;
}
die() {
echo $* >&2;
exit 1;
}
# Substring to match in the download filename for this platform -- see download link values on the website to pick one
PLATFORM='embed-amd64';
# Where you want the distributions to be stored
STORAGE_FOLDER='/c/repos/app';
# www.python.org api documentation (more or less): https://github.com/python/pythondotorg/blob/main/downloads/api.py
RELEASE_INFO_URL="https://www.python.org/api/v2/downloads/release/";
FILE_INFO_URL_BASE="https://www.python.org/api/v2/downloads/release_file/";
DOWNLOAD_FOLDER="$STORAGE_FOLDER/python-current";
# Defaults
VERSION_PREFIX=3;
ADDITIONAL=no;
UPGRADE=no;
while [ $# -gt 0 ]; do
case $1 in
-v | --version)
shift;
VERSION_PREFIX="$1";
;;
-a | --additional-version)
ADDITIONAL=yes;
;;
-u | --upgrade)
UPGRADE=yes;
;;
-h | --help)
usage;
exit;
;;
*)
usage;
die "unrecognized option $1";
;;
esac;
shift;
done;
if ! which jq >/dev/null 2>&1; then
echo "You must have jq installed and in a path in the PATH environment variable for this to work.";
fi;
echo -e "\nDetermining version information";
VERSION_PREFIX_PATTERN="$(echo "$VERSION_PREFIX" | sed -e 's/[^.0-9]//g; s/\./\\\\./g')";
# Sort by version (descending) then take the first (latest) one
JQ_PATTERN='def lpad(n):
tostring |
if n > length then
((n-length)*"0") + .
else
.
end;
[
.[]
| select(.name | match(" '$VERSION_PREFIX_PATTERN'\\.\\d$"))]
| sort_by(
.name
| split(" ")
| .[1]
| split(".")
| map(select(test("\\d")))
| map(tonumber | lpad(3))
| join("."))
| reverse
| .[0]';
RELEASE_INFO_JSON="$(curl "$RELEASE_INFO_URL" | jq "$JQ_PATTERN" -r)";
VERSION="$(echo "$RELEASE_INFO_JSON" | jq '.name | split(" ") | .[1]' -r)"
RELEASE_RESOURCE_URI="$(echo "$RELEASE_INFO_JSON" | jq '.resource_uri' -r)";
RELEASE_NUMBER="$(basename "$RELEASE_RESOURCE_URI")";
FILE_INFO_URL="${FILE_INFO_URL_BASE}?release=${RELEASE_NUMBER}";
DOWNLOAD_URL=$(curl "$FILE_INFO_URL" | jq '.[].url | select(contains("'$PLATFORM'"))' -r);
if [ $ADDITIONAL = "yes" ]; then
DOWNLOAD_FOLDER="$STORAGE_FOLDER/python-$VERSION";
if [ -e "$DOWNLOAD_FOLDER" ] && [ $UPGRADE != "yes" ]; then
die "Can't download additional version because folder already exists. Delete and run again: $DOWNLOAD_FOLDER";
fi;
fi;
if [ $(echo "$DOWNLOAD_FOLDER" | tr '/' ' ' | wc -w) -lt 2 ]; then
die "Refusing to write to $DOWNLOAD_FOLDER because it has less than 2 slashes -- don't want to risk breaking root folder";
fi;
if [ -e "$DOWNLOAD_FOLDER" ]; then
if [ -e "$DOWNLOAD_FOLDER/python" ] && [ "$("$DOWNLOAD_FOLDER/python" --version)" = "Python $VERSION" ]; then
echo "Version $VERSION already appears to be installed at $DOWNLOAD_FOLDER - doing nothing.";
exit;
fi;
rm -rf "$DOWNLOAD_FOLDER";
fi;
echo -e "\nActually performing download/install of the software from $DOWNLOAD_URL";
mkdir -p "$DOWNLOAD_FOLDER";
cd "$DOWNLOAD_FOLDER";
case "$DOWNLOAD_URL" in
*.zip)
curl "$DOWNLOAD_URL" -o "_archive.zip";
unzip "_archive.zip";
;;
*.tar.gz)
curl "$DOWNLOAD_URL" | tar -xzv;
;;
*)
die "Don't know how to handle file extension of download url: $DOWNLOAD_URL";
;;
esac;
if echo "$DOWNLOAD_URL" | grep "embed" >/dev/null; then
echo -e "\nInstalling pip";
PTH_FILE=
sed -i 's/^#//' "$DOWNLOAD_FOLDER/"python*._pth;
curl "https://bootstrap.pypa.io/get-pip.py" | "$DOWNLOAD_FOLDER/python" || die "Unable to install pip. See error for details.";
fi;
echo -e "\nVerifying installation";
if [ "$("$DOWNLOAD_FOLDER/python" --version)" != "Python $VERSION" ]; then
die "Something seems to be wrong with the installation -- maybe wrong architecture? Check the platform parameter variable in the script and see any error output directly above this message to troubleshoot.";
fi;
echo -e "\nInstalled to $DOWNLOAD_FOLDER successfully! You can ues it from there explicitly or add it to your PATH environment variable to use.";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment