Zuletzt aktiv 6 days ago

Interactive developer environment bootstrapper using official upstream downloads and signed OS-vendor packages.

weehong hat die Gist bearbeitet 6 days ago. Zu Änderung gehen

1 file changed, 45 insertions, 260 deletions

menu.sh

@@ -5,9 +5,9 @@
5 5 # =======================================================
6 6 if [ -z "${_PREFER_ZSH_BOOTSTRAPPED:-}" ]; then
7 7 export _PREFER_ZSH_BOOTSTRAPPED=1
8 -
8 +
9 9 # Only attempt to re-execute if $0 is an actual file on disk.
10 - # This prevents the 'can't open input file' error when running
10 + # This prevents the 'can't open input file' error when running
11 11 # from memory via `bash -c "$(curl ...)"` or `zsh -c`.
12 12 if [ -f "$0" ]; then
13 13 if command -v zsh >/dev/null 2>&1; then
@@ -61,7 +61,7 @@ add_to_path_config() {
61 61 local label=$1
62 62 local path_line=$2
63 63 local target_file="${3:-$PROFILE_FILE}"
64 -
64 +
65 65 if [[ -f "$target_file" ]]; then
66 66 if ! grep -q "$label" "$target_file"; then
67 67 printf "\n# %s\n%s\n" "$label" "$path_line" >> "$target_file"
@@ -71,8 +71,8 @@ add_to_path_config() {
71 71 printf "\n# %s\n%s\n" "$label" "$path_line" >> "$PROFILE_FILE"
72 72 log "Added $label to shell profile ($PROFILE_FILE)."
73 73 fi
74 -
75 - # Instantly evaluate the path line so the current script session
74 +
75 + # Instantly evaluate the path line so the current script session
76 76 # can immediately use the newly installed tool in subsequent steps.
77 77 eval "$path_line" 2>/dev/null || true
78 78 }
@@ -120,10 +120,10 @@ install_build_tools() {
120 120 install_brew() {
121 121 if require_cmd brew; then warn "Homebrew already installed"; return; fi
122 122 log "Installing Homebrew from Official Source..."
123 -
123 +
124 124 # Homebrew's installer specifically requires Bash execution, regardless of current shell
125 125 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
126 -
126 +
127 127 if [[ "$OS_LOWER" == "linux" ]]; then
128 128 add_to_path_config "HOMEBREW" 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"'
129 129 elif [[ "$MAC_ARCH" == "arm64" ]]; then
@@ -135,46 +135,46 @@ install_brew() {
135 135
136 136 install_nvm() {
137 137 # 1. Temporarily disable 'unbound variable' strictness for NVM
138 - set +u
139 -
138 + set +u
139 +
140 140 export NVM_DIR="$HOME/.nvm"
141 -
142 - if [ -d "$NVM_DIR" ]; then
141 +
142 + if [ -d "$NVM_DIR" ]; then
143 143 warn "NVM is already installed."
144 144 else
145 145 log "Installing NVM via $CURRENT_SHELL..."
146 146 curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | $CURRENT_SHELL
147 147 fi
148 -
148 +
149 149 [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
150 -
150 +
151 151 printf "\n${YELLOW}Which version of Node.js would you like to install?${NC}\n"
152 152 printf " 1) LTS (Long Term Support - Recommended for stability)\n"
153 153 printf " 2) Latest (Current features - Recommended for testing new APIs)\n"
154 154 printf " 3) Skip installing Node.js right now\n"
155 -
156 - printf "Select (1/2/3): "
155 +
156 + printf "Select (1/2/3): "
157 157 read node_choice
158 158
159 159 case "$node_choice" in
160 - 2)
160 + 2)
161 161 log "Installing Latest Node.js..."
162 162 nvm install node
163 163 nvm alias default node
164 164 nvm use node
165 -
165 +
166 166 log "Disabling npm logs..."
167 167 npm config set logs-max 0
168 168 ;;
169 - 3)
170 - log "Skipping Node.js installation."
169 + 3)
170 + log "Skipping Node.js installation."
171 171 ;;
172 - *)
172 + *)
173 173 log "Installing Latest LTS Node.js..."
174 174 nvm install --lts
175 175 nvm alias default 'lts/*'
176 176 nvm use --lts
177 -
177 +
178 178 log "Disabling npm logs..."
179 179 npm config set logs-max 0
180 180 ;;
@@ -204,7 +204,7 @@ install_python() {
204 204 err "Failed to download Python macOS package from $PKG_URL"
205 205 return 1
206 206 }
207 -
207 +
208 208 log "Running installer..."
209 209 sudo installer -pkg /tmp/python.pkg -target / || {
210 210 err "Python macOS installer failed."
@@ -257,14 +257,14 @@ install_go() {
257 257 add_to_path_config "GO_BIN" 'export PATH="$PATH:/usr/local/go/bin"'
258 258 return 0
259 259 fi
260 -
260 +
261 261 log "Downloading $TAR_FILE..."
262 262 curl -fsSL -o /tmp/go.tar.gz "https://go.dev/dl/$TAR_FILE" || {
263 263 err "Failed to download $TAR_FILE."
264 264 rm -f /tmp/go.tar.gz
265 265 return 1
266 266 }
267 -
267 +
268 268 log "Installing to /usr/local/go..."
269 269 if ! sudo rm -rf /usr/local/go || ! sudo tar -C /usr/local -xzf /tmp/go.tar.gz; then
270 270 err "Go installation failed. Run this installer from an interactive terminal so sudo can authenticate."
@@ -278,8 +278,8 @@ install_go() {
278 278
279 279 install_sdkman() {
280 280 if [ -d "$HOME/.sdkman" ]; then warn "SDKMAN already exists"; return; fi
281 -
282 - # SDKMAN explicitly blocks macOS's default Bash 3.2.
281 +
282 + # SDKMAN explicitly blocks macOS's default Bash 3.2.
283 283 # If we are trapped in Bash < 4, force the installer to use Zsh.
284 284 if [[ "$CURRENT_SHELL" == "bash" && "${BASH_VERSINFO[0]:-0}" -lt 4 ]]; then
285 285 log "Outdated Bash detected. Installing SDKMAN via Zsh..."
@@ -296,210 +296,13 @@ install_dotnet() {
296 296 add_to_path_config "DOTNET_TOOLS" 'export PATH="$PATH:$HOME/.dotnet/tools"'
297 297 }
298 298
299 - # Prints the major Java version of the given java binary, or fails.
300 - # Handles both "21.0.4" and legacy "1.8.0_xxx" style version strings
301 - # (legacy ones report as 1, which correctly counts as too old).
302 - java_major() {
303 - local out
304 - out=$("$1" -version 2>&1) || return 1
305 - printf '%s\n' "$out" | sed -nE 's/.*version "([0-9]+).*/\1/p' | head -1
306 - }
307 -
308 - # The Android command line tools (sdkmanager, avdmanager) are Java programs
309 - # and need JDK 17 or newer. On macOS, /usr/bin/java is a stub that exists even
310 - # when no JDK is installed, so `command -v java` is not enough: we must run it.
311 - ensure_android_java() {
312 - local major home jbr
313 -
314 - # Pick up an SDKMAN managed JDK if SDKMAN is installed.
315 - if [[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]]; then
316 - set +u; source "$HOME/.sdkman/bin/sdkman-init.sh"; set -u
317 - fi
318 -
319 - major=$(java_major java 2>/dev/null)
320 - if [[ -n "$major" ]] && (( major >= 17 )); then
321 - log "Using Java $major for the Android SDK tools."
322 - return 0
323 - fi
324 -
325 - if [[ "$OS" == "macOS" ]]; then
326 - # A JDK registered with macOS (Temurin, Zulu, Oracle .pkg installers).
327 - home=$(/usr/libexec/java_home -v 17+ 2>/dev/null || true)
328 - if [[ -n "$home" && -x "$home/bin/java" ]]; then
329 - export JAVA_HOME="$home"
330 - export PATH="$JAVA_HOME/bin:$PATH"
331 - log "Using the JDK at $JAVA_HOME"
332 - return 0
333 - fi
334 -
335 - # The JDK bundled inside Android Studio (not registered with macOS).
336 - jbr="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
337 - if [[ -x "$jbr/bin/java" ]]; then
338 - add_to_path_config "ANDROID_STUDIO_JBR" 'export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
339 - export PATH="$JAVA_HOME/bin:$PATH"'
340 - log "Using the JDK bundled with Android Studio."
341 - return 0
342 - fi
343 - fi
344 -
345 - # Nothing usable: provision a JDK through SDKMAN.
346 - if [[ ! -s "$HOME/.sdkman/bin/sdkman-init.sh" ]]; then
347 - log "No Java 17+ found. Installing SDKMAN to provide a JDK..."
348 - install_sdkman
349 - fi
350 -
351 - if [[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]]; then
352 - log "Installing the default Temurin JDK through SDKMAN..."
353 - set +u
354 - source "$HOME/.sdkman/bin/sdkman-init.sh"
355 - yes | sdk install java
356 - # Re-source so the freshly installed JDK lands on PATH and JAVA_HOME.
357 - source "$HOME/.sdkman/bin/sdkman-init.sh"
358 - set -u
359 -
360 - major=$(java_major java 2>/dev/null)
361 - if [[ -n "$major" ]] && (( major >= 17 )); then
362 - log "Using Java $major for the Android SDK tools."
363 - return 0
364 - fi
365 - fi
366 -
367 - err "Java 17 or newer is required by the Android SDK tools, but none could be set up."
368 - err "Install a JDK (for example: sdk install java), open a new terminal, then rerun Option 8."
369 - return 1
370 - }
371 -
372 - # Prints the download URL of the newest Android command line tools zip.
373 - # Tries the Android Studio download page first, then falls back to Google's
374 - # SDK repository manifest, which is a stable machine readable source.
375 - latest_cmdline_tools_url() {
376 - local tools_os=$1 file
377 -
378 - file=$(curl -fsSL --compressed https://developer.android.com/studio 2>/dev/null \
379 - | grep -oE "commandlinetools-${tools_os}-[0-9]+_latest\.zip" \
380 - | head -1)
381 -
382 - if [[ -z "$file" ]]; then
383 - file=$(curl -fsSL --compressed https://dl.google.com/android/repository/repository2-3.xml 2>/dev/null \
384 - | grep -oE "commandlinetools-${tools_os}-[0-9]+_latest\.zip" \
385 - | sort -t- -k3 -n \
386 - | tail -1)
387 - fi
388 -
389 - [[ -n "$file" ]] && printf 'https://dl.google.com/android/repository/%s\n' "$file"
390 - }
391 -
392 - install_android() {
393 - log "Installing Android SDK command-line tools..."
394 -
395 - if ! require_cmd unzip; then
396 - err "unzip is required. Please install 'Build Tools' (Option 1) first."
397 - return 1
398 - fi
399 -
400 - if [[ "$OS_LOWER" == "linux" && "$SYS_ARCH" != "amd64" ]]; then
401 - err "Google's Android command-line tools installer supports Linux x86_64 only."
402 - return 1
403 - fi
404 -
405 - if [[ "$OS" == "macOS" ]]; then
406 - TOOLS_OS="mac"
407 - elif [[ "$OS_LOWER" == "linux" ]]; then
408 - TOOLS_OS="linux"
409 - else
410 - err "Android SDK installation is not supported for $OS."
411 - return 1
412 - fi
413 -
414 - # sdkmanager is a Java program, so fail fast before downloading anything.
415 - ensure_android_java || return 1
416 -
417 - ANDROID_HOME="$HOME/Android/Sdk"
418 - ANDROID_SDK_ROOT="$ANDROID_HOME"
419 - export ANDROID_HOME ANDROID_SDK_ROOT
420 -
421 - mkdir -p "$ANDROID_HOME/cmdline-tools"
422 -
423 - log "Finding latest Android command-line tools from Google..."
424 - TOOLS_URL=$(latest_cmdline_tools_url "$TOOLS_OS")
425 -
426 - if [[ -z "$TOOLS_URL" ]]; then
427 - err "Could not find the Android command-line tools download URL."
428 - return 1
429 - fi
430 -
431 - log "Downloading $TOOLS_URL..."
432 - rm -rf /tmp/android-cmdline-tools /tmp/android-cmdline-tools.zip
433 - mkdir -p /tmp/android-cmdline-tools
434 - if ! curl -fsSL -o /tmp/android-cmdline-tools.zip "$TOOLS_URL" || \
435 - ! unzip -q /tmp/android-cmdline-tools.zip -d /tmp/android-cmdline-tools; then
436 - err "Failed to download or extract the Android command-line tools."
437 - rm -rf /tmp/android-cmdline-tools /tmp/android-cmdline-tools.zip
438 - return 1
439 - fi
440 -
441 - rm -rf "$ANDROID_HOME/cmdline-tools/latest"
442 - mkdir -p "$ANDROID_HOME/cmdline-tools/latest"
443 - mv /tmp/android-cmdline-tools/cmdline-tools/* "$ANDROID_HOME/cmdline-tools/latest/"
444 - rm -rf /tmp/android-cmdline-tools /tmp/android-cmdline-tools.zip
445 -
446 - local tools_bin="$ANDROID_HOME/cmdline-tools/latest/bin"
447 -
448 - if [[ -x "$tools_bin/android" ]]; then
449 - # Current cmdline-tools ship the Android CLI ('android'), and
450 - # 'android sdk' replaces the deprecated sdkmanager. It is left
451 - # interactive on purpose so any license prompt reaches you.
452 - log "Installing Android SDK packages with Android CLI..."
453 - if ! "$tools_bin/android" --sdk="$ANDROID_HOME" sdk install \
454 - cmdline-tools/latest \
455 - platform-tools \
456 - emulator \
457 - platforms/android-36 \
458 - build-tools/36.0.0; then
459 - err "Android CLI failed to install the SDK packages. See the error above."
460 - return 1
461 - fi
462 - elif [[ -x "$tools_bin/sdkmanager" ]]; then
463 - # Older cmdline-tools without the Android CLI: use sdkmanager.
464 - warn "Android CLI not found in cmdline-tools. Falling back to sdkmanager."
465 - SDKMANAGER="$tools_bin/sdkmanager"
466 -
467 - # stdout is silenced, stderr is kept so Java or network errors stay visible.
468 - log "Accepting Android SDK licenses..."
469 - if ! yes | "$SDKMANAGER" --sdk_root="$ANDROID_HOME" --licenses >/dev/null; then
470 - err "sdkmanager could not run. See the error above."
471 - return 1
472 - fi
473 -
474 - log "Installing Android SDK packages..."
475 - if ! "$SDKMANAGER" --sdk_root="$ANDROID_HOME" \
476 - "cmdline-tools;latest" \
477 - "platform-tools" \
478 - "emulator" \
479 - "platforms;android-36" \
480 - "build-tools;36.0.0"; then
481 - err "Failed to install Android SDK packages."
482 - return 1
483 - fi
484 - else
485 - err "Neither Android CLI nor sdkmanager was found in $tools_bin."
486 - return 1
487 - fi
488 -
489 - add_to_path_config "ANDROID_SDK" 'export ANDROID_HOME="$HOME/Android/Sdk"
490 - export ANDROID_SDK_ROOT="$ANDROID_HOME"
491 - export PATH="$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator"'
492 -
493 - log "Android SDK installation sequence finished!"
494 - }
495 -
496 299 # =======================================================
497 300 # CLOUD & INFRASTRUCTURE
498 301 # =======================================================
499 302
500 303 install_docker() {
501 304 log "Checking Docker status..."
502 -
305 +
503 306 # 1. Install if missing
504 307 if ! require_cmd docker; then
505 308 log "Installing Docker from official source..."
@@ -511,7 +314,7 @@ install_docker() {
511 314 sudo cp -a /Volumes/Docker/Docker.app /Applications/
512 315 hdiutil detach /Volumes/Docker
513 316 rm /tmp/Docker.dmg
514 -
317 +
515 318 log "Starting Docker Desktop..."
516 319 open /Applications/Docker.app
517 320 log "Please complete the setup in the Docker Desktop UI."
@@ -525,11 +328,11 @@ install_docker() {
525 328 # 2. Aggressively enforce Linux permissions
526 329 if [[ "$OS" != "macOS" ]]; then
527 330 log "Applying strict Linux post-install actions..."
528 -
331 +
529 332 # Ensure docker group exists and user is added
530 333 sudo groupadd -f docker
531 334 sudo usermod -aG docker "$USER"
532 -
335 +
533 336 # Ensure services are enabled and running
534 337 if command -v systemctl >/dev/null 2>&1; then
535 338 sudo systemctl enable --now docker.service
@@ -606,7 +409,7 @@ install_aws() {
606 409 sudo installer -pkg /tmp/AWSCLIV2.pkg -target /
607 410 rm /tmp/AWSCLIV2.pkg
608 411 else
609 - if ! require_cmd unzip; then
412 + if ! require_cmd unzip; then
610 413 err "unzip is required. Please install 'Build Tools' (Option 1) first."
611 414 return 1
612 415 fi
@@ -623,7 +426,7 @@ install_gcloud() {
623 426 log "Installing Google Cloud CLI to $gcloud_dir..."
624 427 curl -fsSL https://sdk.cloud.google.com | sudo bash -s -- --disable-prompts --install-dir=/opt
625 428 sudo chown -R "$(id -u):$(id -g)" "$gcloud_dir"
626 -
429 +
627 430 if [[ "$CURRENT_SHELL" == "zsh" ]]; then
628 431 add_to_path_config "GCLOUD" '[ -f "/opt/google-cloud-sdk/path.zsh.inc" ] && source "/opt/google-cloud-sdk/path.zsh.inc"'
629 432 else
@@ -634,12 +437,12 @@ install_gcloud() {
634 437 install_firebase() {
635 438 if require_cmd firebase; then warn "Firebase CLI exists"; return; fi
636 439 log "Installing Firebase CLI via NPM to ensure ARM64 compatibility..."
637 -
440 +
638 441 if ! require_cmd npm; then
639 442 err "NPM not found. Please install NVM (Option 3) first."
640 443 return 1
641 444 fi
642 -
445 +
643 446 npm install -g firebase-tools
644 447 }
645 448
@@ -652,7 +455,7 @@ install_gh() {
652 455 log "Fetching latest GitHub CLI version..."
653 456 LATEST_GH=$(curl -s https://api.github.com/repos/cli/cli/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
654 457 TAR_NAME="gh_${LATEST_GH}_${OS_LOWER}_${SYS_ARCH}"
655 -
458 +
656 459 curl -fsSL -o /tmp/gh.tar.gz "https://github.com/cli/cli/releases/download/v${LATEST_GH}/${TAR_NAME}.tar.gz"
657 460 tar -xzf /tmp/gh.tar.gz -C /tmp
658 461 sudo mv "/tmp/${TAR_NAME}/bin/gh" /usr/local/bin/
@@ -662,12 +465,12 @@ install_gh() {
662 465 install_infisical() {
663 466 if require_cmd infisical; then warn "Infisical CLI exists"; return; fi
664 467 log "Installing Infisical CLI via NPM..."
665 -
666 - if ! require_cmd npm; then
468 +
469 + if ! require_cmd npm; then
667 470 err "NPM not found. Please install NVM (Option 3) first."
668 471 return 1
669 472 fi
670 -
473 +
671 474 npm install -g @infisical/cli
672 475 }
673 476
@@ -749,21 +552,6 @@ update_all() {
749 552 curl -fsSL https://dot.net/v1/dotnet-install.sh | $CURRENT_SHELL
750 553 fi
751 554
752 - local android_sdk="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-$HOME/Android/Sdk}}"
753 - local android_bin="$android_sdk/cmdline-tools/latest/bin"
754 - if [[ -x "$android_bin/android" ]]; then
755 - log "Updating Android SDK packages with Android CLI..."
756 - "$android_bin/android" --sdk="$android_sdk" sdk update || \
757 - warn "Android CLI could not update the SDK. See the error above."
758 - elif [[ -x "$android_bin/sdkmanager" ]]; then
759 - if ensure_android_java; then
760 - yes | "$android_bin/sdkmanager" --licenses >/dev/null || true
761 - "$android_bin/sdkmanager" --update
762 - else
763 - warn "Skipping the Android SDK update because no usable Java was found."
764 - fi
765 - fi
766 -
767 555 if require_cmd docker; then
768 556 if [[ "$OS" == "macOS" ]]; then
769 557 docker desktop update || warn "Update Docker Desktop from its application menu."
@@ -842,8 +630,6 @@ show_menu() {
842 630 printf " 5) Go\n"
843 631 printf " 6) SDKMAN (Java/Kotlin/Gradle)\n"
844 632 printf " 7) .NET\n"
845 - printf "${YELLOW}--- Mobile Development ---${NC}\n"
846 - printf " 8) Android SDK (CLI + Platform Tools)\n"
847 633 printf "${YELLOW}--- Containers & Infrastructure ---${NC}\n"
848 634 printf " 9) Docker\n"
849 635 printf " 13) Portainer (Docker UI)\n"
@@ -869,7 +655,7 @@ show_menu() {
869 655
870 656 while true; do
871 657 show_menu
872 -
658 +
873 659 # Bulletproof prompt for both Bash and Zsh
874 660 printf "Select options (space-separated): "
875 661 if ! read input; then
@@ -877,7 +663,7 @@ while true; do
877 663 warn "Input closed. Exiting installer."
878 664 exit 0
879 665 fi
880 -
666 +
881 667 # Thanks to 'setopt shwordsplit' in Zsh, this behaves perfectly across both shells
882 668 for choice in $input; do
883 669 case "$choice" in
@@ -888,7 +674,6 @@ while true; do
888 674 5) install_go ;;
889 675 6) install_sdkman ;;
890 676 7) install_dotnet ;;
891 - 8) install_android ;;
892 677 9) install_docker ;;
893 678 10) install_aws ;;
894 679 11) install_gcloud ;;
@@ -902,20 +687,20 @@ while true; do
902 687 19) update_all ;;
903 688 20) install_augment ;;
904 689 21) install_coderabbit ;;
905 - 99)
690 + 99)
906 691 log "Installation complete! Refreshing terminal environment..."
907 -
692 +
908 693 # If on Linux, forcefully inherit the new docker group without needing a logout
909 694 if [[ "$OS" != "macOS" ]] && command -v sg >/dev/null 2>&1; then
910 695 exec sg docker -c "exec ${SHELL:-zsh}"
911 696 else
912 - exec "${SHELL:-zsh}"
697 + exec "${SHELL:-zsh}"
913 698 fi
914 699 ;;
915 700 *) warn "Option $choice not valid." ;;
916 701 esac
917 702 done
918 -
919 - printf "Press Enter to continue..."
703 +
704 + printf "Press Enter to continue..."
920 705 read dummy || exit 0
921 706 done

weehong hat die Gist bearbeitet 6 days ago. Zu Änderung gehen

1 file changed, 4 insertions, 2 deletions

menu.sh

@@ -677,7 +677,9 @@ install_infisical() {
677 677
678 678 install_claude() { log "Installing Claude Code..."; curl -fsSL https://claude.ai/install.sh | $CURRENT_SHELL; }
679 679
680 - install_opencode() { log "Installing OpenCode..."; curl -fsSL https://opencode.ai/install | $CURRENT_SHELL; }
680 + # opencode.ai/install now serves the v1 branch; OpenCode 2 has its own installer.
681 + # It installs to ~/.opencode/bin and is documented to run under bash.
682 + install_opencode() { log "Installing OpenCode 2..."; curl -fsSL https://opencode.ai/v2/install | bash; }
681 683
682 684 install_codex() {
683 685 log "Installing @openai/codex..."
@@ -814,7 +816,7 @@ update_all() {
814 816 require_cmd infisical && npm install -g @infisical/cli@latest
815 817 require_cmd claude && { curl -fsSL https://claude.ai/install.sh | $CURRENT_SHELL; }
816 818 require_cmd codex && npm install -g @openai/codex@latest
817 - require_cmd opencode && { curl -fsSL https://opencode.ai/install | $CURRENT_SHELL; }
819 + require_cmd opencode && { curl -fsSL https://opencode.ai/v2/install | bash; }
818 820 require_cmd auggie && npm install -g @augmentcode/auggie@latest
819 821 if require_cmd coderabbit || require_cmd cr; then
820 822 curl -fsSL https://cli.coderabbit.ai/install.sh | sh

weehong hat die Gist bearbeitet 6 days ago. Zu Änderung gehen

1 file changed, 48 insertions, 24 deletions

menu.sh

@@ -443,27 +443,46 @@ install_android() {
443 443 mv /tmp/android-cmdline-tools/cmdline-tools/* "$ANDROID_HOME/cmdline-tools/latest/"
444 444 rm -rf /tmp/android-cmdline-tools /tmp/android-cmdline-tools.zip
445 445
446 - SDKMANAGER="$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager"
447 - if [[ ! -x "$SDKMANAGER" ]]; then
448 - err "sdkmanager was not installed correctly."
449 - return 1
450 - fi
451 -
452 - # stdout is silenced, stderr is kept so Java or network errors stay visible.
453 - log "Accepting Android SDK licenses..."
454 - if ! yes | "$SDKMANAGER" --sdk_root="$ANDROID_HOME" --licenses >/dev/null; then
455 - err "sdkmanager could not run. See the error above."
456 - return 1
457 - fi
446 + local tools_bin="$ANDROID_HOME/cmdline-tools/latest/bin"
447 +
448 + if [[ -x "$tools_bin/android" ]]; then
449 + # Current cmdline-tools ship the Android CLI ('android'), and
450 + # 'android sdk' replaces the deprecated sdkmanager. It is left
451 + # interactive on purpose so any license prompt reaches you.
452 + log "Installing Android SDK packages with Android CLI..."
453 + if ! "$tools_bin/android" --sdk="$ANDROID_HOME" sdk install \
454 + cmdline-tools/latest \
455 + platform-tools \
456 + emulator \
457 + platforms/android-36 \
458 + build-tools/36.0.0; then
459 + err "Android CLI failed to install the SDK packages. See the error above."
460 + return 1
461 + fi
462 + elif [[ -x "$tools_bin/sdkmanager" ]]; then
463 + # Older cmdline-tools without the Android CLI: use sdkmanager.
464 + warn "Android CLI not found in cmdline-tools. Falling back to sdkmanager."
465 + SDKMANAGER="$tools_bin/sdkmanager"
466 +
467 + # stdout is silenced, stderr is kept so Java or network errors stay visible.
468 + log "Accepting Android SDK licenses..."
469 + if ! yes | "$SDKMANAGER" --sdk_root="$ANDROID_HOME" --licenses >/dev/null; then
470 + err "sdkmanager could not run. See the error above."
471 + return 1
472 + fi
458 473
459 - log "Installing Android SDK packages..."
460 - if ! "$SDKMANAGER" --sdk_root="$ANDROID_HOME" \
461 - "cmdline-tools;latest" \
462 - "platform-tools" \
463 - "emulator" \
464 - "platforms;android-36" \
465 - "build-tools;36.0.0"; then
466 - err "Failed to install Android SDK packages."
474 + log "Installing Android SDK packages..."
475 + if ! "$SDKMANAGER" --sdk_root="$ANDROID_HOME" \
476 + "cmdline-tools;latest" \
477 + "platform-tools" \
478 + "emulator" \
479 + "platforms;android-36" \
480 + "build-tools;36.0.0"; then
481 + err "Failed to install Android SDK packages."
482 + return 1
483 + fi
484 + else
485 + err "Neither Android CLI nor sdkmanager was found in $tools_bin."
467 486 return 1
468 487 fi
469 488
@@ -728,11 +747,16 @@ update_all() {
728 747 curl -fsSL https://dot.net/v1/dotnet-install.sh | $CURRENT_SHELL
729 748 fi
730 749
731 - local sdkmanager="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-$HOME/Android/Sdk}}/cmdline-tools/latest/bin/sdkmanager"
732 - if [[ -x "$sdkmanager" ]]; then
750 + local android_sdk="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-$HOME/Android/Sdk}}"
751 + local android_bin="$android_sdk/cmdline-tools/latest/bin"
752 + if [[ -x "$android_bin/android" ]]; then
753 + log "Updating Android SDK packages with Android CLI..."
754 + "$android_bin/android" --sdk="$android_sdk" sdk update || \
755 + warn "Android CLI could not update the SDK. See the error above."
756 + elif [[ -x "$android_bin/sdkmanager" ]]; then
733 757 if ensure_android_java; then
734 - yes | "$sdkmanager" --licenses >/dev/null || true
735 - "$sdkmanager" --update
758 + yes | "$android_bin/sdkmanager" --licenses >/dev/null || true
759 + "$android_bin/sdkmanager" --update
736 760 else
737 761 warn "Skipping the Android SDK update because no usable Java was found."
738 762 fi

weehong hat die Gist bearbeitet 6 days ago. Zu Änderung gehen

1 file changed, 127 insertions, 18 deletions

menu.sh

@@ -296,6 +296,99 @@ install_dotnet() {
296 296 add_to_path_config "DOTNET_TOOLS" 'export PATH="$PATH:$HOME/.dotnet/tools"'
297 297 }
298 298
299 + # Prints the major Java version of the given java binary, or fails.
300 + # Handles both "21.0.4" and legacy "1.8.0_xxx" style version strings
301 + # (legacy ones report as 1, which correctly counts as too old).
302 + java_major() {
303 + local out
304 + out=$("$1" -version 2>&1) || return 1
305 + printf '%s\n' "$out" | sed -nE 's/.*version "([0-9]+).*/\1/p' | head -1
306 + }
307 +
308 + # The Android command line tools (sdkmanager, avdmanager) are Java programs
309 + # and need JDK 17 or newer. On macOS, /usr/bin/java is a stub that exists even
310 + # when no JDK is installed, so `command -v java` is not enough: we must run it.
311 + ensure_android_java() {
312 + local major home jbr
313 +
314 + # Pick up an SDKMAN managed JDK if SDKMAN is installed.
315 + if [[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]]; then
316 + set +u; source "$HOME/.sdkman/bin/sdkman-init.sh"; set -u
317 + fi
318 +
319 + major=$(java_major java 2>/dev/null)
320 + if [[ -n "$major" ]] && (( major >= 17 )); then
321 + log "Using Java $major for the Android SDK tools."
322 + return 0
323 + fi
324 +
325 + if [[ "$OS" == "macOS" ]]; then
326 + # A JDK registered with macOS (Temurin, Zulu, Oracle .pkg installers).
327 + home=$(/usr/libexec/java_home -v 17+ 2>/dev/null || true)
328 + if [[ -n "$home" && -x "$home/bin/java" ]]; then
329 + export JAVA_HOME="$home"
330 + export PATH="$JAVA_HOME/bin:$PATH"
331 + log "Using the JDK at $JAVA_HOME"
332 + return 0
333 + fi
334 +
335 + # The JDK bundled inside Android Studio (not registered with macOS).
336 + jbr="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
337 + if [[ -x "$jbr/bin/java" ]]; then
338 + add_to_path_config "ANDROID_STUDIO_JBR" 'export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
339 + export PATH="$JAVA_HOME/bin:$PATH"'
340 + log "Using the JDK bundled with Android Studio."
341 + return 0
342 + fi
343 + fi
344 +
345 + # Nothing usable: provision a JDK through SDKMAN.
346 + if [[ ! -s "$HOME/.sdkman/bin/sdkman-init.sh" ]]; then
347 + log "No Java 17+ found. Installing SDKMAN to provide a JDK..."
348 + install_sdkman
349 + fi
350 +
351 + if [[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]]; then
352 + log "Installing the default Temurin JDK through SDKMAN..."
353 + set +u
354 + source "$HOME/.sdkman/bin/sdkman-init.sh"
355 + yes | sdk install java
356 + # Re-source so the freshly installed JDK lands on PATH and JAVA_HOME.
357 + source "$HOME/.sdkman/bin/sdkman-init.sh"
358 + set -u
359 +
360 + major=$(java_major java 2>/dev/null)
361 + if [[ -n "$major" ]] && (( major >= 17 )); then
362 + log "Using Java $major for the Android SDK tools."
363 + return 0
364 + fi
365 + fi
366 +
367 + err "Java 17 or newer is required by the Android SDK tools, but none could be set up."
368 + err "Install a JDK (for example: sdk install java), open a new terminal, then rerun Option 8."
369 + return 1
370 + }
371 +
372 + # Prints the download URL of the newest Android command line tools zip.
373 + # Tries the Android Studio download page first, then falls back to Google's
374 + # SDK repository manifest, which is a stable machine readable source.
375 + latest_cmdline_tools_url() {
376 + local tools_os=$1 file
377 +
378 + file=$(curl -fsSL --compressed https://developer.android.com/studio 2>/dev/null \
379 + | grep -oE "commandlinetools-${tools_os}-[0-9]+_latest\.zip" \
380 + | head -1)
381 +
382 + if [[ -z "$file" ]]; then
383 + file=$(curl -fsSL --compressed https://dl.google.com/android/repository/repository2-3.xml 2>/dev/null \
384 + | grep -oE "commandlinetools-${tools_os}-[0-9]+_latest\.zip" \
385 + | sort -t- -k3 -n \
386 + | tail -1)
387 + fi
388 +
389 + [[ -n "$file" ]] && printf 'https://dl.google.com/android/repository/%s\n' "$file"
390 + }
391 +
299 392 install_android() {
300 393 log "Installing Android SDK command-line tools..."
301 394
@@ -309,12 +402,6 @@ install_android() {
309 402 return 1
310 403 fi
311 404
312 - ANDROID_HOME="$HOME/Android/Sdk"
313 - ANDROID_SDK_ROOT="$ANDROID_HOME"
314 - export ANDROID_HOME ANDROID_SDK_ROOT
315 -
316 - mkdir -p "$ANDROID_HOME/cmdline-tools"
317 -
318 405 if [[ "$OS" == "macOS" ]]; then
319 406 TOOLS_OS="mac"
320 407 elif [[ "$OS_LOWER" == "linux" ]]; then
@@ -324,21 +411,32 @@ install_android() {
324 411 return 1
325 412 fi
326 413
414 + # sdkmanager is a Java program, so fail fast before downloading anything.
415 + ensure_android_java || return 1
416 +
417 + ANDROID_HOME="$HOME/Android/Sdk"
418 + ANDROID_SDK_ROOT="$ANDROID_HOME"
419 + export ANDROID_HOME ANDROID_SDK_ROOT
420 +
421 + mkdir -p "$ANDROID_HOME/cmdline-tools"
422 +
327 423 log "Finding latest Android command-line tools from Google..."
328 - TOOLS_URL=$(curl -fsSL https://developer.android.com/studio \
329 - | grep -o "https://dl.google.com/android/repository/commandlinetools-${TOOLS_OS}-[0-9]*_latest.zip" \
330 - | head -1)
424 + TOOLS_URL=$(latest_cmdline_tools_url "$TOOLS_OS")
331 425
332 426 if [[ -z "$TOOLS_URL" ]]; then
333 427 err "Could not find the Android command-line tools download URL."
334 428 return 1
335 429 fi
336 430
337 - log "Downloading Android command-line tools..."
431 + log "Downloading $TOOLS_URL..."
338 432 rm -rf /tmp/android-cmdline-tools /tmp/android-cmdline-tools.zip
339 433 mkdir -p /tmp/android-cmdline-tools
340 - curl -fsSL -o /tmp/android-cmdline-tools.zip "$TOOLS_URL"
341 - unzip -q /tmp/android-cmdline-tools.zip -d /tmp/android-cmdline-tools
434 + if ! curl -fsSL -o /tmp/android-cmdline-tools.zip "$TOOLS_URL" || \
435 + ! unzip -q /tmp/android-cmdline-tools.zip -d /tmp/android-cmdline-tools; then
436 + err "Failed to download or extract the Android command-line tools."
437 + rm -rf /tmp/android-cmdline-tools /tmp/android-cmdline-tools.zip
438 + return 1
439 + fi
342 440
343 441 rm -rf "$ANDROID_HOME/cmdline-tools/latest"
344 442 mkdir -p "$ANDROID_HOME/cmdline-tools/latest"
@@ -351,16 +449,23 @@ install_android() {
351 449 return 1
352 450 fi
353 451
452 + # stdout is silenced, stderr is kept so Java or network errors stay visible.
354 453 log "Accepting Android SDK licenses..."
355 - yes | "$SDKMANAGER" --sdk_root="$ANDROID_HOME" --licenses >/dev/null || true
454 + if ! yes | "$SDKMANAGER" --sdk_root="$ANDROID_HOME" --licenses >/dev/null; then
455 + err "sdkmanager could not run. See the error above."
456 + return 1
457 + fi
356 458
357 459 log "Installing Android SDK packages..."
358 - "$SDKMANAGER" --sdk_root="$ANDROID_HOME" \
460 + if ! "$SDKMANAGER" --sdk_root="$ANDROID_HOME" \
359 461 "cmdline-tools;latest" \
360 462 "platform-tools" \
361 463 "emulator" \
362 464 "platforms;android-36" \
363 - "build-tools;36.0.0"
465 + "build-tools;36.0.0"; then
466 + err "Failed to install Android SDK packages."
467 + return 1
468 + fi
364 469
365 470 add_to_path_config "ANDROID_SDK" 'export ANDROID_HOME="$HOME/Android/Sdk"
366 471 export ANDROID_SDK_ROOT="$ANDROID_HOME"
@@ -625,8 +730,12 @@ update_all() {
625 730
626 731 local sdkmanager="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-$HOME/Android/Sdk}}/cmdline-tools/latest/bin/sdkmanager"
627 732 if [[ -x "$sdkmanager" ]]; then
628 - yes | "$sdkmanager" --licenses >/dev/null || true
629 - "$sdkmanager" --update
733 + if ensure_android_java; then
734 + yes | "$sdkmanager" --licenses >/dev/null || true
735 + "$sdkmanager" --update
736 + else
737 + warn "Skipping the Android SDK update because no usable Java was found."
738 + fi
630 739 fi
631 740
632 741 if require_cmd docker; then
@@ -783,4 +892,4 @@ while true; do
783 892
784 893 printf "Press Enter to continue..."
785 894 read dummy || exit 0
786 - done
895 + done

weehong hat die Gist bearbeitet 1 week ago. Zu Änderung gehen

Keine Änderungen

weehong hat die Gist bearbeitet 2 months ago. Zu Änderung gehen

1 file changed, 1 insertion, 1 deletion

README.md

@@ -17,7 +17,7 @@ This script follows a **"Strict Official Source"** philosophy. It fetches binari
17 17 You can launch the interactive installer directly from your terminal with a single command:
18 18
19 19 ```bash
20 - zsh -c "$(curl -fsSL https://tinyurl.com/4rskc9e7)"
20 + bash -c "$(curl -fsSL https://tinyurl.com/4rskc9e7)"
21 21 ```
22 22
23 23 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`).

Vernon Wee Hong KOH hat die Gist bearbeitet 2 months ago. Zu Änderung gehen

2 files changed, 34 insertions, 16 deletions

README.md

@@ -9,7 +9,7 @@ This script follows a **"Strict Official Source"** philosophy. It fetches binari
9 9 * **Zero-Brew Dependency:** By default, it bypasses Homebrew entirely, using official APIs, release pages, and signed OS repositories (Homebrew is available as an optional install).
10 10 * **Idempotent:** Safe to run multiple times. It intelligently checks if a tool is already installed before attempting to download it.
11 11 * **Dynamic Versioning:** Uses official APIs (like GitHub Releases or `go.dev/VERSION`) when maintainers publish versioned binaries. OS-packaged tools track the supported distribution version and security updates.
12 - * **Auto-Path Management:** Intelligently injects paths into a dedicated `~/.pathrc` (or your `.bashrc`/`.zshrc`) without mangling your config files.
12 + * **Auto-Path Management:** Consistently writes installed-tool paths to `~/.zshrc`, regardless of which shell launches the installer.
13 13 * **Architecture Aware:** Automatically detects if you are running on Intel (`x86_64`) or Apple Silicon/ARM (`aarch64`/`arm64`) and downloads the correct binaries.
14 14
15 15 ## 🚀 Usage
@@ -17,7 +17,7 @@ This script follows a **"Strict Official Source"** philosophy. It fetches binari
17 17 You can launch the interactive installer directly from your terminal with a single command:
18 18
19 19 ```bash
20 - bash -c "$(curl -fsSL https://tinyurl.com/4rskc9e7)"
20 + zsh -c "$(curl -fsSL https://tinyurl.com/4rskc9e7)"
21 21 ```
22 22
23 23 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`).
@@ -64,7 +64,7 @@ Choose **19) Update All Installed Software** to update every detected tool in th
64 64
65 65 ## ⚠️ Important Notes & Troubleshooting
66 66
67 - * **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.
67 + * **Restart Your Shell:** After running the script for the first time, restart your terminal or run `source ~/.zshrc` to ensure all new PATH variables (like NVM, Go, or .NET) take effect.
68 68 * **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.
69 69 * **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.
70 70 * **Python Version on Linux:** Python follows the version supported by your distribution rather than the newest python.org patch release. This keeps installation precompiled, vendor-supported, and eligible for normal OS security updates.

menu.sh

@@ -24,21 +24,18 @@ fi
24 24 set -u
25 25
26 26 # =======================================================
27 - # 2. CROSS-SHELL NORMALIZATION
27 + # 2. SHELL NORMALIZATION
28 28 # =======================================================
29 + PROFILE_FILE="$HOME/.zshrc"
30 +
29 31 if [ -n "${ZSH_VERSION:-}" ]; then
30 32 # Zsh: Enable Bash-like word splitting for unquoted variables (menu input)
31 33 setopt shwordsplit 2>/dev/null || true
32 34 CURRENT_SHELL="zsh"
33 - PROFILE_FILE="$HOME/.zshrc"
34 35 elif [ -n "${BASH_VERSION:-}" ]; then
35 - # Bash
36 36 CURRENT_SHELL="bash"
37 - PROFILE_FILE="$HOME/.bashrc"
38 37 else
39 - # Fallback POSIX
40 38 CURRENT_SHELL="sh"
41 - PROFILE_FILE="$HOME/.profile"
42 39 fi
43 40
44 41 # =======================================================
@@ -249,17 +246,34 @@ install_python() {
249 246
250 247 install_go() {
251 248 log "Fetching latest Go version from official source..."
252 - LATEST_GO=$(curl -sL https://go.dev/VERSION?m=text | head -n 1)
249 + LATEST_GO=$(curl -fsSL 'https://go.dev/VERSION?m=text' | head -n 1) || {
250 + err "Could not determine the latest Go version."
251 + return 1
252 + }
253 253 TAR_FILE="${LATEST_GO}.${OS_LOWER}-${SYS_ARCH}.tar.gz"
254 +
255 + if [[ -x /usr/local/go/bin/go ]] && [[ "$(/usr/local/go/bin/go version)" == "go version $LATEST_GO "* ]]; then
256 + warn "$LATEST_GO is already installed."
257 + add_to_path_config "GO_BIN" 'export PATH="$PATH:/usr/local/go/bin"'
258 + return 0
259 + fi
254 260
255 261 log "Downloading $TAR_FILE..."
256 - curl -fsSL -o /tmp/go.tar.gz "https://go.dev/dl/$TAR_FILE"
262 + curl -fsSL -o /tmp/go.tar.gz "https://go.dev/dl/$TAR_FILE" || {
263 + err "Failed to download $TAR_FILE."
264 + rm -f /tmp/go.tar.gz
265 + return 1
266 + }
257 267
258 268 log "Installing to /usr/local/go..."
259 - sudo rm -rf /usr/local/go
260 - sudo tar -C /usr/local -xzf /tmp/go.tar.gz
261 - rm /tmp/go.tar.gz
269 + if ! sudo rm -rf /usr/local/go || ! sudo tar -C /usr/local -xzf /tmp/go.tar.gz; then
270 + err "Go installation failed. Run this installer from an interactive terminal so sudo can authenticate."
271 + rm -f /tmp/go.tar.gz
272 + return 1
273 + fi
274 + rm -f /tmp/go.tar.gz
262 275 add_to_path_config "GO_BIN" 'export PATH="$PATH:/usr/local/go/bin"'
276 + log "$(/usr/local/go/bin/go version) installed successfully."
263 277 }
264 278
265 279 install_sdkman() {
@@ -723,7 +737,11 @@ while true; do
723 737
724 738 # Bulletproof prompt for both Bash and Zsh
725 739 printf "Select options (space-separated): "
726 - read input
740 + if ! read input; then
741 + printf "\n"
742 + warn "Input closed. Exiting installer."
743 + exit 0
744 + fi
727 745
728 746 # Thanks to 'setopt shwordsplit' in Zsh, this behaves perfectly across both shells
729 747 for choice in $input; do
@@ -764,5 +782,5 @@ while true; do
764 782 done
765 783
766 784 printf "Press Enter to continue..."
767 - read dummy
785 + read dummy || exit 0
768 786 done

Vernon Wee Hong KOH hat die Gist bearbeitet 2 months ago. Zu Änderung gehen

2 files changed, 23 insertions

README.md

@@ -59,6 +59,8 @@ Choose **19) Update All Installed Software** to update every detected tool in th
59 59 * **Claude Code CLI:** Anthropic's official agent.
60 60 * **OpenAI Codex CLI:** Required NVM/Node.js to run.
61 61 * **OpenCode:** AI agent orchestration installed from the official OpenCode installer.
62 + * **Augment Code CLI (Auggie):** Installed from Augment's official NPM package; requires Node.js 20 or later.
63 + * **CodeRabbit CLI:** Local AI code reviews installed from CodeRabbit's official installer.
62 64
63 65 ## ⚠️ Important Notes & Troubleshooting
64 66

menu.sh

@@ -547,6 +547,19 @@ install_codex() {
547 547 npm i -g @openai/codex
548 548 }
549 549
550 + install_augment() {
551 + if require_cmd auggie; then warn "Augment Code CLI exists"; return; fi
552 + log "Installing Augment Code CLI (Auggie)..."
553 + if ! require_cmd npm; then err "Node.js 20+/NPM is required. Install NVM (3) first."; return 1; fi
554 + npm install -g @augmentcode/auggie
555 + }
556 +
557 + install_coderabbit() {
558 + if require_cmd coderabbit || require_cmd cr; then warn "CodeRabbit CLI exists"; return; fi
559 + log "Installing CodeRabbit CLI..."
560 + curl -fsSL https://cli.coderabbit.ai/install.sh | sh
561 + }
562 +
550 563 update_all() {
551 564 log "Updating all installed software from official sources..."
552 565
@@ -655,6 +668,10 @@ update_all() {
655 668 require_cmd claude && { curl -fsSL https://claude.ai/install.sh | $CURRENT_SHELL; }
656 669 require_cmd codex && npm install -g @openai/codex@latest
657 670 require_cmd opencode && { curl -fsSL https://opencode.ai/install | $CURRENT_SHELL; }
671 + require_cmd auggie && npm install -g @augmentcode/auggie@latest
672 + if require_cmd coderabbit || require_cmd cr; then
673 + curl -fsSL https://cli.coderabbit.ai/install.sh | sh
674 + fi
658 675
659 676 log "Finished updating installed software. Review any warnings or errors above."
660 677 }
@@ -693,6 +710,8 @@ show_menu() {
693 710 printf " 16) Claude Code CLI\n"
694 711 printf " 17) OpenAI Codex CLI\n"
695 712 printf " 18) OpenCode\n"
713 + printf " 20) Augment Code CLI (Auggie)\n"
714 + printf " 21) CodeRabbit CLI\n"
696 715 printf "${BLUE}==================================================${NC}\n"
697 716 printf " 19) Update All Installed Software\n"
698 717 printf " 99) Quit & Refresh Shell\n"
@@ -728,6 +747,8 @@ while true; do
728 747 17) install_codex ;;
729 748 18) install_opencode ;;
730 749 19) update_all ;;
750 + 20) install_augment ;;
751 + 21) install_coderabbit ;;
731 752 99)
732 753 log "Installation complete! Refreshing terminal environment..."
733 754

weehong hat die Gist bearbeitet 2 months ago. Zu Änderung gehen

2 files changed, 116 insertions

README.md

@@ -22,6 +22,8 @@ bash -c "$(curl -fsSL https://tinyurl.com/4rskc9e7)"
22 22
23 23 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`).
24 24
25 + Choose **19) Update All Installed Software** to update every detected tool in the menu from its official source. Tools that are not installed are skipped.
26 +
25 27 ## 🛠️ Included Tools
26 28
27 29 ### Essentials & Package Managers

menu.sh

@@ -547,6 +547,118 @@ install_codex() {
547 547 npm i -g @openai/codex
548 548 }
549 549
550 + update_all() {
551 + log "Updating all installed software from official sources..."
552 +
553 + if require_cmd apt-get; then
554 + sudo apt-get update && sudo apt-get install -y --only-upgrade \
555 + build-essential curl wget git jq unzip libssl-dev zlib1g-dev libffi-dev libsqlite3-dev \
556 + python3 python3-pip python3-venv
557 + elif require_cmd dnf; then
558 + sudo dnf upgrade -y python3 python3-pip
559 + elif require_cmd zypper; then
560 + sudo zypper --non-interactive update python3 python3-pip
561 + elif require_cmd pacman; then
562 + sudo pacman -Syu --noconfirm python python-pip
563 + elif require_cmd apk; then
564 + sudo apk upgrade
565 + fi
566 +
567 + if [[ "$OS" == "macOS" ]] && require_cmd python3; then
568 + install_python
569 + fi
570 +
571 + require_cmd brew && { brew update && brew upgrade; }
572 +
573 + if [[ -s "$HOME/.nvm/nvm.sh" ]]; then
574 + set +u
575 + export NVM_DIR="$HOME/.nvm"
576 + LATEST_NVM=$(curl -fsSL https://api.github.com/repos/nvm-sh/nvm/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
577 + curl -fsSL "https://raw.githubusercontent.com/nvm-sh/nvm/${LATEST_NVM}/install.sh" | PROFILE=/dev/null $CURRENT_SHELL
578 + \. "$NVM_DIR/nvm.sh"
579 + nvm install --lts --reinstall-packages-from=current
580 + nvm alias default 'lts/*'
581 + nvm use --lts
582 + set -u
583 + fi
584 +
585 + require_cmd go && install_go
586 +
587 + if [[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]]; then
588 + set +u
589 + source "$HOME/.sdkman/bin/sdkman-init.sh"
590 + sdk selfupdate force
591 + sdk upgrade
592 + set -u
593 + fi
594 +
595 + if require_cmd dotnet; then
596 + curl -fsSL https://dot.net/v1/dotnet-install.sh | $CURRENT_SHELL
597 + fi
598 +
599 + local sdkmanager="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-$HOME/Android/Sdk}}/cmdline-tools/latest/bin/sdkmanager"
600 + if [[ -x "$sdkmanager" ]]; then
601 + yes | "$sdkmanager" --licenses >/dev/null || true
602 + "$sdkmanager" --update
603 + fi
604 +
605 + if require_cmd docker; then
606 + if [[ "$OS" == "macOS" ]]; then
607 + docker desktop update || warn "Update Docker Desktop from its application menu."
608 + else
609 + curl -fsSL https://get.docker.com | sudo sh
610 + fi
611 + fi
612 +
613 + if require_cmd docker && docker ps -a --format '{{.Names}}' | grep -Fxq portainer; then
614 + log "Updating Portainer CE..."
615 + docker pull portainer/portainer-ce:sts && \
616 + docker stop portainer && \
617 + docker rm portainer && \
618 + docker run -d \
619 + -p 8000:8000 \
620 + -p 9443:9443 \
621 + --name portainer \
622 + --restart=always \
623 + -v /var/run/docker.sock:/var/run/docker.sock \
624 + -v portainer_data:/data \
625 + portainer/portainer-ce:sts
626 + fi
627 +
628 + if require_cmd aws; then
629 + if [[ "$OS" == "macOS" ]]; then
630 + curl -fsSL -o /tmp/AWSCLIV2.pkg https://awscli.amazonaws.com/AWSCLIV2.pkg && \
631 + sudo installer -pkg /tmp/AWSCLIV2.pkg -target /
632 + rm -f /tmp/AWSCLIV2.pkg
633 + elif require_cmd unzip; then
634 + curl -fsSL -o /tmp/awscliv2.zip "https://awscli.amazonaws.com/awscli-exe-linux-${AWS_ARCH}.zip" && \
635 + rm -rf /tmp/aws && unzip -q /tmp/awscliv2.zip -d /tmp && \
636 + sudo /tmp/aws/install --update
637 + rm -rf /tmp/aws /tmp/awscliv2.zip
638 + fi
639 + fi
640 +
641 + require_cmd gcloud && gcloud components update --quiet
642 + require_cmd firebase && npm install -g firebase-tools@latest
643 +
644 + if require_cmd gh; then
645 + log "Updating GitHub CLI..."
646 + LATEST_GH=$(curl -s https://api.github.com/repos/cli/cli/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
647 + TAR_NAME="gh_${LATEST_GH}_${OS_LOWER}_${SYS_ARCH}"
648 + curl -fsSL -o /tmp/gh.tar.gz "https://github.com/cli/cli/releases/download/v${LATEST_GH}/${TAR_NAME}.tar.gz" && \
649 + tar -xzf /tmp/gh.tar.gz -C /tmp && \
650 + sudo mv "/tmp/${TAR_NAME}/bin/gh" /usr/local/bin/
651 + sudo rm -rf "/tmp/${TAR_NAME}" /tmp/gh.tar.gz
652 + fi
653 +
654 + require_cmd infisical && npm install -g @infisical/cli@latest
655 + require_cmd claude && { curl -fsSL https://claude.ai/install.sh | $CURRENT_SHELL; }
656 + require_cmd codex && npm install -g @openai/codex@latest
657 + require_cmd opencode && { curl -fsSL https://opencode.ai/install | $CURRENT_SHELL; }
658 +
659 + log "Finished updating installed software. Review any warnings or errors above."
660 + }
661 +
550 662 # =======================================================
551 663 # MENU LOGIC
552 664 # =======================================================
@@ -582,6 +694,7 @@ show_menu() {
582 694 printf " 17) OpenAI Codex CLI\n"
583 695 printf " 18) OpenCode\n"
584 696 printf "${BLUE}==================================================${NC}\n"
697 + printf " 19) Update All Installed Software\n"
585 698 printf " 99) Quit & Refresh Shell\n"
586 699 printf "${BLUE}==================================================${NC}\n"
587 700 }
@@ -614,6 +727,7 @@ while true; do
614 727 16) install_claude ;;
615 728 17) install_codex ;;
616 729 18) install_opencode ;;
730 + 19) update_all ;;
617 731 99)
618 732 log "Installation complete! Refreshing terminal environment..."
619 733

weehong hat die Gist bearbeitet 2 months ago. Zu Änderung gehen

2 files changed, 43 insertions, 63 deletions

README.md

@@ -2,13 +2,13 @@
2 2
3 3 A robust, idempotent, and interactive bash script to bootstrap your macOS, Linux, or WSL development environment.
4 4
5 - 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).
5 + This script follows a **"Strict Official Source"** philosophy. It fetches binaries and installers directly from official maintainers, or from the operating system vendor's signed repositories when upstream does not publish native binaries for that platform.
6 6
7 7 ## ✨ Key Features
8 8
9 - * **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).
9 + * **Zero-Brew Dependency:** By default, it bypasses Homebrew entirely, using official APIs, release pages, and signed OS repositories (Homebrew is available as an optional install).
10 10 * **Idempotent:** Safe to run multiple times. It intelligently checks if a tool is already installed before attempting to download it.
11 - * **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.
11 + * **Dynamic Versioning:** Uses official APIs (like GitHub Releases or `go.dev/VERSION`) when maintainers publish versioned binaries. OS-packaged tools track the supported distribution version and security updates.
12 12 * **Auto-Path Management:** Intelligently injects paths into a dedicated `~/.pathrc` (or your `.bashrc`/`.zshrc`) without mangling your config files.
13 13 * **Architecture Aware:** Automatically detects if you are running on Intel (`x86_64`) or Apple Silicon/ARM (`aarch64`/`arm64`) and downloads the correct binaries.
14 14
@@ -30,7 +30,7 @@ Once the menu loads, simply **follow the interactive prompts**. You can select m
30 30
31 31 ### Languages & Runtimes
32 32 * **NVM (Node Version Manager):** Includes interactive prompt to install LTS or Latest Node.js immediately.
33 - * **Python 3:** Fetches the latest stable `.pkg` for Mac or compiles strictly from source for Linux.
33 + * **Python 3:** Fetches Python.org's latest stable `.pkg` for macOS. Linux and WSL install precompiled Python, pip, and venv from the signed OS-vendor repository without source compilation or third-party repositories.
34 34 * **Go:** Fetches the latest tarball and installs system-wide to `/usr/local/go`.
35 35 * **SDKMAN:** For managing Java, Kotlin, and Gradle.
36 36 * **.NET:** Installed via Microsoft's official script.
@@ -63,6 +63,7 @@ Once the menu loads, simply **follow the interactive prompts**. You can select m
63 63 * **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.
64 64 * **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.
65 65 * **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.
66 + * **Python Version on Linux:** Python follows the version supported by your distribution rather than the newest python.org patch release. This keeps installation precompiled, vendor-supported, and eligible for normal OS security updates.
66 67
67 68 ---
68 69 *Built for developers who want total control over their toolchain.*

menu.sh

@@ -188,22 +188,19 @@ install_nvm() {
188 188 }
189 189
190 190 install_python() {
191 - log "Fetching latest stable Python version..."
192 -
193 - LATEST_PY=$(
194 - curl -fsSL --compressed https://www.python.org/downloads/ |
195 - sed -nE 's/.*Download Python ([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' |
196 - head -1
197 - )
198 -
199 - if [[ -z "$LATEST_PY" ]]; then
200 - err "Could not detect the latest stable Python version from python.org."
201 - return 1
202 - fi
203 -
204 - log "Detected Stable Version: $LATEST_PY"
205 -
206 191 if [[ "$OS" == "macOS" ]]; then
192 + log "Fetching latest stable Python version..."
193 + LATEST_PY=$(
194 + curl -fsSL --compressed https://www.python.org/downloads/ |
195 + sed -nE 's/.*Download Python ([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' |
196 + head -1
197 + )
198 + if [[ -z "$LATEST_PY" ]]; then
199 + err "Could not detect the latest stable Python version from python.org."
200 + return 1
201 + fi
202 +
203 + log "Detected Stable Version: $LATEST_PY"
207 204 log "Downloading official macOS package..."
208 205 PKG_URL="https://www.python.org/ftp/python/${LATEST_PY}/python-${LATEST_PY}-macos11.pkg"
209 206 curl -fsSL --compressed -o /tmp/python.pkg "$PKG_URL" || {
@@ -219,53 +216,35 @@ install_python() {
219 216 }
220 217 rm /tmp/python.pkg
221 218 else
222 - log "Installing build dependencies (zlib, ssl, etc)..."
223 - sudo apt-get update && sudo apt-get install -y build-essential zlib1g-dev libssl-dev libffi-dev libsqlite3-dev || {
224 - err "Failed to install Python build dependencies."
225 - return 1
226 - }
227 -
228 - SRC_URL="https://www.python.org/ftp/python/${LATEST_PY}/Python-${LATEST_PY}.tgz"
229 -
230 - log "Downloading $SRC_URL..."
231 - curl -fSL --compressed -o /tmp/Python.tgz "$SRC_URL" || {
232 - err "Failed to download Python source from $SRC_URL"
233 - return 1
234 - }
235 -
236 - cd /tmp && tar -xzf Python.tgz && cd "Python-${LATEST_PY}" || {
237 - err "Failed to extract Python source archive."
238 - return 1
239 - }
240 -
241 - log "Configuring build (with ensurepip)..."
242 - ./configure --enable-optimizations --with-ensurepip=install || {
243 - err "Python configure step failed."
244 - return 1
245 - }
246 -
247 - log "Compiling Python (this may take a few minutes)..."
248 - sudo make altinstall || {
249 - err "Python build/install step failed."
250 - return 1
251 - }
252 -
253 - PY_MINOR=$(echo "$LATEST_PY" | cut -d. -f1,2)
254 -
255 - log "Setting up symlinks..."
256 - sudo ln -sf /usr/local/bin/python${PY_MINOR} /usr/local/bin/python3
257 -
258 - if [[ -f "/usr/local/bin/pip${PY_MINOR}" ]]; then
259 - sudo ln -sf /usr/local/bin/pip${PY_MINOR} /usr/local/bin/pip3
260 - log "Successfully linked pip3!"
219 + log "Installing precompiled Python from the official OS repository..."
220 + if require_cmd apt-get; then
221 + sudo apt-get update && \
222 + sudo apt-get install -y python3 python3-pip python3-venv
223 + elif require_cmd dnf; then
224 + sudo dnf install -y python3 python3-pip
225 + elif require_cmd zypper; then
226 + sudo zypper --non-interactive install python3 python3-pip
227 + elif require_cmd pacman; then
228 + sudo pacman -Sy --needed python python-pip
229 + elif require_cmd apk; then
230 + sudo apk add python3 py3-pip py3-virtualenv
261 231 else
262 - err "pip${PY_MINOR} was not generated during the build!"
232 + err "No supported official OS package manager found for Python."
233 + return 1
263 234 fi
264 -
265 - cd ~ && sudo rm -rf /tmp/Python*
266 235 fi
267 -
268 - log "Python $LATEST_PY installation sequence finished!"
236 +
237 + require_cmd python3 || { err "python3 was not installed successfully."; return 1; }
238 + python3 -m pip --version >/dev/null 2>&1 || {
239 + err "pip is unavailable for the installed Python."
240 + return 1
241 + }
242 + python3 -m venv --help >/dev/null 2>&1 || {
243 + err "venv is unavailable for the installed Python."
244 + return 1
245 + }
246 +
247 + log "$(python3 --version) installed with pip and venv support."
269 248 }
270 249
271 250 install_go() {
Neuer Älter