b26b5002633e865b70e17933536fe4dc99127898

Author
Iyigun Cevik <iyigun@cevik.io>
Committer
GitHub <noreply@github.com>
Date

Message

feat(juju): add native zsh completion and fix plugin utilities (#13663)

Diff

This diff is truncated to protect this page.

  1diff --git a/plugins/juju/_juju b/plugins/juju/_juju
  2new file mode 100644
  3index 0000000000000000000000000000000000000000..4e08ba6adb2f78db3877b0d2382cdf1a1b3159ba
  4--- /dev/null
  5+++ b/plugins/juju/_juju
  6@@ -0,0 +1,231 @@
  7+#compdef juju
  8+(( $+functions[compdef] )) && compdef _juju juju
  9+
 10+# zsh completion for juju                                  -*- shell-script -*-
 11+
 12+__juju_debug()
 13+{
 14+    local file="$BASH_COMP_DEBUG_FILE"
 15+    if [[ -n ${file} ]]; then
 16+        echo "$*" >> "${file}"
 17+    fi
 18+}
 19+
 20+__juju_help_options()
 21+{
 22+    local out line token cleaned desc f
 23+    local -a opts pending
 24+    typeset -U opts
 25+
 26+    __juju_debug "[options] called with args: $*"
 27+    out=$(command juju help "$@" 2>/dev/null)
 28+    local rc=$?
 29+    __juju_debug "[options] juju help exit code: $rc, output length: ${#out}"
 30+    (( rc )) && return 1
 31+
 32+    while IFS= read -r line; do
 33+        if [[ "$line" =~ '^[[:space:]]{0,3}-' ]]; then
 34+            for f in "${pending[@]}"; do opts+=("$f"); done
 35+            pending=()
 36+            for token in ${(z)line}; do
 37+                cleaned="${token%%,*}"
 38+                cleaned="${cleaned%%;*}"
 39+                cleaned="${cleaned%%]*}"
 40+                cleaned="${cleaned%%)*}"
 41+                cleaned="${cleaned%%=<*}"
 42+                cleaned="${cleaned%%=*}"
 43+                cleaned="${cleaned%%<*}"
 44+                cleaned="${cleaned%%\[*}"
 45+                cleaned="${cleaned%%\(*}"
 46+                [[ "$cleaned" == --* || "$cleaned" == -[[:alnum:]] ]] || continue
 47+                [[ "$cleaned" == "-" || "$cleaned" == "--" ]] && continue
 48+                __juju_debug "[options] found flag: $cleaned"
 49+                pending+=("$cleaned")
 50+            done
 51+        elif (( ${#pending} )) && [[ -n "$line" ]]; then
 52+            desc="${line#"${line%%[![:space:]]*}"}"
 53+            desc="${desc//:/\\:}"
 54+            __juju_debug "[options] desc for ${pending[*]}: $desc"
 55+            for f in "${pending[@]}"; do opts+=("${f}:${desc}"); done
 56+            pending=()
 57+        elif [[ -z "$line" ]]; then
 58+            for f in "${pending[@]}"; do opts+=("$f"); done
 59+            pending=()
 60+        fi
 61+    done < <(printf "%s\n" "$out")
 62+
 63+    for f in "${pending[@]}"; do opts+=("$f"); done
 64+    __juju_debug "[options] total opts: ${#opts}, first few: ${opts[1]} ${opts[2]} ${opts[3]}"
 65+
 66+    printf "%s\n" "${opts[@]}"
 67+}
 68+
 69+
 70+__juju_help_commands()
 71+{
 72+    local line cmd desc out
 73+    out=$(command juju help commands 2>/dev/null) || return 1
 74+
 75+    while IFS= read -r line; do
 76+        # Strip leading whitespace
 77+        line="${line#"${line%%[![:space:]]*}"}"
 78+        # Only process lines starting with an alphanumeric (command names)
 79+        [[ "$line" =~ '^[[:alnum:]]' ]] || continue
 80+        # Split on the first run of 2+ spaces: left = cmd, right = description
 81+        cmd="${line%%  *}"
 82+        # Validate it's a clean command token (no spaces, only alnum and dash)
 83+        [[ "$cmd" =~ '^[[:alnum:]][[:alnum:]-]*$' ]] || continue
 84+        desc="${line#"$cmd"}"
 85+        desc="${desc#"${desc%%[![:space:]]*}"}"
 86+        if [[ -n "$desc" ]]; then
 87+            printf "%s:%s\n" "$cmd" "$desc"
 88+        else
 89+            printf "%s\n" "$cmd"
 90+        fi
 91+    done <<< "$out"
 92+}
 93+
 94+__juju_models()
 95+{
 96+    # Optional argument: controller name. If given, fetch models for that controller.
 97+    if [[ -n "$1" ]]; then
 98+        command juju models -c "$1" --format=json 2>/dev/null \
 99+            | command jq -r '.models[]."short-name"' 2>/dev/null
100+    else
101+        command juju models --format=json 2>/dev/null \
102+            | command jq -r '.models[]."short-name"' 2>/dev/null
103+    fi
104+}
105+
106diff --git a/plugins/juju/juju.plugin.zsh b/plugins/juju/juju.plugin.zsh
107index 3c159da2206ac4a2fa0b964d61677c46d8b96d18..a7bd98d7e77503e1123b5b47eef804996478da14 100644
108--- a/plugins/juju/juju.plugin.zsh
109+++ b/plugins/juju/juju.plugin.zsh
110@@ -1,17 +1,5 @@
111 # ---------------------------------------------------------- #
112 # Aliases and functions for juju (https://juju.is)           #
113-# ---------------------------------------------------------- #
114-
115-# Load TAB completions
116-# You need juju's bash completion script installed. By default bash-completion's
117-# location will be used (i.e. pkg-config --variable=completionsdir bash-completion).
118-completion_file="$(pkg-config --variable=completionsdir bash-completion 2>/dev/null)/juju" || \
119-  completion_file="/usr/share/bash-completion/completions/juju"
120-[[ -f "$completion_file" ]] && source "$completion_file"
121-unset completion_file
122-
123-# ---------------------------------------------------------- #
124-# Aliases (in alphabetic order)                              #
125 #                                                            #
126 # Generally,                                                 #
127 #   - `!` means --force --no-wait -y                         #
128@@ -132,6 +120,7 @@ jclean() {
129   fi
130 
131   echo
132+  local controller
133   for controller in ${=controllers}; do
134     timeout 2m juju destroy-controller --destroy-all-models --destroy-storage --force --no-wait -y $controller
135     timeout 2m juju kill-controller -y -t 0 $controller 2>/dev/null
136@@ -165,10 +154,11 @@ jreld() {
137 
138 # Return Juju current controller
139 jcontroller() {
140-  local controller="$(awk '/current-controller/ {print $2}' ~/.local/share/juju/controllers.yaml)"
141-  if [[ -z "$controller" ]]; then
142-    return 1
143-  fi
144+  local file="${JUJU_DATA:-$HOME/.local/share/juju}/controllers.yaml"
145+  [[ -f "$file" ]] || return 1
146+
147+  local controller="$(awk '/current-controller/ {print $2}' "$file")"
148+  [[ -z "$controller" ]] && return 1
149 
150   echo $controller
151   return 0
152@@ -176,6 +166,9 @@ jcontroller() {
153 
154 # Return Juju current model
155 jmodel() {
156+  local file="${JUJU_DATA:-$HOME/.local/share/juju}/models.yaml"
157+  [[ -f "$file" ]] || return 1
158+
159   local yqbin="$(whereis yq | awk '{print $2}')"
160 
161   if [[ -z "$yqbin" ]]; then
162@@ -183,9 +176,10 @@ jmodel() {
163     return 1
164   fi
165 
166-  local model="$(yq e ".controllers.$(jcontroller).current-model" < ~/.local/share/juju/models.yaml | cut -d/ -f2)"
167+  local controller="$(jcontroller)"
168+  local model="$(yq e ".controllers.[\"${controller}\"].current-model" < "${file}" | cut -d/ -f2)"
169 
170-  if [[ -z "$model" ]]; then
171+  if [[ -z "$model" || $model == "null" ]]; then
172     echo "--"
173     return 1
174   fi
175@@ -194,9 +188,10 @@ jmodel() {
176   return 0
177 }
178 
179-# Watch juju status, with optional interval (default: 5 sec)
180+# Watch juju status, with optional interval (default: 1 sec)
181 wjst() {
182-  local interval="${1:-5}"
183+  command -v juju >/dev/null 2>&1 || return 1
184+  local interval="${1:-1}"
185   shift $(( $# > 0 ))
186   watch -n "$interval" --color juju status --relations --color "$@"
187 }