diff --git a/gcp/lib/common.sh b/gcp/lib/common.sh index ef4e5213..08578cd9 100644 --- a/gcp/lib/common.sh +++ b/gcp/lib/common.sh @@ -94,101 +94,55 @@ _gcp_check_auth() { # Interactive pickers for GCP project, zone, and machine type # ============================================================ -# Curated list of popular GCP machine types (value\tLabel\tHint) +# Curated list of popular GCP machine types (id|detail) _gcp_machine_type_options() { printf '%s\n' \ - "e2-micro e2-micro Shared CPU · 2 vCPU · 1 GB RAM (~\$7/mo)" \ - "e2-small e2-small Shared CPU · 2 vCPU · 2 GB RAM (~\$14/mo)" \ - "e2-medium e2-medium Shared CPU · 2 vCPU · 4 GB RAM (~\$28/mo) ← default" \ - "e2-standard-2 e2-standard-2 2 vCPU · 8 GB RAM (~\$49/mo)" \ - "e2-standard-4 e2-standard-4 4 vCPU · 16 GB RAM (~\$98/mo)" \ - "n2-standard-2 n2-standard-2 2 vCPU · 8 GB RAM, higher perf (~\$72/mo)" \ - "n2-standard-4 n2-standard-4 4 vCPU · 16 GB RAM, higher perf (~\$144/mo)" \ - "c4-standard-2 c4-standard-2 2 vCPU · 8 GB RAM, latest gen (~\$82/mo)" + "e2-micro|Shared CPU · 2 vCPU · 1 GB RAM (~\$7/mo)" \ + "e2-small|Shared CPU · 2 vCPU · 2 GB RAM (~\$14/mo)" \ + "e2-medium|Shared CPU · 2 vCPU · 4 GB RAM (~\$28/mo)" \ + "e2-standard-2|2 vCPU · 8 GB RAM (~\$49/mo)" \ + "e2-standard-4|4 vCPU · 16 GB RAM (~\$98/mo)" \ + "n2-standard-2|2 vCPU · 8 GB RAM, higher perf (~\$72/mo)" \ + "n2-standard-4|4 vCPU · 16 GB RAM, higher perf (~\$144/mo)" \ + "c4-standard-2|2 vCPU · 8 GB RAM, latest gen (~\$82/mo)" } -# Curated list of popular GCP zones (value\tLabel\tHint) +# Curated list of popular GCP zones (id|location) _gcp_zone_options() { printf '%s\n' \ - "us-central1-a us-central1-a Iowa, US ← default" \ - "us-east1-b us-east1-b South Carolina, US" \ - "us-east4-a us-east4-a N. Virginia, US" \ - "us-west1-a us-west1-a Oregon, US" \ - "us-west2-a us-west2-a Los Angeles, US" \ - "northamerica-northeast1-a northamerica-northeast1-a Montreal, Canada" \ - "europe-west1-b europe-west1-b Belgium" \ - "europe-west4-a europe-west4-a Netherlands" \ - "europe-west6-a europe-west6-a Zurich, Switzerland" \ - "asia-east1-a asia-east1-a Taiwan" \ - "asia-southeast1-a asia-southeast1-a Singapore" \ - "australia-southeast1-a australia-southeast1-a Sydney, Australia" + "us-central1-a|Iowa, US" \ + "us-east1-b|South Carolina, US" \ + "us-east4-a|N. Virginia, US" \ + "us-west1-a|Oregon, US" \ + "us-west2-a|Los Angeles, US" \ + "northamerica-northeast1-a|Montreal, Canada" \ + "europe-west1-b|Belgium" \ + "europe-west4-a|Netherlands" \ + "europe-west6-a|Zurich, Switzerland" \ + "asia-east1-a|Taiwan" \ + "asia-southeast1-a|Singapore" \ + "australia-southeast1-a|Sydney, Australia" } -# Fetch active GCP projects accessible to the authenticated user (value\tLabel\tHint) +# Fetch active GCP projects accessible to the authenticated user (id|name) _gcp_project_options() { gcloud projects list \ --filter="lifecycleState=ACTIVE" \ --format="value(projectId,name)" \ 2>/dev/null | \ - awk -F'\t' '{ print $1 "\t" $1 "\t" $2 }' -} - -# Generic GCP interactive picker. -# Respects the named env var (skip picker if already set). -# Tries `spawn pick` for a nice arrow-key UI, falls back to a numbered list. -# -# Usage: _gcp_interactive_pick DISPLAY_NAME ENV_VAR_NAME DEFAULT OPTIONS_FN -# Outputs the selected value on stdout. -_gcp_interactive_pick() { - local display="${1}" # e.g. "GCP machine type" - local env_var="${2}" # e.g. "GCP_MACHINE_TYPE" - local default_val="${3}" # e.g. "e2-medium" - local options_fn="${4}" # function name that prints "value\tLabel\tHint" lines - - # Honour an explicit env var override — no prompt needed - local current_val - current_val="${!env_var:-}" - if [[ -n "${current_val}" ]]; then - echo "${current_val}" - return - fi - - # Fetch available options - local options_text - options_text=$("${options_fn}") - if [[ -z "${options_text}" ]]; then - log_warn "Could not list ${display} options — using default: ${default_val}" - echo "${default_val}" - return - fi - - # Try `spawn pick` for a nicer arrow-key UI (available when user ran `spawn`) - if command -v spawn >/dev/null 2>&1; then - local picked - picked=$(printf '%s\n' "${options_text}" | \ - spawn pick --prompt "Select ${display}" --default "${default_val}") && { - echo "${picked}" - return - } - fi - - # Fallback: shared/common.sh numbered-list selector - # Convert "value\tLabel\tHint" → "value|Label" for _display_and_select - local items - items=$(printf '%s\n' "${options_text}" | awk -F'\t' '{ print $1 "|" $2 }') - _display_and_select "${display}" "${default_val}" "${default_val}" <<< "${items}" + awk -F'\t' '{ print $1 "|" $2 }' } _gcp_pick_machine_type() { - _gcp_interactive_pick "GCP machine type" "GCP_MACHINE_TYPE" "e2-medium" "_gcp_machine_type_options" + interactive_pick "GCP_MACHINE_TYPE" "e2-medium" "GCP machine types" _gcp_machine_type_options "e2-medium" } _gcp_pick_zone() { - _gcp_interactive_pick "GCP zone" "GCP_ZONE" "us-central1-a" "_gcp_zone_options" + interactive_pick "GCP_ZONE" "us-central1-a" "GCP zones" _gcp_zone_options "us-central1-a" } _gcp_pick_project() { - _gcp_interactive_pick "GCP project" "GCP_PROJECT" "" "_gcp_project_options" + interactive_pick "GCP_PROJECT" "" "GCP projects" _gcp_project_options } # Resolve and export GCP_PROJECT — prompt interactively if not already set diff --git a/shared/common.sh b/shared/common.sh index 645fbe31..905fecc7 100644 --- a/shared/common.sh +++ b/shared/common.sh @@ -3459,7 +3459,26 @@ _display_and_select() { return fi - # Fallback to numbered list when fzf is not available + # Try spawn pick for an arrow-key UI (available when the user ran `spawn`) + if command -v spawn >/dev/null 2>&1; then + # Convert pipe-delimited "id|label|extra..." → "id\tid\tlabel · extra · ..." + # so spawn pick shows the id as label and all detail fields as hint. + local spawn_input + spawn_input=$(printf '%s\n' "${items_array[@]}" | awk -F'|' '{ + val=$1; hint=""; + for (i=2; i<=NF; i++) { hint = hint (hint ? " \xc2\xb7 " : "") $i } + printf "%s\t%s\t%s\n", val, val, hint + }') + local picked + local spawn_default="${default_id:-${default_value}}" + picked=$(printf '%s\n' "${spawn_input}" | \ + spawn pick --prompt "Select ${prompt_text}" --default "${spawn_default}") && { + echo "${picked}" + return + } + fi + + # Fallback to numbered list when neither fzf nor spawn pick is available _numbered_list_select "${prompt_text}" "${default_value}" "${default_id}" "${items_array[@]}" }