diff --git a/update-go-path.sh b/update-go-path.sh
index 2cd1b5f..483b2da 100755
--- a/update-go-path.sh
+++ b/update-go-path.sh
@@ -1,74 +1,172 @@
#!/bin/bash
-# Automatically detect Go installation and update .config for OpenWRT
+# Point the OpenWrt build at an installed Go toolchain.
+#
+# Go based packages (tailscale, adguardhome, easytier, cloudflared, ...) need a
+# host Go. By default OpenWrt builds the whole bootstrap chain from source; an
+# already installed Go can replace part or all of that:
+#
+# --external GOLANG_BUILD_BOOTSTRAP=n, host Go is built with the
+# installed toolchain directly (skips the entire chain,
+# requires a Go new enough for the target version)
+# default keep GOLANG_BUILD_BOOTSTRAP=y and only set the root, which
+# skips the initial bootstrap step
+#
+# Usage: ./update-go-path.sh [options]
+#
+# --external skip the bootstrap chain entirely (recommended)
+# --go-root
use this Go instead of auto-detecting
+# --skip-defconfig do not run make defconfig afterwards
+# -n, --dry-run show what would change, write nothing
+# -h, --help show this help
+#
+# Run it from the OpenWrt root: ./helper/update-go-path.sh
+#
# Author: Zhe Yuan
-set -e
+set -euo pipefail
umask 022
CONFIG_FILE=".config"
+EXTERNAL=false
+GO_ROOT=""
+RUN_DEFCONFIG=true
+DRY_RUN=false
-echo "========================================"
-echo " Go Path Auto Updater for OpenWRT"
-echo "========================================"
+info() { echo "[INFO] $*"; }
+warn() { echo "[WARN] $*"; }
+err() { echo "[ERROR] $*" >&2; }
-# --- Check for .config file ---
-if [ ! -f "$CONFIG_FILE" ]; then
- echo "[ERROR] No .config file found in current directory!"
- echo "Please run this script inside your OpenWRT build root."
- exit 1
-fi
+usage() { sed -n '2,25p' "$0" | sed 's/^# \{0,1\}//;s/^#$//'; }
-# --- Detect available Go installations ---
-GO_DIRS=(/usr/lib/go-*/)
-if [ ${#GO_DIRS[@]} -eq 0 ]; then
- echo "[ERROR] No Go installation found under /usr/lib/go-*"
- echo "Please install Go using: sudo apt install golang -y"
- exit 1
-fi
-
-# --- Extract version numbers ---
-GO_VERSIONS=()
-for dir in "${GO_DIRS[@]}"; do
- ver=$(basename "$dir" | sed -E 's/^go-([0-9]+\.[0-9]+).*$/\1/')
- GO_VERSIONS+=("$ver")
+while [ $# -gt 0 ]; do
+ case "$1" in
+ --external) EXTERNAL=true ;;
+ --go-root)
+ if [ $# -lt 2 ] || [ -z "${2:-}" ]; then err "--go-root requires a directory."; exit 1; fi
+ GO_ROOT="$2"; shift ;;
+ --skip-defconfig) RUN_DEFCONFIG=false ;;
+ -n|--dry-run) DRY_RUN=true ;;
+ -h|--help) usage; exit 0 ;;
+ *) err "Unknown option: $1"; echo "Run '$0 --help' for usage." >&2; exit 1 ;;
+ esac
+ shift
done
-# --- Sort versions and pick the latest ---
-IFS=$'\n' sorted=($(sort -V <<<"${GO_VERSIONS[*]}"))
-LATEST_VER="${sorted[-1]}"
-LATEST_PATH="/usr/lib/go-${LATEST_VER}/"
+echo "========================================"
+echo " Go Toolchain Setup for OpenWrt"
+echo "========================================"
-echo "[INFO] Found Go versions: ${GO_VERSIONS[*]}"
-echo "[INFO] Using latest Go version: $LATEST_VER"
-echo "[INFO] Path: $LATEST_PATH"
-
-# --- Check if multiple versions exist ---
-if [ ${#GO_VERSIONS[@]} -gt 1 ]; then
- echo "[WARN] Multiple Go versions detected!"
- echo "If you prefer to use an older version, modify manually:"
- echo " CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=\"/usr/lib/go-X.XX/\""
- echo
+if [ ! -f "$CONFIG_FILE" ]; then
+ err "No .config in the current directory."
+ err "From the OpenWrt root, run it as: ./helper/$(basename "$0")"
+ exit 1
fi
-# --- Update .config ---
-if grep -q '^CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=' "$CONFIG_FILE"; then
- echo "[INFO] Updating existing CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT..."
- sed -i "s|^CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=.*|CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=\"${LATEST_PATH}\"|" "$CONFIG_FILE"
+# --- Locate a Go installation --------------------------------------------
+if [ -z "$GO_ROOT" ]; then
+ # nullglob only drops words that actually contain a wildcard; a literal path
+ # such as /usr/local/go/ survives even when it does not exist. So collect
+ # candidates and keep only the directories that are really there.
+ shopt -s nullglob
+ CANDIDATES=(/usr/lib/go-*/ /usr/local/go/ /usr/lib/golang/)
+ shopt -u nullglob
+
+ GO_DIRS=()
+ for dir in "${CANDIDATES[@]}"; do
+ [ -d "$dir" ] && GO_DIRS+=("$dir")
+ done
+
+ if [ ${#GO_DIRS[@]} -eq 0 ]; then
+ err "No Go installation found under /usr/lib/go-*, /usr/local/go or /usr/lib/golang."
+ err "Install one with: sudo apt install golang-1.24-go"
+ err "or keep the default, where OpenWrt builds its own bootstrap chain."
+ exit 1
+ fi
+
+ BEST_VER=""
+ for dir in "${GO_DIRS[@]}"; do
+ [ -x "${dir}bin/go" ] || continue
+ ver="$("${dir}bin/go" version 2>/dev/null | awk '{print $3}' | sed 's/^go//')"
+ [ -n "$ver" ] || continue
+ if [ -z "$BEST_VER" ] ||
+ [ "$(printf '%s\n%s\n' "$BEST_VER" "$ver" | sort -V | tail -n 1)" = "$ver" ]; then
+ BEST_VER="$ver"
+ GO_ROOT="$dir"
+ fi
+ done
+
+ if [ -z "$GO_ROOT" ]; then
+ err "Found Go directories but none contained a working bin/go."
+ exit 1
+ fi
+
+ if [ ${#GO_DIRS[@]} -gt 1 ]; then
+ info "Go installations found: ${GO_DIRS[*]}"
+ info "Using the newest; override with --go-root ."
+ fi
+fi
+
+GO_ROOT="${GO_ROOT%/}/"
+if [ ! -x "${GO_ROOT}bin/go" ]; then
+ err "No usable Go compiler at ${GO_ROOT}bin/go"
+ exit 1
+fi
+GO_VER="$("${GO_ROOT}bin/go" version | awk '{print $3}' | sed 's/^go//')"
+
+info "Go toolchain: $GO_ROOT (version $GO_VER)"
+
+# --- Warn if it is older than what the tree wants -------------------------
+BOOTSTRAP_MK="feeds/packages/lang/golang/golang-bootstrap/Makefile"
+if [ -f "$BOOTSTRAP_MK" ]; then
+ NEED="$(awk -F':=' '/^GO_VERSION_MAJOR_MINOR/ {print $2; exit}' "$BOOTSTRAP_MK" | tr -d ' ')"
+ if [ -n "$NEED" ] &&
+ [ "$(printf '%s\n%s\n' "$NEED" "$GO_VER" | sort -V | head -n 1)" != "$NEED" ]; then
+ warn "Installed Go $GO_VER is older than the bootstrap version $NEED this tree expects."
+ warn "The build may fail; consider installing golang-$NEED-go."
+ fi
+fi
+
+# --- Apply ----------------------------------------------------------------
+set_config() {
+ local key="$1" val="$2"
+ if [ "$DRY_RUN" = true ]; then
+ echo "[DRY-RUN] $key=$val"
+ return
+ fi
+ # Drop every existing form of the symbol, then append once.
+ sed -i "/^${key}=/d;/^# ${key} is not set$/d" "$CONFIG_FILE"
+ if [ "$val" = "n" ]; then
+ echo "# $key is not set" >> "$CONFIG_FILE"
+ else
+ echo "$key=$val" >> "$CONFIG_FILE"
+ fi
+}
+
+set_config CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT "\"$GO_ROOT\""
+
+if [ "$EXTERNAL" = true ]; then
+ set_config CONFIG_GOLANG_BUILD_BOOTSTRAP n
+ info "Bootstrap chain disabled; host Go is built with the installed toolchain."
else
- echo "[INFO] Adding CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT..."
- echo "CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=\"${LATEST_PATH}\"" >> "$CONFIG_FILE"
+ set_config CONFIG_GOLANG_BUILD_BOOTSTRAP y
+ info "Bootstrap chain kept (only the initial step is skipped)."
+ info "Pass --external to skip it entirely."
fi
-# --- Verify result ---
-echo
-echo "[SUCCESS] Go path updated in .config:"
-grep 'CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT' "$CONFIG_FILE"
+if [ "$DRY_RUN" = true ]; then
+ echo
+ info "Dry run complete; .config was not modified."
+ exit 0
+fi
+
+if [ "$RUN_DEFCONFIG" = true ]; then
+ info "Running make defconfig..."
+ make defconfig >/dev/null
+fi
echo
echo "========================================"
-echo "✅ Go path update complete!"
+echo "OK Go configuration updated."
echo "========================================"
-echo
-echo "👉 If you wish to override manually, edit .config and change:"
-echo " CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=\"/usr/lib/go-X.XX/\""
+grep -E '^(CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT|CONFIG_GOLANG_BUILD_BOOTSTRAP)|^# CONFIG_GOLANG_BUILD_BOOTSTRAP' "$CONFIG_FILE" | sed 's/^/ /'
echo