Last active
October 27, 2025 16:39
-
-
Save erikunha/a024bc913078c90372a60c8818e1643d to your computer and use it in GitHub Desktop.
ErikOS — MacOs Dev Environment Script Setup
This file contains hidden or 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
| #!/usr/bin/env bash | |
| # ====================================================== | |
| # 🧠 ErikOS — macOS Developer Workstation Setup | |
| # Author: Erik Henrique Alves Cunha | |
| # ====================================================== | |
| # Builds a full modern environment: | |
| # - CLI tools, Fish shell, Starship prompt | |
| # - Node (fnm), Python, Go, Rust (with fallback) | |
| # - Dev & productivity apps (DevToys, Paw, Obsidian, Raycast, etc.) | |
| # - Comfort tools (Maccy, KeepingYouAwake, Shottr, Stats, Shotcut, DBeaver, Fig, Warp) | |
| # ====================================================== | |
| # | |
| # 🧭 How to Use (from Gist) | |
| # ====================================================== | |
| # Run this installer directly from your terminal — no need to clone or download: | |
| # | |
| # curl -fsSL https://gist.githubusercontent.com/erikunha/a024bc913078c90372a60c8818e1643d/raw/install.sh | bash | |
| # | |
| # Optional flags: | |
| # --overwrite-fish Force overwrite of ~/.config/fish/config.fish | |
| # | |
| # curl -fsSL https://gist.githubusercontent.com/erikunha/a024bc913078c90372a60c8818e1643d/raw/install.sh | bash -s -- --overwrite-fish | |
| # | |
| # Notes: | |
| # - Safe to re-run anytime — skips already installed packages. | |
| # - Works on any modern macOS with curl and bash preinstalled. | |
| # - You may be asked for your password once (for setting Fish as the default shell). | |
| # | |
| # Tip: After setup completes, restart your terminal or run: | |
| # exec fish | |
| # ====================================================== | |
| set -e | |
| START_TIME=$(date +%s) | |
| # ------------------------- | |
| # 🎨 Colors | |
| # ------------------------- | |
| GREEN="\033[0;32m" | |
| YELLOW="\033[1;33m" | |
| BLUE="\033[1;34m" | |
| CYAN="\033[0;36m" | |
| RED="\033[0;31m" | |
| RESET="\033[0m" | |
| log() { echo -e "${BLUE}→${RESET} $1"; } | |
| success() { echo -e "${GREEN}✅${RESET} $1"; } | |
| warn() { echo -e "${YELLOW}⚠️ ${RESET}$1"; } | |
| error() { echo -e "${RED}❌${RESET} $1"; } | |
| # ------------------------- | |
| # ⚙️ Flags | |
| # ------------------------- | |
| OVERWRITE_FISH=false | |
| for arg in "$@"; do | |
| case "$arg" in | |
| --overwrite-fish) OVERWRITE_FISH=true ;; | |
| esac | |
| done | |
| trap 'error "Setup failed on line $LINENO. Check your network or permissions."' ERR | |
| echo "" | |
| echo "======================================================" | |
| echo -e " 🚀 ${CYAN}Starting ErikOS Setup${RESET}" | |
| echo "======================================================" | |
| echo "" | |
| # ====================================================== | |
| # 🍺 Homebrew | |
| # ====================================================== | |
| if ! command -v brew &>/dev/null; then | |
| log "Installing Homebrew..." | |
| /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | |
| echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.bash_profile | |
| eval "$(/opt/homebrew/bin/brew shellenv)" | |
| success "Homebrew installed." | |
| else | |
| success "Homebrew already installed." | |
| fi | |
| log "Updating Homebrew..." | |
| brew update >/dev/null | |
| success "Homebrew updated." | |
| # ====================================================== | |
| # 🧩 Helper Functions | |
| # ====================================================== | |
| safe_exec() { "$@" >/dev/null 2>&1 || warn "Non-critical failure: $*"; } | |
| install_pkg() { | |
| local pkg="$1" | |
| if brew list --formula | grep -q "^${pkg}\$"; then | |
| success "$pkg already installed." | |
| else | |
| log "Installing $pkg..." | |
| safe_exec brew install "$pkg" | |
| brew list --formula | grep -q "^${pkg}\$" && success "$pkg installed." || warn "$pkg failed." | |
| fi | |
| } | |
| install_app() { | |
| local app="$1" | |
| if brew list --cask | grep -q "^${app}\$"; then | |
| success "$app already installed." | |
| else | |
| log "Installing $app..." | |
| safe_exec brew install --cask "$app" | |
| success "$app installed or queued." | |
| fi | |
| } | |
| # ====================================================== | |
| # ⚙️ Core CLI Stack | |
| # ====================================================== | |
| log "Installing CLI tools..." | |
| for pkg in fish starship fzf ripgrep fd zoxide atuin thefuck bat eza jq git gh direnv httpie; do | |
| install_pkg "$pkg" | |
| done | |
| # ====================================================== | |
| # ⚡ Languages | |
| # ====================================================== | |
| # Node.js via FNM | |
| install_pkg "fnm" | |
| if command -v fnm &>/dev/null; then | |
| log "Installing latest LTS Node via fnm..." | |
| safe_exec fnm install --lts | |
| LTS_VERSION=$(fnm ls-remote --lts | tail -1 | awk '{print $1}') | |
| if [ -n "$LTS_VERSION" ]; then | |
| fnm default "$LTS_VERSION" >/dev/null 2>&1 && success "Node $LTS_VERSION set as default via fnm." | |
| else | |
| warn "Could not detect remote LTS version. Using system default." | |
| fi | |
| else | |
| warn "fnm installation failed or not found in PATH." | |
| fi | |
| # Python | |
| log "Installing latest Python..." | |
| safe_exec brew install python | |
| python3 -m pip install --upgrade pip >/dev/null 2>&1 && success "Python & pip ready." | |
| # Go | |
| install_pkg "go" | |
| # Rust (robust fallback) | |
| log "Installing Rust toolchain..." | |
| if ! command -v rustc &>/dev/null; then | |
| if brew list --formula | grep -q "^rustup-init\$"; then | |
| log "Running rustup-init..." | |
| if rustup-init -y >/dev/null 2>&1; then | |
| success "Rust installed via rustup." | |
| else | |
| warn "rustup-init failed; trying Homebrew Rust fallback..." | |
| safe_exec brew install rust | |
| command -v rustc &>/dev/null && success "Rust installed via Homebrew." || error "Rust installation failed completely." | |
| fi | |
| else | |
| log "Installing rustup-init via Homebrew..." | |
| safe_exec brew install rustup-init | |
| if rustup-init -y >/dev/null 2>&1; then | |
| success "Rust installed via rustup." | |
| else | |
| warn "rustup-init failed; falling back to Homebrew Rust..." | |
| safe_exec brew install rust | |
| command -v rustc &>/dev/null && success "Rust installed via Homebrew." || error "Rust installation failed completely." | |
| fi | |
| fi | |
| else | |
| success "Rust already installed." | |
| fi | |
| # ====================================================== | |
| # 💼 Productivity & Dev Apps | |
| # ====================================================== | |
| log "Installing productivity and developer applications..." | |
| for app in devtoys paw obsidian raycast rectangle appcleaner monitorcontrol kap; do | |
| install_app "$app" | |
| done | |
| success "Productivity apps installed." | |
| # ====================================================== | |
| # 🌈 Comfort & Utility Tools | |
| # ====================================================== | |
| log "Installing comfort & utility tools..." | |
| # Replaced Amphetamine with KeepingYouAwake (open-source equivalent) | |
| for app in maccy keepingyouawake shottr stats shotcut dbeaver-community fig warp; do | |
| install_app "$app" | |
| done | |
| success "Comfort tools installed." | |
| # ====================================================== | |
| # 🐚 Fish Shell Setup | |
| # ====================================================== | |
| FISH_PATH="/opt/homebrew/bin/fish" | |
| grep -q "$FISH_PATH" /etc/shells || echo "$FISH_PATH" | sudo tee -a /etc/shells >/dev/null | |
| [ "$SHELL" != "$FISH_PATH" ] && chsh -s "$FISH_PATH" | |
| safe_exec "$(brew --prefix)"/opt/fzf/install --key-bindings --completion --no-update-rc | |
| safe_exec atuin init fish | |
| # ====================================================== | |
| # 🎣 Fish Configuration | |
| # ====================================================== | |
| mkdir -p ~/.config/fish | |
| if [ -f ~/.config/fish/config.fish ] && [ "$OVERWRITE_FISH" = true ]; then | |
| warn "Backing up existing Fish config..." | |
| cp ~/.config/fish/config.fish ~/.config/fish/config.fish.bak | |
| fi | |
| if [ ! -f ~/.config/fish/config.fish ] || [ "$OVERWRITE_FISH" = true ]; then | |
| cat > ~/.config/fish/config.fish <<'EOF' | |
| # ====================================================== | |
| # ~/.config/fish/config.fish — ErikOS | |
| # ====================================================== | |
| if not status is-interactive | |
| exit | |
| end | |
| # 🧭 Add Homebrew binary paths (Apple Silicon + Intel) | |
| set -gx PATH /opt/homebrew/bin /usr/local/bin $PATH | |
| # 🌍 Environment | |
| set -Ux LANG "en_US.UTF-8" | |
| set -Ux LC_ALL "en_US.UTF-8" | |
| set -Ux EDITOR "code -w" | |
| set -Ux VISUAL "code -w" | |
| set -Ux PNPM_HOME "$HOME/Library/pnpm" | |
| set -gx PATH $PNPM_HOME $PATH | |
| # 🪄 Plugin Initializations | |
| if command -q starship | |
| starship init fish | source | |
| end | |
| if command -q zoxide | |
| zoxide init fish | source | |
| end | |
| if type -q fzf_key_bindings | |
| fzf_key_bindings | |
| end | |
| if command -q atuin | |
| atuin init fish | source | |
| end | |
| if command -q thefuck | |
| thefuck --alias | source | |
| end | |
| if command -q direnv | |
| direnv hook fish | source | |
| end | |
| if command -q fnm | |
| fnm env --use-on-cd | source | |
| end | |
| # 🧰 Aliases | |
| alias ll 'eza -lah --git' | |
| alias reload 'source ~/.config/fish/config.fish; echo "🔁 Reloaded ✅"' | |
| alias g 'git' | |
| alias ga 'git add .' | |
| alias gs 'git status -sb' | |
| alias gp 'git pull --rebase' | |
| alias gpp 'git push' | |
| alias gundo 'git reset --soft HEAD~1' | |
| # ⚡ Maintenance & Upgrades | |
| function erikos-update | |
| echo "🔄 Updating ErikOS environment..." | |
| brew update && brew upgrade && brew cleanup | |
| rustup update || true | |
| fnm install --lts | |
| python3 -m pip install --upgrade pip | |
| echo "✨ ErikOS environment fully updated." | |
| end | |
| # 💾 Backup Brewfile | |
| function erikos-backup | |
| brew bundle dump --file=~/ErikOS.Brewfile --force | |
| echo "💾 Brewfile snapshot saved at ~/ErikOS.Brewfile" | |
| end | |
| # 👋 Greeting | |
| function fish_greeting | |
| echo "" | |
| echo "👨💻 ErikOS — Dev Environment" | |
| set node_version (command -q node; and node -v; or echo "N/A") | |
| set python_version (command -q python3; and python3 --version | awk '{print $2}'; or echo "N/A") | |
| set go_version (command -q go; and go version | awk '{print $3}'; or echo "N/A") | |
| echo "🔧 Node $node_version | Python $python_version | Go $go_version" | |
| echo "🕒 "(date '+%A, %d %B %Y — %H:%M:%S') | |
| echo "💡 Tools: zoxide + fzf + atuin + bat + eza" | |
| end | |
| EOF | |
| success "Fish config created or overwritten." | |
| else | |
| warn "Fish config already exists — skipping overwrite." | |
| fi | |
| # ====================================================== | |
| # 🌟 Starship Prompt | |
| # ====================================================== | |
| mkdir -p ~/.config | |
| if [ ! -f ~/.config/starship.toml ]; then | |
| cat > ~/.config/starship.toml <<'EOF' | |
| add_newline = false | |
| [character] | |
| success_symbol = "➜" | |
| error_symbol = "✗" | |
| [git_branch] | |
| symbol = "🌿 " | |
| [time] | |
| disabled = false | |
| format = "🕒 [$time]($style) " | |
| EOF | |
| success "Starship prompt configured." | |
| else | |
| warn "Starship config already exists — skipping overwrite." | |
| fi | |
| # ====================================================== | |
| # 🪙 Summary | |
| # ====================================================== | |
| END_TIME=$(date +%s) | |
| DURATION=$((END_TIME - START_TIME)) | |
| echo "" | |
| echo "======================================================" | |
| echo -e "🎉 ${GREEN}ErikOS setup complete in ${DURATION}s${RESET}" | |
| echo -e " Restart terminal or run: ${CYAN}exec fish${RESET}" | |
| echo " Run ${YELLOW}erikos-update${RESET} anytime to stay up to date." | |
| echo "======================================================" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment