Last active 3 weeks ago

Interactive developer environment bootstrapper for Zsh/Bash with repeatable workstation setup helpers.

Revision 69632a496231db1c8d2f9319646435a0b1992718

README.md Raw

Strict Developer Environment Installer

A robust, idempotent, and interactive bash script to bootstrap your macOS, Linux, or WSL development environment.

Unlike standard setup scripts that rely heavily on package managers like Homebrew or Apt (which can introduce bloat, dependency hell, or outdated packages), this script is designed with a "Strict Official Source" philosophy. It dynamically fetches the absolute latest binaries and pre-compiled releases directly from the official maintainers (e.g., GitHub API, Python.org, Amazon).

✨ Key Features

  • Zero-Brew Dependency: By default, it bypasses Homebrew entirely, fetching tools directly from official APIs and release pages (Homebrew is available as an optional install).
  • Idempotent: Safe to run multiple times. It intelligently checks if a tool is already installed before attempting to download it.
  • Dynamic Versioning: Pings official APIs (like GitHub Releases or go.dev/VERSION) to ensure you are downloading the exact latest version at the time of execution.
  • Auto-Path Management: Intelligently injects paths into a dedicated ~/.pathrc (or your .bashrc/.zshrc) without mangling your config files.
  • Architecture Aware: Automatically detects if you are running on Intel (x86_64) or Apple Silicon/ARM (aarch64/arm64) and downloads the correct binaries.

🚀 Usage

You can launch the interactive installer directly from your terminal with a single command:

bash -c "$(curl -fsSL https://opengist.rmrf.online/weehong/af1c64c143a44ffbb0a1632dd6a32af1/raw/HEAD/menu.sh)"

Once the menu loads, simply follow the interactive prompts. You can select multiple tools at once by entering space-separated numbers (e.g., 1 3 8 12).

🛠️ Included Tools

Core Runtimes & Managers

  • Build Tools: GCC, Make, Git, Curl, Unzip, and core libraries.
  • Homebrew: (Optional) Installed officially.
  • NVM (Node Version Manager): Includes interactive prompt to install LTS or Latest Node.js immediately.
  • Python 3: Fetches the latest stable .pkg for Mac or compiles strictly from source for Linux.
  • Go: Fetches the latest tarball and installs system-wide to /usr/local/go.
  • SDKMAN: For managing Java, Kotlin, and Gradle.
  • .NET: Installed via Microsoft's official script.

Cloud & Infrastructure

  • Docker: Downloads the official .dmg (macOS) or runs the official get.docker.com script (Linux) with auto-group assignment.
  • AWS CLI: Fetches the official binaries directly from Amazon.
  • Google Cloud CLI (gcloud): Official Google setup script.
  • Firebase CLI: Standalone binary (no Node.js required natively).

Dev Tools & Security

  • GitHub CLI (gh): Downloaded directly from GitHub Releases to /usr/local/bin.
  • Infisical CLI: Downloaded directly from GitHub Releases for secret management.

AI & Agentic Tools

  • Claude Code CLI: Anthropic's official agent.
  • OpenCode: AI agent orchestration.
  • OpenAI Codex CLI: Required NVM/Node.js to run.

⚠️ Important Notes & Troubleshooting

  • Restart Your Shell: After running the script for the first time, you should restart your terminal or run source ~/.bashrc (or ~/.zshrc) to ensure all new PATH variables (like NVM, Go, or .NET) take effect.
  • Docker Permissions (Linux): The script automatically adds your user to the docker group. You will need to log out and log back in for this to take effect.
  • AWS CLI on Linux: Ensure you install Build Tools (Option 1) first if you are on a fresh Linux install, as the AWS installer requires unzip to extract the payload.

Built for developers who want total control over their toolchain.

menu.sh Raw
1#!/usr/bin/env bash
2set -u
3
4# =============================
5# COLORS & LOGGING
6# =============================
7GREEN="\033[0;32m"
8RED="\033[0;31m"
9YELLOW="\033[1;33m"
10BLUE="\033[0;34m"
11NC="\033[0m"
12
13log() { echo -e "${GREEN}$*${NC}"; }
14warn() { echo -e "${YELLOW}$*${NC}"; }
15err() { echo -e "${RED}$*${NC}"; }
16info() { echo -e "${BLUE}$*${NC}"; }
17
18# =============================
19# HELPERS & SYSTEM DETECTION
20# =============================
21require_cmd() { command -v "$1" >/dev/null 2>&1; }
22
23add_to_path_config() {
24 local label=$1
25 local path_line=$2
26 local target_file="${3:-$HOME/.pathrc}"
27
28 if [[ -f "$target_file" ]]; then
29 if ! grep -q "$label" "$target_file"; then
30 echo -e "\n# $label\n$path_line" >> "$target_file"
31 log "Added $label to $target_file"
32 fi
33 else
34 echo -e "\n# $label\n$path_line" >> "$HOME/.bashrc"
35 [[ -f "$HOME/.zshrc" ]] && echo -e "\n# $label\n$path_line" >> "$HOME/.zshrc"
36 log "Added $label to shell profiles."
37 fi
38}
39
40detect_os_arch() {
41 ARCH=$(uname -m)
42 case "$ARCH" in
43 x86_64|amd64) SYS_ARCH="amd64"; MAC_ARCH="x86_64"; AWS_ARCH="x86_64" ;;
44 aarch64|arm64) SYS_ARCH="arm64"; MAC_ARCH="arm64"; AWS_ARCH="aarch64" ;;
45 *) err "Unsupported architecture: $ARCH"; exit 1 ;;
46 esac
47
48 if [[ "$OSTYPE" == "darwin"* ]]; then
49 OS="macOS"
50 OS_LOWER="darwin"
51 elif grep -qi microsoft /proc/version 2>/dev/null; then
52 OS="WSL"
53 OS_LOWER="linux"
54 elif [[ -f /etc/os-release ]]; then
55 . /etc/os-release
56 [[ "$ID" == "ubuntu" || "$ID_LIKE" == *"ubuntu"* ]] && OS="Ubuntu" || OS="Linux"
57 OS_LOWER="linux"
58 else
59 OS="Unknown"
60 OS_LOWER="unknown"
61 fi
62 log "Detected: $OS ($ARCH)"
63}
64
65detect_os_arch
66
67# =============================
68# CORE RUNTIMES & MANAGERS
69# =============================
70
71install_build_tools() {
72 log "Installing Build Essentials & Core Dependencies..."
73 case "$OS" in
74 Ubuntu|WSL) sudo apt-get update && sudo apt-get install -y build-essential curl wget git jq unzip libssl-dev zlib1g-dev libffi-dev libsqlite3-dev ;;
75 macOS) xcode-select --install || warn "Xcode tools already installed" ;;
76 *) warn "Manual installation required for $OS." ;;
77 esac
78}
79
80install_brew() {
81 if require_cmd brew; then warn "Homebrew already installed"; return; fi
82 log "Installing Homebrew from Official Source..."
83 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
84
85 if [[ "$OS_LOWER" == "linux" ]]; then
86 add_to_path_config "HOMEBREW" 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"'
87 elif [[ "$MAC_ARCH" == "arm64" ]]; then
88 add_to_path_config "HOMEBREW" 'eval "$(/opt/homebrew/bin/brew shellenv)"'
89 else
90 add_to_path_config "HOMEBREW" 'eval "$(/usr/local/bin/brew shellenv)"'
91 fi
92}
93
94install_nvm() {
95 export NVM_DIR="$HOME/.nvm"
96
97 if [ -d "$NVM_DIR" ]; then
98 warn "NVM is already installed."
99 else
100 log "Installing NVM..."
101 curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
102 fi
103
104 # Load NVM for the current session to ensure the 'nvm' command is available immediately
105 [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
106
107 echo -e "\n${YELLOW}Which version of Node.js would you like to install?${NC}"
108 echo " 1) LTS (Long Term Support - Recommended for stability)"
109 echo " 2) Latest (Current features - Recommended for testing new APIs)"
110 echo " 3) Skip installing Node.js right now"
111 read -p "Select (1/2/3): " node_choice
112
113 case "$node_choice" in
114 2)
115 log "Installing Latest Node.js..."
116 nvm install node
117 nvm alias default node
118 nvm use node
119 ;;
120 3)
121 log "Skipping Node.js installation."
122 ;;
123 *)
124 log "Installing Latest LTS Node.js..."
125 nvm install --lts
126 nvm alias default 'lts/*'
127 nvm use --lts
128 ;;
129 esac
130}
131
132install_python() {
133 log "Fetching latest stable Python version..."
134
135 # Scrape the main downloads page for the official 'Download' button text
136 LATEST_PY=$(curl -s https://www.python.org/downloads/ | grep -o 'Download Python 3\.[0-9]\{1,2\}\.[0-9]\{1,2\}' | head -1 | grep -o '3\.[0-9]\{1,2\}\.[0-9]\{1,2\}')
137
138 # Fallback just in case curl fails
139 [[ -z "$LATEST_PY" ]] && LATEST_PY="3.12.3"
140
141 log "Detected Stable Version: $LATEST_PY"
142
143 if [[ "$OS" == "macOS" ]]; then
144 log "Downloading official macOS package..."
145 PKG_URL="https://www.python.org/ftp/python/${LATEST_PY}/python-${LATEST_PY}-macos11.pkg"
146 curl -fsSL -o /tmp/python.pkg "$PKG_URL"
147
148 log "Running installer..."
149 sudo installer -pkg /tmp/python.pkg -target /
150 rm /tmp/python.pkg
151 else
152 log "Installing build dependencies (zlib, ssl, etc)..."
153 sudo apt-get update && sudo apt-get install -y build-essential zlib1g-dev libssl-dev libffi-dev libsqlite3-dev
154
155 SRC_URL="https://www.python.org/ftp/python/${LATEST_PY}/Python-${LATEST_PY}.tgz"
156
157 log "Downloading $SRC_URL..."
158 curl -fSL -o /tmp/Python.tgz "$SRC_URL" || err "Failed to download Python source from $SRC_URL"
159
160 cd /tmp && tar -xzf Python.tgz && cd "Python-${LATEST_PY}"
161
162 log "Configuring build (with ensurepip)..."
163 ./configure --enable-optimizations --with-ensurepip=install
164
165 log "Compiling Python (this may take a few minutes)..."
166 sudo make altinstall
167
168 PY_MINOR=$(echo "$LATEST_PY" | cut -d. -f1,2)
169
170 log "Setting up symlinks..."
171 sudo ln -sf /usr/local/bin/python${PY_MINOR} /usr/local/bin/python3
172
173 if [[ -f "/usr/local/bin/pip${PY_MINOR}" ]]; then
174 sudo ln -sf /usr/local/bin/pip${PY_MINOR} /usr/local/bin/pip3
175 log "Successfully linked pip3!"
176 else
177 err "pip${PY_MINOR} was not generated during the build!"
178 fi
179
180 cd ~ && sudo rm -rf /tmp/Python*
181 fi
182
183 log "Python $LATEST_PY installation sequence finished!"
184}
185
186install_go() {
187 log "Fetching latest Go version from official source..."
188 LATEST_GO=$(curl -sL https://go.dev/VERSION?m=text | head -n 1)
189 TAR_FILE="${LATEST_GO}.${OS_LOWER}-${SYS_ARCH}.tar.gz"
190
191 log "Downloading $TAR_FILE..."
192 curl -fsSL -o /tmp/go.tar.gz "https://go.dev/dl/$TAR_FILE"
193
194 log "Installing to /usr/local/go..."
195 sudo rm -rf /usr/local/go
196 sudo tar -C /usr/local -xzf /tmp/go.tar.gz
197 rm /tmp/go.tar.gz
198 add_to_path_config "GO_BIN" 'export PATH="$PATH:/usr/local/go/bin"'
199}
200
201install_sdkman() {
202 if [ -d "$HOME/.sdkman" ]; then warn "SDKMAN already exists"; return; fi
203 log "Installing SDKMAN..."
204 curl -s "https://get.sdkman.io" | bash
205}
206
207install_dotnet() {
208 log "Installing .NET from official script..."
209 curl -fsSL https://dot.net/v1/dotnet-install.sh | bash
210 add_to_path_config "DOTNET_TOOLS" 'export PATH="$PATH:$HOME/.dotnet/tools"'
211}
212
213# =============================
214# CLOUD & INFRASTRUCTURE
215# =============================
216
217install_docker() {
218 if require_cmd docker; then log "Docker exists"; else
219 log "Installing Docker from official source..."
220
221 if [[ "$OS" == "macOS" ]]; then
222 [[ "$SYS_ARCH" == "arm64" ]] && DOCKER_MAC_ARCH="arm64" || DOCKER_MAC_ARCH="amd64"
223 DMG_URL="https://desktop.docker.com/mac/main/${DOCKER_MAC_ARCH}/Docker.dmg"
224 curl -fsSL -o /tmp/Docker.dmg "$DMG_URL"
225 hdiutil attach /tmp/Docker.dmg -nobrowse -mountpoint /Volumes/Docker
226 sudo cp -a /Volumes/Docker/Docker.app /Applications/
227 hdiutil detach /Volumes/Docker
228 rm /tmp/Docker.dmg
229
230 log "Starting Docker Desktop..."
231 open /Applications/Docker.app
232 log "Please complete the setup in the Docker Desktop UI."
233 else
234 # Linux install
235 curl -fsSL https://get.docker.com | sudo sh
236 fi
237 fi
238
239 # Post-install logic for Linux (Ubuntu/WSL)
240 if [[ "$OS" != "macOS" ]]; then
241 log "Applying Linux post-install actions..."
242
243 # 1. Create docker group and add user
244 sudo groupadd -f docker
245 sudo usermod -aG docker "$USER"
246
247 # 2. Enable and start Docker services
248 if command -v systemctl >/dev/null 2>&1; then
249 sudo systemctl enable --now docker.service
250 sudo systemctl enable --now containerd.service
251 elif [[ "$OS" == "WSL" ]]; then
252 sudo service docker start
253 fi
254
255 # 3. Immediate Socket Fix
256 if [[ -S /var/run/docker.sock ]]; then
257 log "Fixing ownership of /var/run/docker.sock..."
258 sudo chown root:docker /var/run/docker.sock
259 sudo chmod 660 /var/run/docker.sock
260 fi
261
262 log "Added $USER to the docker group."
263 log "CRITICAL: To apply group changes immediately, run: newgrp docker"
264 fi
265}
266
267install_aws() {
268 if require_cmd aws; then warn "AWS CLI exists"; return; fi
269 log "Installing AWS CLI directly from Amazon..."
270
271 if [[ "$OS" == "macOS" ]]; then
272 curl -fsSL -o /tmp/AWSCLIV2.pkg "https://awscli.amazonaws.com/AWSCLIV2.pkg"
273 sudo installer -pkg /tmp/AWSCLIV2.pkg -target /
274 rm /tmp/AWSCLIV2.pkg
275 else
276 if ! require_cmd unzip; then
277 err "unzip is required. Please install 'Build Tools' (Option 1) first."
278 return 1
279 fi
280 curl -fsSL -o /tmp/awscliv2.zip "https://awscli.amazonaws.com/awscli-exe-linux-${AWS_ARCH}.zip"
281 cd /tmp && unzip -q awscliv2.zip && sudo ./aws/install
282 rm -rf /tmp/awscliv2.zip /tmp/aws
283 fi
284}
285
286install_gcloud() {
287 if require_cmd gcloud; then warn "Google Cloud CLI exists"; return; fi
288 log "Installing Google Cloud CLI..."
289 curl -fsSL https://sdk.cloud.google.com | bash -s -- --disable-prompts
290
291 add_to_path_config "GCLOUD" '[ -f "$HOME/google-cloud-sdk/path.bash.inc" ] && . "$HOME/google-cloud-sdk/path.bash.inc"'
292}
293
294install_firebase() {
295 if require_cmd firebase; then warn "Firebase CLI exists"; return; fi
296 log "Installing Firebase CLI via NPM to ensure ARM64 compatibility..."
297
298 if ! require_cmd npm; then
299 err "NPM not found. Please install NVM (Option 3) first."
300 return 1
301 fi
302
303 npm install -g firebase-tools
304}
305
306# =============================
307# DEV TOOLS & SECURITY
308# =============================
309
310install_gh() {
311 if require_cmd gh; then warn "GitHub CLI exists"; return; fi
312 log "Fetching latest GitHub CLI version..."
313 LATEST_GH=$(curl -s https://api.github.com/repos/cli/cli/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
314 TAR_NAME="gh_${LATEST_GH}_${OS_LOWER}_${SYS_ARCH}"
315
316 curl -fsSL -o /tmp/gh.tar.gz "https://github.com/cli/cli/releases/download/v${LATEST_GH}/${TAR_NAME}.tar.gz"
317 tar -xzf /tmp/gh.tar.gz -C /tmp
318 sudo mv "/tmp/${TAR_NAME}/bin/gh" /usr/local/bin/
319 sudo rm -rf "/tmp/${TAR_NAME}" /tmp/gh.tar.gz
320}
321
322install_infisical() {
323 if require_cmd infisical; then warn "Infisical CLI exists"; return; fi
324 log "Installing Infisical CLI via NPM..."
325
326 if ! require_cmd npm; then
327 err "NPM not found. Please install NVM (Option 3) first."
328 return 1
329 fi
330
331 npm install -g @infisical/cli
332}
333
334# =============================
335# AI & AGENTIC TOOLS
336# =============================
337
338install_claude() { log "Installing Claude Code..."; curl -fsSL https://claude.ai/install.sh | bash; }
339install_opencode() { log "Installing OpenCode..."; curl -fsSL https://opencode.ai/install | bash; }
340
341install_codex() {
342 log "Installing @openai/codex..."
343 if ! require_cmd npm; then err "Node.js/NPM is required. Install NVM (3) first."; return 1; fi
344 npm i -g @openai/codex
345}
346
347# =============================
348# MENU LOGIC
349# =============================
350show_menu() {
351 clear
352 echo -e "${BLUE}==================================================${NC}"
353 echo -e "${GREEN} DEVELOPER ENVIRONMENT INSTALLER (Strict) ${NC}"
354 echo -e "${BLUE}==================================================${NC}"
355 echo -e "${YELLOW}--- Core Runtimes & Managers ---${NC}"
356 echo " 1) Build Tools (GCC/Make)"
357 echo " 2) Homebrew (Optional)"
358 echo " 3) NVM (Node.js)"
359 echo " 4) Python 3 (Official API)"
360 echo " 5) Go (Official -> /usr/local)"
361 echo " 6) SDKMAN (Java/Kotlin)"
362 echo " 7) .NET (Official Script)"
363 echo -e "${YELLOW}--- Cloud & Infrastructure ---${NC}"
364 echo " 8) Docker (Official DMG/sh)"
365 echo " 9) AWS CLI (Official Bin)"
366 echo " 10) Google Cloud CLI (gcloud)"
367 echo " 11) Firebase CLI (NPM/ARM64 Safe)"
368 echo -e "${YELLOW}--- Dev Tools & Security ---${NC}"
369 echo " 12) GitHub CLI (Official Bin)"
370 echo " 13) Infisical (Official Bin)"
371 echo -e "${YELLOW}--- AI & Agentic Tools ---${NC}"
372 echo " 14) Claude Code CLI"
373 echo " 15) OpenCode (opencode.ai)"
374 echo " 16) OpenAI Codex CLI"
375 echo -e "${BLUE}==================================================${NC}"
376 echo " 99) Quit"
377 echo -e "${BLUE}==================================================${NC}"
378}
379
380while true; do
381 show_menu
382 read -p "Select options (space-separated): " input
383 for choice in $input; do
384 case "$choice" in
385 1) install_build_tools ;;
386 2) install_brew ;;
387 3) install_nvm ;;
388 4) install_python ;;
389 5) install_go ;;
390 6) install_sdkman ;;
391 7) install_dotnet ;;
392 8) install_docker ;;
393 9) install_aws ;;
394 10) install_gcloud ;;
395 11) install_firebase ;;
396 12) install_gh ;;
397 13) install_infisical ;;
398 14) install_claude ;;
399 15) install_opencode ;;
400 16) install_codex ;;
401 99) log "Exiting..."; exit 0 ;;
402 *) warn "Option $choice not valid." ;;
403 esac
404 done
405 read -p "Press Enter to continue..."
406done