Match ${XXX} environment variables (#1896)
parent
a25da1f5c6
commit
7ca8ad8cea
|
|
@ -579,6 +579,8 @@ K9s does provide additional environment variables for you to customize your plug
|
|||
* `$POD` while in a container view
|
||||
* `$COL-<RESOURCE_COLUMN_NAME>` use a given column name for a viewed resource. Must be prefixed by `COL-`!
|
||||
|
||||
Curly braces can be used to embed an environment variable inside another string, or if the column name contains special characters. (e.g. `${NAME}-example` or `${COL-%CPU/L}`)
|
||||
|
||||
### Example
|
||||
|
||||
This defines a plugin for viewing logs on a selected pod using `ctrl-l` for shortcut.
|
||||
|
|
|
|||
|
|
@ -13,30 +13,41 @@ import (
|
|||
// Env represent K9s and K8s available environment variables.
|
||||
type Env map[string]string
|
||||
|
||||
// EnvRX match $XXX custom arg.
|
||||
var envRX = regexp.MustCompile(`\$(\!?[\w|\d|\-|]+)`)
|
||||
// EnvRX match $XXX, $!XXX, ${XXX} or ${!XXX} custom arg.
|
||||
// |
|
||||
// | (g2)(group 3) (g5)( group 6 )
|
||||
// | ( group 1 ) ( group 4 )
|
||||
// | ( group 0 )
|
||||
var envRX = regexp.MustCompile(`(\$(!?)([\w\-]+))|(\$\{(!?)([\w\-%/: ]+)})`)
|
||||
|
||||
// keyFromSubmatch extracts the name and inverse flag of a match.
|
||||
func keyFromSubmatch(m []string) (key string, inverse bool) {
|
||||
// group 1 matches $XXX and $!XXX args.
|
||||
if m[1] != "" {
|
||||
return m[3], m[2] == "!"
|
||||
}
|
||||
// group 4 matches ${XXX} and ${!XXX} args.
|
||||
return m[6], m[5] == "!"
|
||||
}
|
||||
|
||||
// Substitute replaces env variable keys from in a string with their corresponding values.
|
||||
func (e Env) Substitute(arg string) (string, error) {
|
||||
kk := envRX.FindAllString(arg, -1)
|
||||
if len(kk) == 0 {
|
||||
matches := envRX.FindAllStringSubmatch(arg, -1)
|
||||
if len(matches) == 0 {
|
||||
return arg, nil
|
||||
}
|
||||
|
||||
// To prevent the substitution starts with the shorter environment variable,
|
||||
// sort with the length of the found environment variables.
|
||||
sort.Slice(kk, func(i, j int) bool {
|
||||
return len(kk[i]) > len(kk[j])
|
||||
sort.Slice(matches, func(i, j int) bool {
|
||||
return len(matches[i][0]) > len(matches[j][0])
|
||||
})
|
||||
|
||||
for _, k := range kk {
|
||||
key, inverse := k[1:], false
|
||||
if key[0] == '!' {
|
||||
key, inverse = key[1:], true
|
||||
}
|
||||
for _, m := range matches {
|
||||
key, inverse := keyFromSubmatch(m)
|
||||
v, ok := e[strings.ToUpper(key)]
|
||||
if !ok {
|
||||
log.Warn().Msgf("no k9s environment matching key %q:%q", k, key)
|
||||
log.Warn().Msgf("no k9s environment matching key %q:%q", m[0], key)
|
||||
continue
|
||||
}
|
||||
if b, err := strconv.ParseBool(v); err == nil {
|
||||
|
|
@ -45,7 +56,7 @@ func (e Env) Substitute(arg string) (string, error) {
|
|||
}
|
||||
v = fmt.Sprintf("%t", b)
|
||||
}
|
||||
arg = strings.Replace(arg, k, v, -1)
|
||||
arg = strings.Replace(arg, m[0], v, -1)
|
||||
}
|
||||
|
||||
return arg, nil
|
||||
|
|
|
|||
|
|
@ -19,20 +19,42 @@ func TestEnvReplace(t *testing.T) {
|
|||
"noMatch": {arg: "blah blah and $BLEE", e: "blah blah and $BLEE"},
|
||||
"lower": {arg: "And then $b happened", e: "And then blee happened"},
|
||||
"dash": {arg: "$col0", e: "fred"},
|
||||
"underline": {arg: "$RESOURCE_GROUP", e: "foo"},
|
||||
"mix": {arg: "$col0 and then $a but $B", e: "fred and then 10 but blee"},
|
||||
"subs": {arg: `{"spec" : {"suspend" : $COL0 }}`, e: `{"spec" : {"suspend" : fred }}`},
|
||||
"boolean": {arg: "$COL-BOOL", e: "false"},
|
||||
"invert": {arg: "$!COL-BOOL", e: "true"},
|
||||
|
||||
"simple_braces": {arg: "${A}", e: "10"},
|
||||
"embed_braces": {arg: "blabla${A}blabla", e: "blabla10blabla"},
|
||||
"open_braces": {arg: "${A", e: "${A"},
|
||||
"closed_braces": {arg: "$A}", e: "10}"},
|
||||
"substring_braces": {arg: "${A} and ${AA}", e: "10 and 20"},
|
||||
"with-text_braces": {arg: "Something ${A}", e: "Something 10"},
|
||||
"noMatch_braces": {arg: "blah blah and ${BLEE}", e: "blah blah and ${BLEE}"},
|
||||
"lower_braces": {arg: "And then ${b} happened", e: "And then blee happened"},
|
||||
"dash_braces": {arg: "${col0}", e: "fred"},
|
||||
"underline_braces": {arg: "${RESOURCE_GROUP}", e: "foo"},
|
||||
"mix_braces": {arg: "${col0} and then ${a} but ${B}", e: "fred and then 10 but blee"},
|
||||
"subs_braces": {arg: `{"spec" : {"suspend" : ${COL0} }}`, e: `{"spec" : {"suspend" : fred }}`},
|
||||
"boolean_braces": {arg: "${COL-BOOL}", e: "false"},
|
||||
"invert_braces": {arg: "${!COL-BOOL}", e: "true"},
|
||||
"special_braces": {arg: "${COL-%CPU/L}/${COL-MEM/R:L}", e: "10/32:32"},
|
||||
"space_braces": {arg: "${READINESS GATES}", e: "bar"},
|
||||
}
|
||||
|
||||
e := Env{
|
||||
"A": "10",
|
||||
"AA": "20",
|
||||
"B": "blee",
|
||||
"COL0": "fred",
|
||||
"FRED": "fred",
|
||||
"COL-NAME": "zorg",
|
||||
"COL-BOOL": "false",
|
||||
"A": "10",
|
||||
"AA": "20",
|
||||
"B": "blee",
|
||||
"COL0": "fred",
|
||||
"FRED": "fred",
|
||||
"COL-NAME": "zorg",
|
||||
"COL-BOOL": "false",
|
||||
"COL-%CPU/L": "10",
|
||||
"COL-MEM/R:L": "32:32",
|
||||
"RESOURCE_GROUP": "foo",
|
||||
"READINESS GATES": "bar",
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
|
|
|
|||
Loading…
Reference in New Issue