#!/usr/bin/env bash # # cruft installer — https://cruft.sh/install # # curl -fsSL https://cruft.sh/install | bash # curl -fsSL https://cruft.sh/install | bash -s 0.0.10 # pin a version # # Downloads the prebuilt cruft binary for your OS/arch from the npm registry # (the same artifacts `npm i -g cruftjs` uses — the registry is a plain HTTPS # host, so this needs only curl + tar, not node/npm) and installs it to # ~/.cruft/bin. Override the location with CRUFT_INSTALL. set -euo pipefail platform=$(uname -ms) # On Windows outside a MINGW bash, hand off to the PowerShell installer. if [[ ${OS:-} = Windows_NT ]]; then if [[ $platform != MINGW64* ]]; then powershell -c "irm cruft.sh/install.ps1|iex" exit $? fi fi # ── colors (only when stdout is a tty) ─────────────────────────────────────── Color_Off=''; Red=''; Green=''; Dim=''; Bold_White=''; Bold_Green='' if [[ -t 1 ]]; then Color_Off='\033[0m'; Red='\033[0;31m'; Green='\033[0;32m'; Dim='\033[0;2m' Bold_Green='\033[1;32m'; Bold_White='\033[1m' fi error() { echo -e "${Red}error${Color_Off}:" "$@" >&2; exit 1; } info() { echo -e "${Dim}$@ ${Color_Off}"; } info_bold() { echo -e "${Bold_White}$@ ${Color_Off}"; } success() { echo -e "${Green}$@ ${Color_Off}"; } command -v curl >/dev/null || error 'curl is required to install cruft' command -v tar >/dev/null || error 'tar is required to install cruft' if [[ $# -gt 1 ]]; then error 'Too many arguments. Only one is allowed: a cruft version to install (e.g. "0.0.10").' fi # ── resolve target (npm platform-package suffix) ───────────────────────────── case $platform in 'Darwin x86_64') target=darwin-x64 ;; 'Darwin arm64') target=darwin-arm64 ;; 'Linux aarch64' | 'Linux arm64') target=linux-arm64 ;; 'Linux x86_64') target=linux-x64 ;; 'MINGW64'*) target=win32-x64 ;; 'Linux riscv64') error 'cruft is not yet available for linux riscv64' ;; *) target=linux-x64 ;; esac # Rosetta: a darwin-x64 shell on Apple Silicon should take the native binary. if [[ $target = darwin-x64 ]]; then if [[ $(sysctl -n sysctl.proc_translated 2>/dev/null || echo 0) = 1 ]]; then target=darwin-arm64 info "Your shell is running under Rosetta 2; installing cruft for $target instead." fi fi # cruft's linux binary is glibc-only; there is no musl build yet. if [[ $target = linux-* && -f /etc/alpine-release ]]; then error 'cruft has no musl (Alpine) build yet. A glibc-based image is required.' fi exe_name=cruft [[ $target = win32-* ]] && exe_name=cruft.exe # ── resolve the version + tarball from the npm registry ────────────────────── registry=${CRUFT_NPM_REGISTRY:-https://registry.npmjs.org} pkg="@cruftless-dev/cruft-$target" req_version=${1:-latest} req_version=${req_version#v} # accept "v0.0.10" or "0.0.10" meta=$(curl -fsL "$registry/$pkg/$req_version" 2>/dev/null) || error "No cruft release found for $pkg@$req_version (check the version, or your network)." tarball=$(printf '%s' "$meta" | grep -o '"tarball":"[^"]*"' | head -1 | sed 's/.*"tarball":"//; s/"$//') version=$(printf '%s' "$meta" | sed -n 's/.*"version":"\([^"]*\)".*/\1/p' | head -1) [[ -n $tarball ]] || error "No prebuilt cruft binary found for $target (version $req_version)." # ── download + extract ─────────────────────────────────────────────────────── install_dir=${CRUFT_INSTALL:-$HOME/.cruft} bin_dir=$install_dir/bin exe=$bin_dir/cruft mkdir -p "$bin_dir" || error "Failed to create install directory \"$bin_dir\"" tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT curl --fail --location --progress-bar --output "$tmp/cruft.tgz" "$tarball" || error "Failed to download cruft from \"$tarball\"" tar -xzf "$tmp/cruft.tgz" -C "$tmp" || error 'Failed to extract the cruft archive' [[ -f "$tmp/package/$exe_name" ]] || error "Archive did not contain the expected binary ($exe_name)" mv "$tmp/package/$exe_name" "$exe" || error 'Failed to install the cruft binary' chmod +x "$exe" || error 'Failed to set permissions on the cruft binary' tildify() { if [[ $1 = $HOME/* ]]; then echo "~/${1#"$HOME"/}"; else echo "$1"; fi } success "cruft $version was installed successfully to $Bold_Green$(tildify "$exe")" if command -v cruft >/dev/null && [[ "$(command -v cruft)" = "$exe" ]]; then echo "Run 'cruft --help' to get started" exit fi # ── wire up PATH for the user's shell (mirrors the bun installer) ──────────── refresh_command='' tilde_bin_dir=$(tildify "$bin_dir") quoted_install_dir="\"${install_dir//\"/\\\"}\"" [[ $quoted_install_dir = \"$HOME/* ]] && quoted_install_dir=${quoted_install_dir/$HOME\//\$HOME/} echo case $(basename "${SHELL:-}") in fish) commands=( "set --export CRUFT_INSTALL $quoted_install_dir" "set --export PATH \$CRUFT_INSTALL/bin \$PATH" ) config=$HOME/.config/fish/config.fish ;; zsh) commands=( "export CRUFT_INSTALL=$quoted_install_dir" "export PATH=\"\$CRUFT_INSTALL/bin:\$PATH\"" ) config=$HOME/.zshrc ;; bash) commands=( "export CRUFT_INSTALL=$quoted_install_dir" "export PATH=\"\$CRUFT_INSTALL/bin:\$PATH\"" ) config=$HOME/.bashrc ;; *) config='' echo 'Manually add cruft to your PATH (in ~/.bashrc or similar):' info_bold " export CRUFT_INSTALL=$quoted_install_dir" info_bold " export PATH=\"\$CRUFT_INSTALL/bin:\$PATH\"" ;; esac if [[ -n $config ]]; then tilde_config=$(tildify "$config") if [[ -w $config ]] || [[ ! -e $config && -w $(dirname "$config") ]]; then { echo -e '\n# cruft' for c in "${commands[@]}"; do echo "$c"; done } >>"$config" info "Added \"$tilde_bin_dir\" to \$PATH in \"$tilde_config\"" refresh_command="source $tilde_config" else echo "Manually add the directory to $tilde_config (or similar):" for c in "${commands[@]}"; do info_bold " $c"; done fi fi echo info "To get started, run:" echo [[ -n $refresh_command ]] && info_bold " $refresh_command" info_bold " cruft --help"