#!/bin/sh # Microsandbox installer # Usage: curl -fsSL https://install.microsandbox.dev | sh set -eu # --------------------------------------------------------------------------- # Constants # --------------------------------------------------------------------------- GITHUB_REPO="superradcompany/microsandbox" INSTALL_DIR="$HOME/.microsandbox" BIN_DIR="$INSTALL_DIR/bin" LIB_DIR="$INSTALL_DIR/lib" # libkrunfw versioned filenames (must match the build) LIBKRUNFW_VERSION="5.2.1" LIBKRUNFW_ABI="5" # Shell config markers MARKER_START="# >>> microsandbox >>>" MARKER_END="# <<< microsandbox <<<" # Progress bar BAR_WIDTH=40 # Colors (disabled if not a terminal) if [ -t 1 ]; then BOLD='\033[1m' DIM='\033[2m' GREEN='\033[0;32m' CYAN='\033[0;36m' RED='\033[0;31m' YELLOW='\033[0;33m' RESET='\033[0m' else BOLD='' DIM='' GREEN='' CYAN='' RED='' YELLOW='' RESET='' fi # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- info() { printf "${BOLD}${CYAN}info${RESET} %s\n" "$1" } success() { printf "${BOLD}${GREEN}done${RESET} %s\n" "$1" } warn() { printf "${BOLD}${YELLOW}warn${RESET} %s\n" "$1" } error() { printf "${BOLD}${RED}error${RESET} %s\n" "$1" >&2 exit 1 } need_cmd() { if ! command -v "$1" > /dev/null 2>&1; then error "required command not found: $1" fi } # --------------------------------------------------------------------------- # Shell configuration # --------------------------------------------------------------------------- detect_current_shell() { _shell_path="${SHELL:-/bin/sh}" case "$(basename "$_shell_path")" in bash) CURRENT_SHELL="bash" ;; zsh) CURRENT_SHELL="zsh" ;; fish) CURRENT_SHELL="fish" ;; *) CURRENT_SHELL="sh" ;; esac } # Update a shell config file idempotently with a marker block. # If the file doesn't exist it is created. If a marker block already # exists it is replaced in-place. Otherwise the block is appended. update_shell_config() { _file=$1 _block=$2 if [ ! -f "$_file" ]; then mkdir -p "$(dirname "$_file")" printf '%s\n' "$_block" > "$_file" return 0 fi # Back up the original file on first modification if [ ! -f "${_file}.pre-microsandbox" ]; then cp -p "$_file" "${_file}.pre-microsandbox" fi if grep -qF "$MARKER_START" "$_file"; then # Replace existing block in-place (ENVIRON avoids awk -v escape issues) _tmp="${_file}.msb_tmp" _MSB_BLOCK="$_block" awk ' BEGIN { block = ENVIRON["_MSB_BLOCK"] } /^# >>> microsandbox >>>/ { if (!done) { print block; done=1 } skip=1; next } /^# <<< microsandbox << "$_tmp" mv "$_tmp" "$_file" else # Append with a leading blank line printf '\n%s\n' "$_block" >> "$_file" fi } # Configure all relevant shell config files with PATH and library path. configure_shell() { detect_current_shell # Build POSIX block (sh, bash, zsh) if [ "$OS" = "linux" ]; then _lib_line='export LD_LIBRARY_PATH="$HOME/.microsandbox/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"' else _lib_line='export DYLD_LIBRARY_PATH="$HOME/.microsandbox/lib${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"' fi _path_line='export PATH="$HOME/.microsandbox/bin:$PATH"' _posix_block="${MARKER_START} ${_path_line} ${_lib_line} ${MARKER_END}" # Build fish block if [ "$OS" = "linux" ]; then _fish_lib='set -gx LD_LIBRARY_PATH "$HOME/.microsandbox/lib" $LD_LIBRARY_PATH' else _fish_lib='set -gx DYLD_LIBRARY_PATH "$HOME/.microsandbox/lib" $DYLD_LIBRARY_PATH' fi _fish_path='set -gx PATH "$HOME/.microsandbox/bin" $PATH' _fish_block="${MARKER_START} ${_fish_path} ${_fish_lib} ${MARKER_END}" _did_bashrc=false _did_zshrc=false _did_profile=false printf "\n" printf " ${BOLD}Shell Configuration${RESET}\n" printf "\n" # Update existing POSIX shell config files for _file in "$HOME/.profile" "$HOME/.bash_profile" "$HOME/.bashrc" "$HOME/.zshrc"; do if [ -f "$_file" ]; then update_shell_config "$_file" "$_posix_block" _display="${_file#$HOME}" success "Configured ~${_display}" case "$_file" in */.bashrc) _did_bashrc=true ;; */.zshrc) _did_zshrc=true ;; */.profile) _did_profile=true ;; esac fi done # If current shell's primary config wasn't updated, create it case "$CURRENT_SHELL" in bash) if [ "$_did_bashrc" = false ]; then update_shell_config "$HOME/.bashrc" "$_posix_block" success "Configured ~/.bashrc" fi ;; zsh) if [ "$_did_zshrc" = false ]; then update_shell_config "$HOME/.zshrc" "$_posix_block" success "Configured ~/.zshrc" fi ;; sh) if [ "$_did_profile" = false ]; then update_shell_config "$HOME/.profile" "$_posix_block" success "Configured ~/.profile" fi ;; esac # Fish: update if config dir exists or fish is the current shell if [ -d "$HOME/.config/fish" ] || [ "$CURRENT_SHELL" = "fish" ]; then _fish_conf="$HOME/.config/fish/conf.d/microsandbox.fish" update_shell_config "$_fish_conf" "$_fish_block" success "Configured ~/.config/fish/conf.d/microsandbox.fish" fi printf "\n" printf " Restart your shell or run:\n" printf "\n" case "$CURRENT_SHELL" in fish) printf " ${DIM}source ~/.config/fish/conf.d/microsandbox.fish${RESET}\n" ;; zsh) printf " ${DIM}source ~/.zshrc${RESET}\n" ;; bash) printf " ${DIM}source ~/.bashrc${RESET}\n" ;; *) printf " ${DIM}. ~/.profile${RESET}\n" ;; esac printf "\n" } # --------------------------------------------------------------------------- # Progress bar # --------------------------------------------------------------------------- # Draw a progress bar: progress_bar