mirror of
https://github.com/hanzoai/pack.git
synced 2026-09-30 23:43:13 +00:00
REPO_OWNER/REPO_NAME built the GitHub API and download URLs from railwayapp/railpack, so the installer could never find a release under this fork -- hanzoai/pack has never had one. REPO_NAME did double duty as both the repository slug (used in the API and download URLs, needs to be "pack") and the installed command name (used by `which`/`rm` on uninstall, needs to stay "railpack", the actual compiled binary name per .goreleaser.yml). Collapsing both into "pack" would make uninstall run `which pack`, which on many machines resolves to the unrelated Cloud Native Buildpacks CLI. Split it into REPO_NAME (repo slug and archive-name prefix, matching the project_name pinned in .goreleaser.yml) and a new BINARY_NAME (the installed executable), and routed each use to the right one. RELEASE.md's GHCR links and package-registry URLs updated to match. Do not merge until hanzoai/pack has an actual release: push a v* tag once the prior two commits are on main and the release workflow has published the builder, runtime, and frontend images. Before that, the download URL this script builds 404s by construction. Co-authored-by: Hanzo Dev <[email protected]>
490 lines
11 KiB
Bash
Executable File
490 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Repository configuration
|
|
REPO_OWNER="hanzoai"
|
|
REPO_NAME="pack"
|
|
REPO_URL="https://github.com/${REPO_OWNER}/${REPO_NAME}"
|
|
# the compiled binary is still named railpack (see .goreleaser.yml), distinct
|
|
# from the repository name above
|
|
BINARY_NAME="railpack"
|
|
|
|
help_text="Options
|
|
|
|
-V, --verbose
|
|
Enable verbose output for the installer
|
|
|
|
-f, -y, --force, --yes
|
|
Skip the confirmation prompt during installation
|
|
|
|
-p, --platform
|
|
Override the platform identified by the installer
|
|
|
|
-b, --bin-dir
|
|
Override the bin installation directory
|
|
|
|
-a, --arch
|
|
Override the architecture identified by the installer
|
|
|
|
-B, --base-url
|
|
Override the base URL used for downloading releases
|
|
|
|
-r, --remove
|
|
Uninstall railpack
|
|
|
|
-h, --help
|
|
Get some help
|
|
|
|
"
|
|
|
|
set -eu
|
|
printf '\n'
|
|
|
|
BOLD="$(tput bold 2>/dev/null || printf '')"
|
|
GREY="$(tput setaf 0 2>/dev/null || printf '')"
|
|
UNDERLINE="$(tput smul 2>/dev/null || printf '')"
|
|
RED="$(tput setaf 1 2>/dev/null || printf '')"
|
|
GREEN="$(tput setaf 2 2>/dev/null || printf '')"
|
|
YELLOW="$(tput setaf 3 2>/dev/null || printf '')"
|
|
BLUE="$(tput setaf 4 2>/dev/null || printf '')"
|
|
MAGENTA="$(tput setaf 5 2>/dev/null || printf '')"
|
|
NO_COLOR="$(tput sgr0 2>/dev/null || printf '')"
|
|
|
|
|
|
SUPPORTED_TARGETS="x86_64-apple-darwin arm64-apple-darwin \
|
|
x86_64-unknown-linux-musl arm64-unknown-linux-musl \
|
|
x86_64-pc-windows-msvc arm64-pc-windows-msvc"
|
|
|
|
CURL_RETRY_OPTS="--retry 3 --retry-all-errors --retry-delay 2"
|
|
|
|
info() {
|
|
printf '%s\n' "${BOLD}${GREY}>${NO_COLOR} $*"
|
|
}
|
|
|
|
debug() {
|
|
if [[ -n "${VERBOSE}" ]]; then
|
|
printf '%s\n' "${BOLD}${GREY}>${NO_COLOR} $*"
|
|
fi
|
|
}
|
|
|
|
warn() {
|
|
printf '%s\n' "${YELLOW}! $*${NO_COLOR}"
|
|
}
|
|
|
|
error() {
|
|
printf '%s\n' "${RED}x $*${NO_COLOR}" >&2
|
|
}
|
|
|
|
completed() {
|
|
printf '%s\n' "${GREEN}✓${NO_COLOR} $*"
|
|
}
|
|
|
|
has() {
|
|
command -v "$1" 1>/dev/null 2>&1
|
|
}
|
|
|
|
get_tmpfile() {
|
|
local suffix
|
|
suffix="$1"
|
|
if has mktemp; then
|
|
printf "%s%s.%s.%s" "$(mktemp)" "-railpack" "$(date +%s)" "${suffix}"
|
|
else
|
|
printf "/tmp/railpack.%s" "${suffix}"
|
|
fi
|
|
}
|
|
|
|
# Test if a location is writeable by trying to write to it. Windows does not let
|
|
# you test writeability other than by writing: https://stackoverflow.com/q/1999988
|
|
test_writeable() {
|
|
local path
|
|
path="${1:-}/test.txt"
|
|
if touch "${path}" 2>/dev/null; then
|
|
rm "${path}"
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
download() {
|
|
file="$1"
|
|
url="$2"
|
|
touch "$file"
|
|
|
|
if has curl; then
|
|
cmd="curl --fail --silent --location ${CURL_RETRY_OPTS} --output $file $url"
|
|
elif has wget; then
|
|
cmd="wget --quiet --output-document=$file $url"
|
|
elif has fetch; then
|
|
cmd="fetch --quiet --output=$file $url"
|
|
else
|
|
error "No HTTP download program (curl, wget, fetch) found, exiting…"
|
|
return 1
|
|
fi
|
|
|
|
$cmd && return 0 || rc=$?
|
|
|
|
error "Command failed (exit code $rc): ${BLUE}${cmd}${NO_COLOR}"
|
|
printf "\n" >&2
|
|
info "This is likely due to railpack not yet supporting your configuration."
|
|
info "If you would like to see a build for your configuration,"
|
|
info "please create an issue requesting a build for ${MAGENTA}${TARGET}${NO_COLOR}:"
|
|
info "${BOLD}${UNDERLINE}${REPO_URL}/issues/new/${NO_COLOR}"
|
|
return $rc
|
|
}
|
|
|
|
unpack() {
|
|
local archive=$1
|
|
local bin_dir=$2
|
|
local sudo=${3-}
|
|
|
|
case "$archive" in
|
|
*.tar.gz)
|
|
flags=$(test -n)
|
|
${sudo} tar "${flags}" -xzf "${archive}" -C "${bin_dir}"
|
|
return 0
|
|
;;
|
|
*.zip)
|
|
flags=$(test -z)
|
|
UNZIP="${flags}" ${sudo} unzip "${archive}" -d "${bin_dir}"
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
error "Unknown package extension."
|
|
printf "\n"
|
|
info "This almost certainly results from a bug in this script--please file a"
|
|
info "bug report at ${REPO_URL}/issues"
|
|
return 1
|
|
}
|
|
|
|
elevate_priv() {
|
|
if ! has sudo; then
|
|
error 'Could not find the command "sudo", needed to get permissions for install.'
|
|
info "If you are on Windows, please run your shell as an administrator, then"
|
|
info "rerun this script. Otherwise, please run this script as root, or install"
|
|
info "sudo."
|
|
exit 1
|
|
fi
|
|
if ! sudo -v; then
|
|
error "Superuser not granted, aborting installation"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
install() {
|
|
local msg
|
|
local sudo
|
|
local archive
|
|
local ext="$1"
|
|
|
|
if test_writeable "${BIN_DIR}"; then
|
|
sudo=""
|
|
msg="Installing railpack, please wait…"
|
|
else
|
|
warn "Escalated permissions are required to install to ${BIN_DIR}"
|
|
elevate_priv
|
|
sudo="sudo"
|
|
msg="Installing railpack as root, please wait…"
|
|
fi
|
|
info "$msg"
|
|
|
|
archive=$(get_tmpfile "$ext")
|
|
|
|
# download to the temp file
|
|
download "${archive}" "${URL}"
|
|
|
|
# unpack the temp file to the bin dir, using sudo if required
|
|
unpack "${archive}" "${BIN_DIR}" "${sudo}"
|
|
|
|
# remove tempfile
|
|
# rm "${archive}"
|
|
}
|
|
|
|
# Simplify platform detection
|
|
detect_platform() {
|
|
local platform
|
|
platform="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
|
|
|
case "${platform}" in
|
|
msys_nt*|cygwin_nt*|mingw*) platform="pc-windows-msvc" ;;
|
|
linux) platform="unknown-linux-musl" ;;
|
|
darwin) platform="apple-darwin" ;;
|
|
esac
|
|
|
|
printf '%s' "${platform}"
|
|
}
|
|
|
|
detect_arch() {
|
|
local arch
|
|
arch="$(uname -m | tr '[:upper:]' '[:lower:]')"
|
|
|
|
case "${arch}" in
|
|
amd64|x86_64) printf 'x86_64' ;;
|
|
arm64|aarch64) printf 'arm64' ;;
|
|
*) printf 'x86_64' ;;
|
|
esac
|
|
}
|
|
|
|
detect_target() {
|
|
local arch="$1"
|
|
local platform="$2"
|
|
local target="$arch-$platform"
|
|
|
|
if [ "${target}" = "arm-unknown-linux-musl" ]; then
|
|
target="${target}eabihf"
|
|
fi
|
|
|
|
printf '%s' "${target}"
|
|
}
|
|
|
|
|
|
confirm() {
|
|
if [ -t 0 ]; then
|
|
if [ -z "${FORCE-}" ]; then
|
|
printf "%s " "${MAGENTA}?${NO_COLOR} $* ${BOLD}[y/N]${NO_COLOR}"
|
|
set +e
|
|
read -r yn </dev/tty
|
|
rc=$?
|
|
set -e
|
|
if [ $rc -ne 0 ]; then
|
|
error "Error reading from prompt (please re-run with the '--yes' option)"
|
|
exit 1
|
|
fi
|
|
if [ "$yn" != "y" ] && [ "$yn" != "yes" ]; then
|
|
error 'Aborting (please answer "yes" to continue)'
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
check_bin_dir() {
|
|
local bin_dir="$1"
|
|
|
|
if [ ! -d "$BIN_DIR" ]; then
|
|
error "Installation location $BIN_DIR does not appear to be a directory"
|
|
info "Make sure the location exists and is a directory, then try again."
|
|
exit 1
|
|
fi
|
|
|
|
# https://stackoverflow.com/a/11655875
|
|
local good
|
|
good=$(
|
|
IFS=:
|
|
for path in $PATH; do
|
|
if [ "${path}" = "${bin_dir}" ]; then
|
|
printf 1
|
|
break
|
|
fi
|
|
done
|
|
)
|
|
|
|
if [ "${good}" != "1" ]; then
|
|
warn "Bin directory ${bin_dir} is not in your \$PATH"
|
|
fi
|
|
}
|
|
|
|
is_build_available() {
|
|
local arch="$1"
|
|
local platform="$2"
|
|
local target="$3"
|
|
|
|
local good
|
|
|
|
good=$(
|
|
IFS=" "
|
|
for t in $SUPPORTED_TARGETS; do
|
|
if [ "${t}" = "${target}" ]; then
|
|
printf 1
|
|
break
|
|
fi
|
|
done
|
|
)
|
|
|
|
if [ "${good}" != "1" ]; then
|
|
error "${arch} builds for ${platform} are not yet available for nixpacks"
|
|
printf "\n" >&2
|
|
info "If you would like to see a build for your configuration,"
|
|
info "please create an issue requesting a build for ${MAGENTA}${target}${NO_COLOR}:"
|
|
info "${BOLD}${UNDERLINE}${REPO_URL}/issues/new/${NO_COLOR}"
|
|
printf "\n"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
UNINSTALL=0
|
|
HELP=0
|
|
|
|
# defaults
|
|
if [ -z "${RAILPACK_VERSION-}" ]; then
|
|
RAILPACK_VERSION=$(curl --fail --silent --show-error ${CURL_RETRY_OPTS} ${GITHUB_TOKEN:+-H "Authorization: Bearer $GITHUB_TOKEN"} "https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/releases/latest" | grep -o '"tag_name": "v.*"' | cut -d'"' -f4 | cut -c2-)
|
|
|
|
if [ -z "${RAILPACK_VERSION}" ]; then
|
|
error "Failed to detect latest version from GitHub API"
|
|
info "You can set RAILPACK_VERSION=x.y.z to specify a version manually"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if [ -z "${RAILPACK_PLATFORM-}" ]; then
|
|
PLATFORM="$(detect_platform)"
|
|
fi
|
|
|
|
if [ -z "${RAILPACK_BIN_DIR-}" ]; then
|
|
BIN_DIR=/usr/local/bin
|
|
fi
|
|
|
|
if [ -z "${RAILPACK_ARCH-}" ]; then
|
|
ARCH="$(detect_arch)"
|
|
fi
|
|
|
|
if [ -z "${RAILPACK_BASE_URL-}" ]; then
|
|
BASE_URL="${REPO_URL}/releases"
|
|
fi
|
|
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
-p | --platform)
|
|
PLATFORM="$2"
|
|
shift 2
|
|
;;
|
|
-b | --bin-dir)
|
|
BIN_DIR="$2"
|
|
shift 2
|
|
;;
|
|
-a | --arch)
|
|
ARCH="$2"
|
|
shift 2
|
|
;;
|
|
-B | --base-url)
|
|
BASE_URL="$2"
|
|
shift 2
|
|
;;
|
|
|
|
-V | --verbose)
|
|
VERBOSE=1
|
|
shift 1
|
|
;;
|
|
-f | -y | --force | --yes)
|
|
FORCE=1
|
|
shift 1
|
|
;;
|
|
-r | --remove | --uninstall)
|
|
UNINSTALL=1
|
|
shift 1
|
|
;;
|
|
-h | --help)
|
|
HELP=1
|
|
shift 1
|
|
;;
|
|
-p=* | --platform=*)
|
|
PLATFORM="${1#*=}"
|
|
shift 1
|
|
;;
|
|
-b=* | --bin-dir=*)
|
|
BIN_DIR="${1#*=}"
|
|
shift 1
|
|
;;
|
|
-a=* | --arch=*)
|
|
ARCH="${1#*=}"
|
|
shift 1
|
|
;;
|
|
-B=* | --base-url=*)
|
|
BASE_URL="${1#*=}"
|
|
shift 1
|
|
;;
|
|
-V=* | --verbose=*)
|
|
VERBOSE="${1#*=}"
|
|
shift 1
|
|
;;
|
|
-f=* | -y=* | --force=* | --yes=*)
|
|
FORCE="${1#*=}"
|
|
shift 1
|
|
;;
|
|
|
|
*)
|
|
error "Unknown option: $1"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ -n "${VERBOSE-}" ]; then
|
|
VERBOSE=v
|
|
else
|
|
VERBOSE=
|
|
fi
|
|
|
|
if [ $UNINSTALL == 1 ]; then
|
|
confirm "Are you sure you want to uninstall railpack?"
|
|
|
|
msg=""
|
|
sudo=""
|
|
|
|
if test_writeable "$(dirname "$(which ${BINARY_NAME})")"; then
|
|
sudo=""
|
|
msg="Removing railpack, please wait…"
|
|
else
|
|
warn "Escalated permissions are required to install to ${BIN_DIR}"
|
|
elevate_priv
|
|
sudo="sudo"
|
|
msg="Removing railpack as root, please wait…"
|
|
fi
|
|
|
|
info "$msg"
|
|
${sudo} rm -f "$(which ${BINARY_NAME})"
|
|
${sudo} rm -rf /tmp/${BINARY_NAME}
|
|
|
|
info "Removed railpack"
|
|
exit 0
|
|
fi
|
|
|
|
if [ $HELP == 1 ]; then
|
|
echo "${help_text}"
|
|
exit 0
|
|
fi
|
|
TARGET="$(detect_target "${ARCH}" "${PLATFORM}")"
|
|
|
|
is_build_available "${ARCH}" "${PLATFORM}" "${TARGET}"
|
|
|
|
print_configuration () {
|
|
if [[ -n "${VERBOSE}" ]]; then
|
|
printf " %s\n" "${UNDERLINE}Configuration${NO_COLOR}"
|
|
debug "${BOLD}Bin directory${NO_COLOR}: ${GREEN}${BIN_DIR}${NO_COLOR}"
|
|
debug "${BOLD}Platform${NO_COLOR}: ${GREEN}${PLATFORM}${NO_COLOR}"
|
|
debug "${BOLD}Arch${NO_COLOR}: ${GREEN}${ARCH}${NO_COLOR}"
|
|
debug "${BOLD}Version${NO_COLOR}: ${GREEN}${RAILPACK_VERSION}${NO_COLOR}"
|
|
printf '\n'
|
|
fi
|
|
}
|
|
|
|
print_configuration
|
|
|
|
EXT=tar.gz
|
|
if [ "${PLATFORM}" = "pc-windows-msvc" ]; then
|
|
EXT=zip
|
|
fi
|
|
|
|
URL="${BASE_URL}/download/v${RAILPACK_VERSION}/${REPO_NAME}-v${RAILPACK_VERSION}-${TARGET}.${EXT}"
|
|
debug "Tarball URL: ${UNDERLINE}${BLUE}${URL}${NO_COLOR}"
|
|
confirm "Install railpack ${GREEN}${RAILPACK_VERSION}${NO_COLOR} to ${BOLD}${GREEN}${BIN_DIR}${NO_COLOR}?"
|
|
check_bin_dir "${BIN_DIR}"
|
|
|
|
install "${EXT}"
|
|
|
|
printf "$GREEN"
|
|
cat <<'EOF'
|
|
|
|
____ _ _ _
|
|
| _ \ __ _(_) |_ __ __ _ ___| | __
|
|
| |_) / _` | | | '_ \ / _` |/ __| |/ /
|
|
| _ < (_| | | | |_) | (_| | (__| <
|
|
|_| \_\__,_|_|_| .__/ \__,_|\___|_|\_\
|
|
|_|
|
|
|
|
Railpack is now installed!
|
|
Run 'railpack --help' to get started
|
|
|
|
EOF
|
|
printf "$NO_COLOR"
|