From 92b0b2fe429ea183ea68666d0edcb04e26371327 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Mon, 6 Nov 2023 01:10:11 -0700 Subject: [PATCH] ref! readable template script --- _webi/curl-pipe-bootstrap.tpl.sh | 549 ++++++++++++------------------- _webi/install-package.tpl.sh | 25 +- 2 files changed, 231 insertions(+), 343 deletions(-) diff --git a/_webi/curl-pipe-bootstrap.tpl.sh b/_webi/curl-pipe-bootstrap.tpl.sh index e1a9a78..c2ae9ca 100644 --- a/_webi/curl-pipe-bootstrap.tpl.sh +++ b/_webi/curl-pipe-bootstrap.tpl.sh @@ -6,354 +6,233 @@ # ############################################################ -#set -x +export WEBI_PKG=webi +export WEBI_HOST=https://webinstall.dev +export WEBI_CHECKSUM=06a7fb9f -__install_webi() { +######################################### +# # +# Display Debug Info in Case of Failure # +# # +######################################### - #WEBI_PKG= - #WEBI_HOST=https://webinstall.dev - export WEBI_HOST +# shellcheck disable=SC2005 +fn_show_welcome() { ( + echo "" + printf "%s %s\n" \ + "$(t_strong 'Welcome to') $(t_stronger 'Webi')$(t_strong '!')" \ + "$(t_dim "- Modern tools, instant installs.")" + echo "We expect your experience to be $(t_em 'absolutely perfect')!" + echo "" + echo " $(t_yellow 'Have a problem?') Please $(t_em 'let us know'):" + echo " $(t_url 'https://github.com/webinstall/webi-installers/issues')" + echo " $(t_dim "(your system is $(t_yellow "$(uname -s)")/$(t_yellow "$(uname -m)") with $(t_yellow "$(fn_get_libc)") & $(t_yellow "$(fn_get_http)"))")" + echo "" + echo " $(t_yellow 'Love it?') Star it!" + echo " $(t_url 'https://github.com/webinstall/webi-installers')" - my_libc='' + sleep 0.2 +); } + +t_strong() { (printf '\e[36m%s\e[39m' "${1}"); } +t_stronger() { (printf '\e[1m\e[32m%s\e[39m\e[22m' "${1}"); } +t_url() { (printf '\e[2m%s\e[22m' "${1}"); } +t_path() { (printf '\e[2m\e[32m%s\e[39m\e[22m' "${1}"); } +t_cmd() { (printf '\e[2m\e[35m%s\e[39m\e[22m' "${1}"); } +t_err() { (printf '\e[31m%s\e[39m' "${1}"); } + +t_bold() { (printf '\e[1m%s\e[22m' "${1}"); } +t_dim() { (printf '\e[2m%s\e[22m' "${1}"); } +t_em() { (printf '\e[3m%s\e[23m' "${1}"); } +t_under() { (printf '\e[4m%s\e[24m' "${1}"); } +t_green() { (printf '\e[32m%s\e[39m' "${1}"); } +t_yellow() { (printf '\e[33m%s\e[39m' "${1}"); } +t_magenta() { (printf '\e[35m%s\e[39m' "${1}"); } +t_cyan() { (printf '\e[36m%s\e[39m' "${1}"); } + +fn_get_libc() { ( + # Ex: + # musl + # libc if ldd /bin/ls 2> /dev/null | grep -q 'musl' 2> /dev/null; then - my_libc='musl' + echo 'musl' elif uname -o | grep -q 'GNU' || uname -s | grep -q 'Linux'; then - my_libc='gnu' + echo 'gnu' else - my_libc='libc' + echo 'libc' + fi +); } + +fn_get_http() { ( + # Ex: + # curl + # curl+wget + b_client="" + if command -v curl > /dev/null; then + b_client="curl" + fi + if command -v wget > /dev/null; then + if test -z "${b_client}"; then + b_client="wget" + else + b_client="curl+wget" + fi fi - if test -z "$WEBI_WELCOME"; then - echo "" - printf "Thanks for using webi to install '\e[32m%s\e[0m' on '\e[33m%s (%s) %s\e[0m'.\n" "${WEBI_PKG:-"Unknown Package"}" "$(uname -s)" "${my_libc:-"Unknown Libc"}" "$(uname -m)" - echo "Have a problem? Experience a bug? Please let us know:" - printf " \e[2m\e[36mhttps://github.com/webinstall/webi-installers/issues\e[0m\n" - echo "" - printf "\e[35mLovin'\e[0m it? Say thanks with a \e[1m\e[33mStar on GitHub\e[0m:\n" - printf " \e[36mhttps://github.com/webinstall/webi-installers\e[0m\n" - echo "" + echo "${b_client}" +); } + +################################### +# # +# Detect HTTP Client # +# # +################################### + +fn_wget() { ( + # Doc: + # Downloads the file at the given url to the given path + a_url="${1}" + a_path="${2}" + + cmd_wget="wget -q --user-agent" + if fn_is_interactive; then + cmd_wget="wget -q --show-progress --user-agent" fi - WEBI_WELCOME=true - export WEBI_WELCOME + b_triple_ua="$(fn_get_target_triple_user_agent)" + b_agent="webi/wget ${b_triple_ua}" + if command -v curl > /dev/null; then + b_agent="webi/wget+curl ${b_triple_ua}" + fi - set -e - set -u + if ! $cmd_wget "${b_agent}" -c "${a_url}" -O "${a_path}"; then + echo >&2 " $(t_err "failed to download (wget)") '$(t_url "${a_url}")'" + return 1 + fi +); } - mkdir -p "$HOME/.local/bin" +fn_curl() { ( + # Doc: + # Downloads the file at the given url to the given path + a_url="${1}" + a_path="${2}" - cat << EOF > "$HOME/.local/bin/webi" -#!/bin/sh + cmd_curl="curl --fail-with-body -sSL -#" + if fn_is_interactive; then + cmd_curl="curl --fail-with-body sSL" + fi + + b_triple_ua="$(fn_get_target_triple_user_agent)" + b_agent="webi/curl ${b_triple_ua}" + if command -v wget > /dev/null; then + b_agent="webi/curl+wget ${b_triple_ua}" + fi + + if ! $cmd_curl -A "${b_agent}" "${a_url}" -o "${a_path}"; then + echo >&2 " $(t_err "failed to download (curl)") '$(t_url "${a_url}")'" + return 1 + fi +); } + +fn_is_interactive() { + # Ex: + # himBH + # hBc + case $- in + *i*) return 0 ;; + *) return 1 ;; + esac +} + +fn_get_target_triple_user_agent() { ( + # Ex: + # x86_64/unknown Linux/5.15.107-2-pve gnu + # arm64/unknown Darwin/22.6.0 libc + echo "$(uname -m)/unknown $(uname -s)/$(uname -r) $(fn_get_libc)" +); } + +fn_download_to_path() { ( + a_url="${1}" + a_path="${2}" + + if command -v wget > /dev/null; then + fn_wget "${a_url}" "${a_path}.part" + elif command -v curl > /dev/null; then + fn_curl "${a_url}" "${a_path}.part" + else + echo >&2 " $(t_err "failed to detect HTTP client (curl, wget)")" + return 1 + fi + mv "${a_path}.part" "${a_path}" +); } + +############################################## +# # +# Install or Update Webi and Install Package # +# # +############################################## + +webi_upgrade() { ( + a_path="${1}" + + echo "" + echo "$(t_strong 'Bootstrapping') $(t_stronger 'Webi')" + + b_path_rel="$(fn_sub_home "${a_path}")" + b_checksum="" + if test -r "${a_path}"; then + echo " $(t_dim 'Found') $(t_path "${b_path_rel}")" + b_checksum="$(fn_checksum "${a_path}")" + fi + if test "$b_checksum" == "${WEBI_CHECKSUM}"; then + sleep 0.1 + return 0 + fi + + b_webi_file_url="${WEBI_HOST}/packages/webi/webi.sh" + if test -r "${a_path}"; then + echo " Updating $(t_path "${b_path_rel}")" + fi + echo " Downloading $(t_url "${b_webi_file_url}")" + echo " to $(t_path "${b_path_rel}")" + fn_download_to_path "${b_webi_file_url}" "${a_path}" + chmod u+x "${a_path}" +); } + +fn_checksum() { + a_filepath="${1}" + + cmd_shasum='sha1sum' + if command -v shasum > /dev/null; then + cmd_shasum='shasum' + fi + + $cmd_shasum "${a_filepath}" | cut -d' ' -f1 | cut -c 1-8 +} + +fn_sub_home() { ( + my_rel=${HOME} + my_abs=${1} + echo "${my_abs}" | sed "s:^${my_rel}:~:" +); } + +main() { ( + fn_show_welcome + export WEBI_WELCOME=true + + # note: we may support custom locations in the future + export WEBI_HOME="${HOME}/.local" + b_home="$(fn_sub_home "${WEBI_HOME}")" + b_webi_path="${WEBI_HOME}/bin/webi" + b_webi_path_rel="${b_home}/bin/webi" + webi_upgrade "${b_webi_path}" + + echo "" + echo "$(t_strong 'Installing') $(t_stronger "${WEBI_PKG}") $(t_strong '...')" + echo " Running $(t_cmd "${b_webi_path_rel} ${WEBI_PKG}")" + "${b_webi_path}" "${WEBI_PKG}" +); } set -e set -u -#set -x - -__webi_main() { - - my_date="\$(date +%F_%H-%M-%S)" - export WEBI_TIMESTAMP="\${my_date}" - export _webi_tmp="\${_webi_tmp:-\$( - mktemp -d -t "webi-\$WEBI_TIMESTAMP.XXXXXXXX" - )}" - - if [ -n "\${_WEBI_PARENT:-}" ]; then - export _WEBI_CHILD=true - else - export _WEBI_CHILD= - fi - export _WEBI_PARENT=true - - my_os="\$(uname -s)" - my_arch="\$(uname -m)" - - ## - ## Detect acceptable package formats - ## - - my_ext="" - set +e - # NOTE: the order here is least favorable to most favorable - if [ -n "\$(command -v pkgutil)" ]; then - my_ext="pkg,\$my_ext" - fi - # disable this check for the sake of building the macOS installer on Linux - #if [ -n "\$(command -v diskutil)" ]; then - # note: could also detect via hdiutil - my_ext="dmg,\$my_ext" - #fi - if [ -n "\$(command -v git)" ]; then - my_ext="git,\$my_ext" - fi - if [ -n "\$(command -v unxz)" ]; then - my_ext="xz,\$my_ext" - fi - if [ -n "\$(command -v unzip)" ]; then - my_ext="zip,\$my_ext" - fi - # for mac/linux 'exe' refers to the uncompressed binary without extension - my_ext="exe,\$my_ext" - if [ -n "\$(command -v tar)" ]; then - my_ext="tar,\$my_ext" - fi - my_ext="\$(echo "\$my_ext" | sed 's/,$//')" # nix trailing comma - set -e - - - ## - ## Detect http client - ## - - set +e - WEBI_CURL="\$(command -v curl)" - export WEBI_URL - WEBI_WGET="\$(command -v wget)" - export WEBI_WGET - set -e - - my_libc='' - if ldd /bin/ls 2> /dev/null | grep -q 'musl' 2> /dev/null; then - my_libc='musl' - elif uname -o | grep -q 'GNU' || uname -s | grep -q 'Linux'; then - my_libc='gnu' - else - my_libc='libc' - fi - - export WEBI_HOST="\${WEBI_HOST:-https://webinstall.dev}" - - # ex: Darwin or Linux - my_sys="\$(uname -s)" - # ex: 22.6.0 - my_rev="\$(uname -r)" - # ex: arm64 - my_machine="\$(uname -m)" - - export WEBI_UA="\${my_sys}/\${my_rev} \${my_machine}/unknown \${my_libc}" - - webinstall() { - - my_package="\${1:-}" - if [ -z "\$my_package" ]; then - echo >&2 "Usage: webi @ ..." - echo >&2 "Example: webi node@lts rg" - exit 1 - fi - - WEBI_BOOT="\$( - mktemp -d -t "\$my_package-bootstrap.\$WEBI_TIMESTAMP.XXXXXXXX" - )" - export WEBI_BOOT - - my_installer_url="\$WEBI_HOST/api/installers/\$my_package.sh?formats=\$my_ext" - if [ -n "\$WEBI_CURL" ]; then - if ! curl -fsSL "\$my_installer_url" -H "User-Agent: curl \$WEBI_UA" \\ - -o "\$WEBI_BOOT/\$my_package-bootstrap.sh"; then - echo >&2 "error fetching '\$my_installer_url'" - exit 1 - fi - else - if ! wget -q "\$my_installer_url" --user-agent="wget \$WEBI_UA" \\ - -O "\$WEBI_BOOT/\$my_package-bootstrap.sh"; then - echo >&2 "error fetching '\$my_installer_url'" - exit 1 - fi - fi - - ( - cd "\$WEBI_BOOT" - sh "\$my_package-bootstrap.sh" - ) - - rm -rf "\$WEBI_BOOT" - - } - - show_path_updates() { - - if test -z "\${_WEBI_CHILD}"; then - if test -f "\$_webi_tmp/.PATH.env"; then - my_paths=\$(sort -u < "\$_webi_tmp/.PATH.env") - if test -n "\$my_paths"; then - printf 'PATH.env updated with:\\n' - printf "%s\\n" "\$my_paths" - printf '\\n' - printf "\\e[1m\\e[35mTO FINISH\\e[0m: copy, paste & run the following command:\\n" - printf "\\n" - printf " \\e[1m\\e[32msource ~/.config/envman/PATH.env\\e[0m\\n" - printf " (newly opened terminal windows will update automatically)\\n" - fi - rm -f "\$_webi_tmp/.PATH.env" - fi - fi - - } - - fn_checksum() { - cmd_shasum='sha1sum' - if command -v shasum > /dev/null; then - cmd_shasum='shasum' - fi - \$cmd_shasum "\${0}" | cut -d' ' -f1 | cut -c 1-8 - } - - version() { - my_checksum="\$( - fn_checksum - )" - my_version=v1.2.0 - printf "\\e[35mwebi\\e[32m %s\\e[0m Copyright 2020+ AJ ONeal\\n" "\${my_version} (\${my_checksum})" - printf " \\e[36mhttps://webinstall.dev/webi\\e[0m\\n" - } - - # show help if no params given or help flags are used - usage() { - echo "" - version - echo "" - - printf "\\e[1mSUMMARY\\e[0m\\n" - echo " Webi is the best way to install the modern developer tools you love." - echo " It's fast, easy-to-remember, and conflict free." - echo "" - printf "\\e[1mUSAGE\\e[0m\\n" - echo " webi [@version] [thing2] ..." - echo "" - printf "\\e[1mUNINSTALL\\e[0m\\n" - echo " Almost everything that is installed with webi is scoped to" - echo " ~/.local/opt/, so you can remove it like so:" - echo "" - echo " rm -rf ~/.local/opt/" - echo " rm -f ~/.local/bin/" - echo "" - echo " Some packages have special uninstall instructions, check" - echo " https://webinstall.dev/ to be sure." - echo "" - printf "\\e[1mOPTIONS\\e[0m\\n" - echo " Generic Program Information" - echo " --help Output a usage message and exit." - echo "" - echo " -V, --version" - echo " Output the version number of webi and exit." - echo "" - echo " Helper Utilities" - echo " --list Show everything webi has to offer." - echo "" - echo " --info " - echo " Show various links and example release." - echo "" - printf "\\e[1mFAQ\\e[0m\\n" - printf " See \\e[34mhttps://webinstall.dev/faq\\e[0m\\n" - echo "" - printf "\\e[1mALWAYS REMEMBER\\e[0m\\n" - echo " Friends don't let friends use brew for simple, modern tools that don't need it." - echo " (and certainly not apt either **shudder**)" - echo "" - } - - if [ \$# -eq 0 ] || echo "\$1" | grep -q -E '^(-V|--version|version)$'; then - version - exit 0 - fi - - if echo "\$1" | grep -q -E '^(-h|--help|help)$'; then - usage "\$@" - exit 0 - fi - - if echo "\$1" | grep -q -E '^(-l|--list|list)$'; then - echo >&2 "[warn] the format of --list output may change" - - # because we don't have sitemap.xml for dev sites yet - my_host="https://webinstall.dev" - my_len="\${#my_host}" - - # 6 because the field will looks like "loc>WEBI_HOST/PKG_NAME" - # and the count is 1-indexed - my_count="\$((my_len + 6))" - - curl -fsS "\${my_host}/sitemap.xml" | - grep -F "\${my_host}" | - cut -d'<' -f2 | - cut -c "\${my_count}"- - - exit 0 - fi - - if echo "\${1}" | grep -q -E '^(--info|info)$'; then - if test -z "\${2}"; then - echo >&2 "Usage: webi --info " - exit 1 - fi - - echo >&2 "[warn] the output of --info is completely half-baked and will change" - my_pkg="\${2}" - # TODO need a way to check that it exists at all (readme, win, lin) - echo "" - echo " Cheat Sheet: \${WEBI_HOST}/\${my_pkg}" - echo " POSIX: curl -sS \${WEBI_HOST}/\${my_pkg} | sh" - echo " Windows: curl.exe -A MS \${WEBI_HOST}/\${my_pkg} | powershell" - echo "Releases (JSON): \${WEBI_HOST}/api/releases/\${my_pkg}.json" - echo " Releases (tsv): \${WEBI_HOST}/api/releases/\${my_pkg}.tab" - echo " (query params): ?channel=stable&limit=10" - echo " &os=\${my_os}&arch=\${my_arch}" - echo " Install Script: \${WEBI_HOST}/api/installers/\${my_pkg}.sh?formats=tar,zip,xz,git,dmg,pkg" - echo " Static Assets: \${WEBI_HOST}/packages/\${my_pkg}/README.md" - echo "" - - # TODO os=linux,macos,windows (limit to tagged releases) - my_releases="\$( - curl -fsS "\${WEBI_HOST}/api/releases/\${my_pkg}.json?channel=stable&limit=1&pretty=true" - )" - - if printf '%s\\n' "\${my_releases}" | grep -q "error"; then - my_releases_beta="\$( - curl -fsS "\${WEBI_HOST}/api/releases/\${my_pkg}.json?&limit=1&pretty=true" - )" - if printf '%s\\n' "\${my_releases_beta}" | grep -q "error"; then - echo >&2 "'\${my_pkg}' is a special case that does not have releases" - else - echo >&2 "ERROR no stable releases for '\${my_pkg}'!" - fi - exit 0 - fi - - echo >&2 "Stable '\${my_pkg}' releases:" - if command -v jq > /dev/null; then - printf '%s\\n' "\${my_releases}" | - jq - else - printf '%s\\n' "\${my_releases}" - fi - - exit 0 - fi - - for pkgname in "\$@"; do - webinstall "\$pkgname" - done - - show_path_updates - -} - -__webi_main "\$@" - -EOF - - chmod a+x "$HOME/.local/bin/webi" - - if [ -n "${WEBI_PKG-}" ]; then - "$HOME/.local/bin/webi" "${WEBI_PKG}" - else - echo "" - echo "Hmm... no WEBI_PKG was specified. This is probably an error in the script." - echo "" - echo "Please open an issue with this information: Package '${WEBI_PKG-}' on '$(uname -s)/$(uname -r) $(uname -m)'" - echo " https://github.com/webinstall/packages/issues" - echo "" - fi - -} - -__install_webi +main diff --git a/_webi/install-package.tpl.sh b/_webi/install-package.tpl.sh index 2a7d9f3..8aac40d 100644 --- a/_webi/install-package.tpl.sh +++ b/_webi/install-package.tpl.sh @@ -14,6 +14,7 @@ __bootstrap_webi() { else my_libc='libc' fi + WEBI_UA="$(uname -s)/$(uname -r) $(uname -m)/unknown ${my_libc}" #WEBI_PKG= #PKG_NAME= @@ -67,6 +68,20 @@ __bootstrap_webi() { mkdir -p "$HOME/.local/bin" mkdir -p "$HOME/.local/opt" + if test -e ~/.local/bin; then + echo "Found ~/.local/bin" + else + echo "Creating ~/.local/bin" + mkdir -p "$HOME/.local/bin" + fi + + if test -e ~/.local/bin/webi; then + echo "Found ~/.local/bin/webi" + else + echo "Creating ~/.local/bin" + mkdir -p "$HOME/.local/bin" + fi + ## ## Detect http client ## @@ -192,14 +207,8 @@ __bootstrap_webi() { is_interactive_shell() { # $- shows shell flags (error,unset,interactive,etc) case $- in - *i*) - # true - return 0 - ;; - *) - # false - return 1 - ;; + *i*) return 0 ;; + *) return 1 ;; esac }