-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add install script * . * . * Apply suggestions from code review --------- Co-authored-by: Matt Johnson-Pint <[email protected]>
- Loading branch information
1 parent
203de59
commit eed085e
Showing
1 changed file
with
291 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,291 @@ | ||
#!/usr/bin/env bash | ||
|
||
# Copyright 2024 Hypermode Inc. | ||
# Licensed under the terms of the Apache License, Version 2.0 | ||
# See the LICENSE file that accompanied this code for further details. | ||
# | ||
# SPDX-FileCopyrightText: 2024 Hypermode Inc. <[email protected]> | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
# Run with: curl install.hypermode.com/hyp.sh -sSfL | bash | ||
|
||
# Config | ||
CLI_NAME="Hyp CLI" | ||
PACKAGE_ORG="@hypermode" | ||
PACKAGE_NAME="hyp-cli" | ||
INSTALL_DIR="${HYP_CLI:-"$HOME/.hypermode/cli"}" | ||
VERSION="latest" | ||
INSTALLER_VERSION="0.1.1" | ||
|
||
NODE_MIN=22 | ||
NODE_PATH="$(which node)" | ||
NPM_PATH="$(which npm)" | ||
|
||
# Properties | ||
ARCH="$(uname -m)" | ||
OS="$(uname -s)" | ||
|
||
# ANSI escape codes | ||
if [[ -t 1 ]]; then | ||
CLEAR_LINE="\e[1A\e[2K\e[2K" | ||
BOLD="\e[1m" | ||
BLUE="\e[34;1m" | ||
YELLOW="\e[33m" | ||
RED="\e[31m" | ||
DIM="\e[2m" | ||
RESET="\e[0m" | ||
else | ||
CLEAR_LINE="" | ||
BOLD="" | ||
BLUE="" | ||
YELLOW="" | ||
RED="" | ||
DIM="" | ||
RESET="" | ||
fi | ||
|
||
get_latest_version() { | ||
local url="https://registry.npmjs.org/${PACKAGE_ORG:+$PACKAGE_ORG/}$PACKAGE_NAME" | ||
|
||
curl --silent "$url" | jq -r '.["dist-tags"].latest' | ||
} | ||
|
||
ARCHIVE_URL="" | ||
download_from_npm() { | ||
local tmpdir="$1" | ||
local url="$2" | ||
local filename="${PACKAGE_NAME}-${VERSION}.tgz" | ||
local download_file="$tmpdir/$filename" | ||
|
||
mkdir -p "$tmpdir" | ||
|
||
curl --progress-bar --show-error --location --fail "$url" --output "$download_file" | ||
if [ "$?" != 0 ]; then | ||
return 1 | ||
fi | ||
|
||
printf "$CLEAR_LINE" >&2 | ||
echo "$download_file" | ||
} | ||
|
||
echo_fexists() { | ||
[ -f "$1" ] && echo "$1" | ||
} | ||
|
||
detect_profile() { | ||
local shellname="$1" | ||
local uname="$2" | ||
|
||
if [ -f "$PROFILE" ]; then | ||
echo "$PROFILE" | ||
return | ||
fi | ||
|
||
case "$shellname" in | ||
bash) | ||
case $uname in | ||
Darwin) | ||
echo_fexists "$HOME/.bash_profile" || echo_fexists "$HOME/.bashrc" | ||
;; | ||
*) | ||
echo_fexists "$HOME/.bashrc" || echo_fexists "$HOME/.bash_profile" | ||
;; | ||
esac | ||
;; | ||
zsh) | ||
echo "$HOME/.zshrc" | ||
;; | ||
fish) | ||
echo "$HOME/.config/fish/config.fish" | ||
;; | ||
*) | ||
local profiles | ||
case $uname in | ||
Darwin) | ||
profiles=(.profile .bash_profile .bashrc .zshrc .config/fish/config.fish) | ||
;; | ||
*) | ||
profiles=(.profile .bashrc .bash_profile .zshrc .config/fish/config.fish) | ||
;; | ||
esac | ||
|
||
for profile in "${profiles[@]}"; do | ||
echo_fexists "$HOME/$profile" && break | ||
done | ||
;; | ||
esac | ||
} | ||
|
||
build_path_str() { | ||
local profile="$1" install_dir="$2" | ||
if [[ $profile == *.fish ]]; then | ||
echo -e "set -gx HYP_CLI \"$install_dir\"\nstring match -r \".hypermode\" \"\$PATH\" > /dev/null; or set -gx PATH \"\$HYP_CLI/bin\" \$PATH" | ||
else | ||
install_dir="${install_dir/#$HOME/\$HOME}" | ||
echo -e "\n# ${CLI_NAME}\nexport HYP_CLI=\"$install_dir\"\nexport PATH=\"\$HYP_CLI/bin:\$PATH\"" | ||
fi | ||
} | ||
|
||
cli_dir_valid() { | ||
if [ -n "${HYP_CLI-}" ] && [ -e "$HYP_CLI" ] && ! [ -d "$HYP_CLI" ]; then | ||
printf "\$HYP_CLI is set but is not a directory ($HYP_CLI).\n" >&2 | ||
printf "Please check your profile scripts and environment.\n" >&2 | ||
exit 1 | ||
fi | ||
return 0 | ||
} | ||
|
||
update_profile() { | ||
local install_dir="$1" | ||
if [[ ":$PATH:" == *":$install_dir:"* ]]; then | ||
printf "[3/4] ${DIM}The ${CLI_NAME} is already in \$PATH${RESET}\n" >&2 | ||
return 0 | ||
fi | ||
|
||
local profile="$(detect_profile $(basename "$SHELL") $(uname -s))" | ||
if [ -z "$profile" ]; then | ||
printf "No user shell profile found.\n" >&2 | ||
return 1 | ||
fi | ||
|
||
export SHOW_RESET_PROFILE=1 | ||
export PROFILE="~/$(basename "$profile")" | ||
|
||
if grep -q 'HYP_CLI' "$profile"; then | ||
printf "[3/4] ${DIM}The ${CLI_NAME} has already been configured in ${PROFILE}${RESET}\n" >&2 | ||
return 0 | ||
fi | ||
|
||
local path_str="$(build_path_str "$profile" "$install_dir")" | ||
echo "$path_str" >>"$profile" | ||
|
||
printf "[3/4] ${DIM}Added the ${CLI_NAME} to the PATH in ${PROFILE}${RESET}\n" >&2 | ||
} | ||
|
||
install_version() { | ||
if ! cli_dir_valid; then | ||
exit 1 | ||
fi | ||
|
||
case "$VERSION" in | ||
latest) | ||
VERSION="$(get_latest_version)" | ||
;; | ||
*) ;; | ||
esac | ||
|
||
install_release | ||
if [ "$?" == 0 ]; then | ||
update_profile "$INSTALL_DIR" && printf "[4/4] ${DIM}Installed the ${CLI_NAME}${RESET}\n" >&2 | ||
fi | ||
} | ||
|
||
install_release() { | ||
printf "[1/4] ${DIM}Downloading the ${CLI_NAME} from NPM${RESET}\n" | ||
|
||
local url="https://registry.npmjs.org/${PACKAGE_ORG:+$PACKAGE_ORG/}${PACKAGE_NAME}/-/${PACKAGE_NAME}-${VERSION}.tgz" | ||
|
||
download_archive="$( | ||
download_release "$url" | ||
exit "$?" | ||
)" | ||
exit_status="$?" | ||
if [ "$exit_status" != 0 ]; then | ||
printf "Could not download the ${CLI_NAME} version '$VERSION' from\n$url\n" >&2 | ||
exit 1 | ||
fi | ||
|
||
printf "$CLEAR_LINE" >&2 | ||
printf "[1/4] ${DIM}Downloaded latest ${CLI_NAME} v${VERSION}${RESET}\n" >&2 | ||
|
||
install_from_file "$download_archive" | ||
} | ||
|
||
download_release() { | ||
local url="$1" | ||
local download_dir="$(mktemp -d)" | ||
download_from_npm "$download_dir" "$url" | ||
} | ||
|
||
install_from_file() { | ||
local archive="$1" | ||
local extract_to="$(dirname "$archive")" | ||
|
||
printf "[2/4] ${DIM}Unpacking archive${RESET}\n" >&2 | ||
|
||
tar -xf "$archive" -C "$extract_to" | ||
|
||
rm -rf "$INSTALL_DIR" | ||
mkdir -p "$INSTALL_DIR" | ||
rm -f "$archive" | ||
mv "$extract_to/package/"* "$INSTALL_DIR" | ||
rm -rf "$extract_to" | ||
|
||
ln -s "$INSTALL_DIR/bin/run.js" "$INSTALL_DIR/bin/hyp" | ||
|
||
printf "$CLEAR_LINE" >&2 | ||
printf "[2/4] ${DIM}Installing dependencies${RESET}\n" >&2 | ||
(cd "$INSTALL_DIR" && "$NPM_PATH" install --omit=dev --silent && find . -type d -empty -delete) | ||
|
||
printf "$CLEAR_LINE" >&2 | ||
printf "[2/4] ${DIM}Unpacked archive${RESET}\n" >&2 | ||
} | ||
|
||
check_platform() { | ||
case $ARCH in | ||
arm64) ARCH="arm64" ;; | ||
x86_64) ARCH="x64" ;; | ||
*) ;; | ||
esac | ||
|
||
case "$ARCH/$OS" in | ||
x64/Linux | arm64/Linux | x64/Darwin | arm64/Darwin) return 0 ;; | ||
*) | ||
printf "Unsupported os $OS $ARCH\n" >&2 | ||
exit 1 | ||
;; | ||
esac | ||
} | ||
|
||
check_node() { | ||
if [ -z "$NODE_PATH" ]; then | ||
printf "${RED}Node.js is not installed.${RESET}\n" >&2 | ||
printf "${RED}Please install Node.js $NODE_WANTED or later and try again.${RESET}\n" >&2 | ||
exit 1 | ||
fi | ||
|
||
# check node version | ||
local node_version="$("$NODE_PATH" --version)" | ||
local node_major="${node_version%%.*}" | ||
node_major="${node_major#v}" | ||
if [ "$node_major" -lt "$NODE_MIN" ]; then | ||
printf "${RED}Node.js $NODE_MIN or later is required. You have $node_version.${RESET}\n" >&2 | ||
printf "${RED}Please update and try again${RESET}\n" >&2 | ||
exit 1 | ||
fi | ||
|
||
# make sure npm can be found too | ||
if [ -z "$NPM_PATH" ]; then | ||
printf "${RED}npm is not installed. Please install npm and try again.${RESET}\n" >&2 | ||
exit 1 | ||
fi | ||
} | ||
|
||
# This is the entry point | ||
printf "\n${BOLD}${BLUE}${CLI_NAME}${RESET} Installer ${DIM}v${INSTALLER_VERSION}${RESET}\n\n" >&2 | ||
|
||
check_platform | ||
check_node | ||
install_version | ||
|
||
printf "\nThe ${CLI_NAME} has been installed! 🎉\n" >&2 | ||
|
||
if [ -n "${SHOW_RESET_PROFILE-}" ]; then | ||
printf "\n${YELLOW}Please restart your terminal or run:${RESET}\n" >&2 | ||
printf " ${DIM}source ${PROFILE}${RESET}\n" >&2 | ||
printf "\nThen, run ${DIM}hyp${RESET} to get started${RESET}\n" >&2 | ||
else | ||
printf "\nRun ${DIM}hyp${RESET} to get started${RESET}\n" >&2 | ||
fi | ||
|
||
printf "\n" >&2 |