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