Skip to main content
Glama
install.sh15.4 kB
#!/usr/bin/env sh # shellcheck shell=sh disable=SC3043 set -eu print_usage() { local program bin default_dest default_platform program="$1" bin="$2" default_dest="$3" default_platform="$4" cat <<-EOF $program Installs a binary release of $bin for supported platforms USAGE: $program [OPTIONS] [--] OPTIONS: -h, --help Prints help information -d, --destination=<DEST> Destination directory for installation [default: $default_dest] -p, --platform=<PLATFORM> Platform type to install [examples: linux-x86_64, linux-aarch64, darwin-x86_64, darwin-aarch64] [default: $default_platform] -V, --version=<VERSION> Release version to install [examples: stable, 20250218.210911.0-sha.bda1ce6ea] [default: stable] EXAMPLES: # Installs the latest release into \`\$HOME/bin\` $program # Installs the latest release for all users under \`/usr/local/bin\` sudo $program # Installs an old release into a temp directory $program -V 20250214.193652.0-sha.0f9972a53 -d /tmp EOF } main() { if [ -n "${DEBUG:-}" ]; then set -v; fi if [ -n "${TRACE:-}" ]; then set -xv; fi local program bin program="install.sh" bin="si" setup_cleanups setup_traps trap_exit parse_cli_args "$program" "$bin" "$@" local dest os_type cpu_type platform version dest="$DEST" os_type="$OS_TYPE" cpu_type="$CPU_TYPE" platform="$PLATFORM" version="$VERSION" unset DEST OS_TYPE CPU_TYPE PLATFORM VERSION section "Downloading and installing '$bin' release '$version' on '$platform'" local asset_url asset_url="$( asset_url "$bin" "$version" "$os_type" "$cpu_type" "$platform" )" || die "Unsupported platform '$platform' for '$bin' release '$version'" local tmpdir tmpdir="$(mktemp_directory)" cleanup_directory "$tmpdir" local asset asset="$(basename "$asset_url")" download "$asset_url" "$tmpdir/$asset" section "Extracting '$asset'" extract_archive "$tmpdir/$asset" "$tmpdir" "$bin" section "Installing '$bin'" install_bin "$tmpdir/$bin" "$dest/$bin" "$bin" section "Installation of '$bin' release '$version' complete" indent "$dest/$bin" --version } parse_cli_args() { local program bin program="$1" shift bin="$1" shift need_cmd grep need_cmd id need_cmd uname need_cmd tr local os_type cpu_type plat dest os_type="$(uname -s | tr '[:upper:]' '[:lower:]')" cpu_type="$(uname -m | tr '[:upper:]' '[:lower:]')" case "$cpu_type" in amd64 | x64 | x86_64 | x86-64) cpu_type=x86_64 ;; aarch64 | arm64 | arm64v8) cpu_type=aarch64 ;; esac plat="$os_type-$cpu_type" if [ "$(id -u)" -eq 0 ]; then dest="/usr/local/bin" else if echo "$PATH" | tr ':' '\n' | grep -q "^$HOME/.local/bin\$"; then dest="$HOME/.local/bin" elif echo "$PATH" | tr ':' '\n' | grep -q "^$HOME/bin\$"; then dest="$HOME/bin" else dest="$HOME/.$bin/bin" fi fi DEST="$dest" PLATFORM="$plat" VERSION="stable" OPTIND=1 while getopts "d:hp:V:-:" arg; do case "$arg" in d) DEST="$OPTARG" ;; h) print_usage "$program" "$bin" "$dest" "$plat" exit 0 ;; p) PLATFORM="$OPTARG" ;; V) VERSION="$OPTARG" ;; -) long_optarg="${OPTARG#*=}" case "$OPTARG" in destination=?*) DEST="$long_optarg" ;; destination*) print_usage "$program" "$bin" "$dest" "$plat" >&2 die "missing required argument for --$OPTARG option" ;; help) print_usage "$program" "$bin" "$dest" "$plat" exit 0 ;; platform=?*) PLATFORM="$long_optarg" ;; platform*) print_usage "$program" "$bin" "$dest" "$plat" >&2 die "missing required argument for --$OPTARG option" ;; version=?*) VERSION="$long_optarg" ;; version*) print_usage "$program" "$bin" "$dest" "$plat" >&2 die "missing required argument for --$OPTARG option" ;; '') # "--" terminates argument processing break ;; *) print_usage "$program" "$bin" "$dest" "$plat" >&2 die "invalid argument --$OPTARG" ;; esac ;; \?) print_usage "$program" "$bin" "$dest" "$plat" >&2 die "invalid argument; arg=-$OPTARG" ;; esac done shift "$((OPTIND - 1))" case "$PLATFORM" in linux-x86_64 | linux-aarch64 | darwin-x86_64 | darwin-aarch64) ;; *) die "Installation failed, unsupported platform: '$PLATFORM'" ;; esac OS_TYPE="${PLATFORM%%-*}" CPU_TYPE="${PLATFORM#*-}" } asset_url() { local bin version os_type cpu_type platform bin="$1" version="$2" os_type="$3" cpu_type="$4" platform="$5" local type asset_url extension type="binary" extension="tar.gz" asset_url="https://artifacts.systeminit.com/$bin/$version/$type" asset_url="$asset_url/$os_type/$cpu_type/$bin-$version-$type-$platform.$extension" echo "$asset_url" } extract_archive() { local archive dest bin archive="$1" dest="$2" bin="$3" need_cmd tar info_start "Extracting archive" tar -xzf "$archive" -C "$dest" info_end # Verify the binary was extracted if [ ! -f "$dest/$bin" ]; then die "Failed to extract binary '$bin' from archive" fi } remove_macos_quarantine() { local file file="$1" if check_cmd xattr; then info "Removing macOS quarantine attribute from '$file'" # Remove the quarantine attribute - ignore errors if it doesn't exist xattr -d com.apple.quarantine "$file" 2>/dev/null || true else warn "xattr command not found, skipping quarantine attribute removal" warn "You may need to run: xattr -d com.apple.quarantine $file" fi } install_bin() { local src dest bin src="$1" dest="$2" bin="$3" need_cmd dirname need_cmd install need_cmd mkdir info_start "Installing '$dest'" mkdir -p "$(dirname "$dest")" install -p -m 755 "$src" "$dest" info_end # Remove macOS quarantine attribute if on macOS if [ "$(uname -s)" = "Darwin" ]; then remove_macos_quarantine "$dest" fi if [ "$(dirname "$dest")" = "$HOME/.$bin/bin" ]; then symlink_to_system_path "$dest" "$bin" fi } symlink_to_system_path() { local dest bin dest="$1" bin="$2" need_cmd sudo local system_path=/usr/local/bin local prompt="[sudo required to link $bin under $system_path]" prompt="$prompt Password for %u: " info "Symlinking '$dest' to $system_path/$bin" sudo -p "$prompt" ln -snf "$dest" "$system_path/$bin" } trap_exit() { if [ $? -ne 0 ]; then local msg msg="We're sorry, but it looks like something might have gone wrong " msg="$msg during installation." { echo warn "$msg" >&2 warn "If you need help, please join us on our discord!" warn "" warn " https://discord.gg/system-init" } >&2 fi trap_cleanups } # BEGIN: libsh.sh # # Copyright 2019 Fletcher Nichol and/or applicable contributors. # # Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or # http://www.apache.org/licenses/LICENSE-2.0> or the MIT license (see # <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. This # file may not be copied, modified, or distributed except according to those # terms. # # libsh.sh # -------- # project: https://github.com/fnichol/libsh # author: Fletcher Nichol <fnichol@nichol.ca> # version: 0.10.1 # distribution: libsh.full-minified.sh # commit-hash: 46134771903ba66967666ca455f73ffc10dd0a03 # commit-date: 2021-05-08 # artifact: https://github.com/fnichol/libsh/releases/download/v0.10.1/libsh.full.sh # source: https://github.com/fnichol/libsh/tree/v0.10.1 # archive: https://github.com/fnichol/libsh/archive/v0.10.1.tar.gz # if [ -n "${KSH_VERSION:-}" ]; then eval "local() { return 0; }" fi # shellcheck disable=SC2120 mktemp_directory() { need_cmd mktemp if [ -n "${1:-}" ]; then mktemp -d "$1/tmp.XXXXXX" else mktemp -d 2>/dev/null || mktemp -d -t tmp fi } # shellcheck disable=SC2120 mktemp_file() { need_cmd mktemp if [ -n "${1:-}" ]; then mktemp "$1/tmp.XXXXXX" else mktemp 2>/dev/null || mktemp -t tmp fi } trap_cleanup_files() { set +e if [ -n "${__CLEANUP_FILES__:-}" ] && [ -f "$__CLEANUP_FILES__" ]; then local _file while read -r _file; do rm -f "$_file" done <"$__CLEANUP_FILES__" unset _file rm -f "$__CLEANUP_FILES__" fi } need_cmd() { if ! check_cmd "$1"; then die "Required command '$1' not found on PATH" fi } trap_cleanups() { set +e trap_cleanup_directories trap_cleanup_files } print_version() { local _program _version _verbose _sha _long_sha _date _program="$1" _version="$2" _verbose="${3:-false}" _sha="${4:-}" _long_sha="${5:-}" _date="${6:-}" if [ -z "$_sha" ] || [ -z "$_long_sha" ] || [ -z "$_date" ]; then if check_cmd git \ && git rev-parse --is-inside-work-tree >/dev/null 2>&1; then if [ -z "$_sha" ]; then _sha="$(git show -s --format=%h)" if ! git diff-index --quiet HEAD --; then _sha="${_sha}-dirty" fi fi if [ -z "$_long_sha" ]; then _long_sha="$(git show -s --format=%H)" case "$_sha" in *-dirty) _long_sha="${_long_sha}-dirty" ;; esac fi if [ -z "$_date" ]; then _date="$(git show -s --format=%ad --date=short)" fi fi fi if [ -n "$_sha" ] && [ -n "$_date" ]; then echo "$_program $_version ($_sha $_date)" else echo "$_program $_version" fi if [ "$_verbose" = "true" ]; then echo "release: $_version" if [ -n "$_long_sha" ]; then echo "commit-hash: $_long_sha" fi if [ -n "$_date" ]; then echo "commit-date: $_date" fi fi unset _program _version _verbose _sha _long_sha _date } warn() { case "${TERM:-}" in *term | alacritty | rxvt | screen | screen-* | tmux | tmux-* | xterm-*) printf -- "\033[1;31;40m!!! \033[1;37;40m%s\033[0m\n" "$1" ;; *) printf -- "!!! %s\n" "$1" ;; esac } section() { case "${TERM:-}" in *term | alacritty | rxvt | screen | screen-* | tmux | tmux-* | xterm-*) printf -- "\033[1;36;40m--- \033[1;37;40m%s\033[0m\n" "$1" ;; *) printf -- "--- %s\n" "$1" ;; esac } setup_cleanup_directories() { if [ "${__CLEANUP_DIRECTORIES_SETUP__:-}" != "$$" ]; then unset __CLEANUP_DIRECTORIES__ __CLEANUP_DIRECTORIES_SETUP__="$$" export __CLEANUP_DIRECTORIES_SETUP__ fi if [ -z "${__CLEANUP_DIRECTORIES__:-}" ]; then __CLEANUP_DIRECTORIES__="$(mktemp_file)" if [ -z "$__CLEANUP_DIRECTORIES__" ]; then return 1 fi export __CLEANUP_DIRECTORIES__ fi } setup_cleanup_files() { if [ "${__CLEANUP_FILES_SETUP__:-}" != "$$" ]; then unset __CLEANUP_FILES__ __CLEANUP_FILES_SETUP__="$$" export __CLEANUP_FILES_SETUP__ fi if [ -z "${__CLEANUP_FILES__:-}" ]; then __CLEANUP_FILES__="$(mktemp_file)" if [ -z "$__CLEANUP_FILES__" ]; then return 1 fi export __CLEANUP_FILES__ fi } setup_cleanups() { setup_cleanup_directories setup_cleanup_files } setup_traps() { local _sig for _sig in HUP INT QUIT ALRM TERM; do trap " $1 trap - $_sig EXIT kill -s $_sig "'"$$"' "$_sig" done if [ -n "${ZSH_VERSION:-}" ]; then eval "zshexit() { eval '$1'; }" else # shellcheck disable=SC2064 trap "$1" EXIT fi unset _sig } trap_cleanup_directories() { set +e if [ -n "${__CLEANUP_DIRECTORIES__:-}" ] \ && [ -f "$__CLEANUP_DIRECTORIES__" ]; then local _dir while read -r _dir; do rm -rf "$_dir" done <"$__CLEANUP_DIRECTORIES__" unset _dir rm -f "$__CLEANUP_DIRECTORIES__" fi } check_cmd() { if ! command -v "$1" >/dev/null 2>&1; then return 1 fi } cleanup_directory() { setup_cleanup_directories echo "$1" >>"$__CLEANUP_DIRECTORIES__" } cleanup_file() { setup_cleanup_files echo "$1" >>"$__CLEANUP_FILES__" } die() { case "${TERM:-}" in *term | alacritty | rxvt | screen | screen-* | tmux | tmux-* | xterm-*) printf -- "\n\033[1;31;40mxxx \033[1;37;40m%s\033[0m\n\n" "$1" >&2 ;; *) printf -- "\nxxx %s\n\n" "$1" >&2 ;; esac exit 1 } download() { local _url _dst _code _orig_flags _url="$1" _dst="$2" need_cmd sed if check_cmd curl; then info "Downloading $_url to $_dst (curl)" _orig_flags="$-" set +e curl -sSfL "$_url" -o "$_dst" _code="$?" set "-$(echo "$_orig_flags" | sed s/s//g)" if [ $_code -eq 0 ]; then unset _url _dst _code _orig_flags return 0 else local _e _e="curl failed to download file, perhaps curl doesn't have" _e="$_e SSL support and/or no CA certificates are present?" warn "$_e" unset _e fi fi if check_cmd wget; then info "Downloading $_url to $_dst (wget)" _orig_flags="$-" set +e wget -q -O "$_dst" "$_url" _code="$?" set "-$(echo "$_orig_flags" | sed s/s//g)" if [ $_code -eq 0 ]; then unset _url _dst _code _orig_flags return 0 else local _e _e="wget failed to download file, perhaps wget doesn't have" _e="$_e SSL support and/or no CA certificates are present?" warn "$_e" unset _e fi fi if check_cmd ftp; then info "Downloading $_url to $_dst (ftp)" _orig_flags="$-" set +e ftp -o "$_dst" "$_url" _code="$?" set "-$(echo "$_orig_flags" | sed s/s//g)" if [ $_code -eq 0 ]; then unset _url _dst _code _orig_flags return 0 else local _e _e="ftp failed to download file, perhaps ftp doesn't have" _e="$_e SSL support and/or no CA certificates are present?" warn "$_e" unset _e fi fi unset _url _dst _code _orig_flags warn "Downloading requires SSL-enabled 'curl', 'wget', or 'ftp' on PATH" return 1 } indent() { local _ecfile _ec _orig_flags need_cmd cat need_cmd rm need_cmd sed _ecfile="$(mktemp_file)" _orig_flags="$-" set +e { "$@" 2>&1 echo "$?" >"$_ecfile" } | sed 's/^/ /' set "-$(echo "$_orig_flags" | sed s/s//g)" _ec="$(cat "$_ecfile")" rm -f "$_ecfile" unset _ecfile _orig_flags return "${_ec:-5}" } info() { case "${TERM:-}" in *term | alacritty | rxvt | screen | screen-* | tmux | tmux-* | xterm-*) printf -- "\033[1;36;40m - \033[1;37;40m%s\033[0m\n" "$1" ;; *) printf -- " - %s\n" "$1" ;; esac } info_end() { case "${TERM:-}" in *term | alacritty | rxvt | screen | screen-* | tmux | tmux-* | xterm-*) printf -- "\033[1;37;40m%s\033[0m\n" "done." ;; *) printf -- "%s\n" "done." ;; esac } info_start() { case "${TERM:-}" in *term | alacritty | rxvt | screen | screen-* | tmux | tmux-* | xterm-*) printf -- "\033[1;36;40m - \033[1;37;40m%s ... \033[0m" "$1" ;; *) printf -- " - %s ... " "$1" ;; esac } # END: libsh.sh main "$@"

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server