mirror of
https://github.com/mikefarah/yq.git
synced 2025-01-26 00:15:36 +00:00
Merge branch 'env_var'
This commit is contained in:
commit
5a5ac0dfef
76
pkg/yqlib/doc/Env Variable Operators.md
Normal file
76
pkg/yqlib/doc/Env Variable Operators.md
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
|
||||||
|
## Read string environment variable
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="cat meow" yq eval --null-input '.a = env(myenv)'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: cat meow
|
||||||
|
```
|
||||||
|
|
||||||
|
## Read boolean environment variable
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="true" yq eval --null-input '.a = env(myenv)'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Read numeric environment variable
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="12" yq eval --null-input '.a = env(myenv)'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: 12
|
||||||
|
```
|
||||||
|
|
||||||
|
## Read yaml environment variable
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="{b: fish}" yq eval --null-input '.a = env(myenv)'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: {b: fish}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Read boolean environment variable as a string
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="true" yq eval --null-input '.a = strenv(myenv)'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: "true"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Read numeric environment variable as a string
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="12" yq eval --null-input '.a = strenv(myenv)'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: "12"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dynamic key lookup with environment variable
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
cat: meow
|
||||||
|
dog: woof
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
myenv="cat" yq eval '.[env(myenv)]' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
meow
|
||||||
|
```
|
||||||
|
|
@ -48,6 +48,24 @@ will output
|
|||||||
frog
|
frog
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Dynamic keys
|
||||||
|
Expressions within [] can be used to dynamically lookup / calculate keys
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
b: apple
|
||||||
|
apple: crispy yum
|
||||||
|
banana: soft yum
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.[.b]' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
crispy yum
|
||||||
|
```
|
||||||
|
|
||||||
## Children don't exist
|
## Children don't exist
|
||||||
Nodes are added dynamically while traversing
|
Nodes are added dynamically while traversing
|
||||||
|
|
||||||
|
0
pkg/yqlib/doc/headers/Env Variable Operators.md
Normal file
0
pkg/yqlib/doc/headers/Env Variable Operators.md
Normal file
@ -70,6 +70,7 @@ var TraverseArray = &OperationType{Type: "TRAVERSE_ARRAY", NumArgs: 1, Precedenc
|
|||||||
var DocumentFilter = &OperationType{Type: "DOCUMENT_FILTER", NumArgs: 0, Precedence: 50, Handler: TraversePathOperator}
|
var DocumentFilter = &OperationType{Type: "DOCUMENT_FILTER", NumArgs: 0, Precedence: 50, Handler: TraversePathOperator}
|
||||||
var SelfReference = &OperationType{Type: "SELF", NumArgs: 0, Precedence: 50, Handler: SelfOperator}
|
var SelfReference = &OperationType{Type: "SELF", NumArgs: 0, Precedence: 50, Handler: SelfOperator}
|
||||||
var ValueOp = &OperationType{Type: "VALUE", NumArgs: 0, Precedence: 50, Handler: ValueOperator}
|
var ValueOp = &OperationType{Type: "VALUE", NumArgs: 0, Precedence: 50, Handler: ValueOperator}
|
||||||
|
var EnvOp = &OperationType{Type: "ENV", NumArgs: 0, Precedence: 50, Handler: EnvOperator}
|
||||||
var Not = &OperationType{Type: "NOT", NumArgs: 0, Precedence: 50, Handler: NotOperator}
|
var Not = &OperationType{Type: "NOT", NumArgs: 0, Precedence: 50, Handler: NotOperator}
|
||||||
var Empty = &OperationType{Type: "EMPTY", NumArgs: 50, Handler: EmptyOperator}
|
var Empty = &OperationType{Type: "EMPTY", NumArgs: 50, Handler: EmptyOperator}
|
||||||
|
|
||||||
|
52
pkg/yqlib/operator_env.go
Normal file
52
pkg/yqlib/operator_env.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
yaml "gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EnvOpPreferences struct {
|
||||||
|
StringValue bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func EnvOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
|
envName := pathNode.Operation.CandidateNode.Node.Value
|
||||||
|
log.Debug("EnvOperator, env name:", envName)
|
||||||
|
|
||||||
|
rawValue := os.Getenv(envName)
|
||||||
|
|
||||||
|
preferences := pathNode.Operation.Preferences.(*EnvOpPreferences)
|
||||||
|
|
||||||
|
var node *yaml.Node
|
||||||
|
if preferences.StringValue {
|
||||||
|
node = &yaml.Node{
|
||||||
|
Kind: yaml.ScalarNode,
|
||||||
|
Tag: "!!str",
|
||||||
|
Value: rawValue,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var dataBucket yaml.Node
|
||||||
|
decoder := yaml.NewDecoder(strings.NewReader(rawValue))
|
||||||
|
errorReading := decoder.Decode(&dataBucket)
|
||||||
|
if errorReading != nil {
|
||||||
|
return nil, errorReading
|
||||||
|
}
|
||||||
|
//first node is a doc
|
||||||
|
node = UnwrapDoc(&dataBucket)
|
||||||
|
}
|
||||||
|
log.Debug("ENV tag", node.Tag)
|
||||||
|
log.Debug("ENV value", node.Value)
|
||||||
|
log.Debug("ENV Kind", node.Kind)
|
||||||
|
|
||||||
|
target := &CandidateNode{
|
||||||
|
Path: make([]interface{}, 0),
|
||||||
|
Document: 0,
|
||||||
|
Filename: "",
|
||||||
|
Node: node,
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeToMap(target), nil
|
||||||
|
}
|
72
pkg/yqlib/operator_env_test.go
Normal file
72
pkg/yqlib/operator_env_test.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var envOperatorScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
description: "Read string environment variable",
|
||||||
|
environmentVariable: "cat meow",
|
||||||
|
expression: `.a = env(myenv)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], ()::a: cat meow\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Read boolean environment variable",
|
||||||
|
environmentVariable: "true",
|
||||||
|
expression: `.a = env(myenv)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], ()::a: true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Read numeric environment variable",
|
||||||
|
environmentVariable: "12",
|
||||||
|
expression: `.a = env(myenv)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], ()::a: 12\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Read yaml environment variable",
|
||||||
|
environmentVariable: "{b: fish}",
|
||||||
|
expression: `.a = env(myenv)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], ()::a: {b: fish}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Read boolean environment variable as a string",
|
||||||
|
environmentVariable: "true",
|
||||||
|
expression: `.a = strenv(myenv)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], ()::a: \"true\"\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Read numeric environment variable as a string",
|
||||||
|
environmentVariable: "12",
|
||||||
|
expression: `.a = strenv(myenv)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], ()::a: \"12\"\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Dynamic key lookup with environment variable",
|
||||||
|
environmentVariable: "cat",
|
||||||
|
document: `{cat: meow, dog: woof}`,
|
||||||
|
expression: `.[env(myenv)]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[cat], (!!str)::meow\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnvOperatorScenarios(t *testing.T) {
|
||||||
|
for _, tt := range envOperatorScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentScenarios(t, "Env Variable Operators", envOperatorScenarios)
|
||||||
|
}
|
@ -54,6 +54,15 @@ var traversePathOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[{}], (!!str)::frog\n",
|
"D0, P[{}], (!!str)::frog\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "Dynamic keys",
|
||||||
|
subdescription: `Expressions within [] can be used to dynamically lookup / calculate keys`,
|
||||||
|
document: `{b: apple, apple: crispy yum, banana: soft yum}`,
|
||||||
|
expression: `.[.b]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[apple], (!!str)::crispy yum\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Children don't exist",
|
description: "Children don't exist",
|
||||||
subdescription: "Nodes are added dynamically while traversing",
|
subdescription: "Nodes are added dynamically while traversing",
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
type expressionScenario struct {
|
type expressionScenario struct {
|
||||||
description string
|
description string
|
||||||
subdescription string
|
subdescription string
|
||||||
|
environmentVariable string
|
||||||
document string
|
document string
|
||||||
document2 string
|
document2 string
|
||||||
expression string
|
expression string
|
||||||
@ -61,6 +62,10 @@ func testScenario(t *testing.T, s *expressionScenario) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.environmentVariable != "" {
|
||||||
|
os.Setenv("myenv", s.environmentVariable)
|
||||||
|
}
|
||||||
|
|
||||||
results, err = treeNavigator.GetMatchingNodes(inputs, node)
|
results, err = treeNavigator.GetMatchingNodes(inputs, node)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -162,6 +167,14 @@ func documentInput(w *bufio.Writer, s expressionScenario) (string, string) {
|
|||||||
formattedDoc := ""
|
formattedDoc := ""
|
||||||
formattedDoc2 := ""
|
formattedDoc2 := ""
|
||||||
command := "eval"
|
command := "eval"
|
||||||
|
|
||||||
|
envCommand := ""
|
||||||
|
|
||||||
|
if s.environmentVariable != "" {
|
||||||
|
envCommand = fmt.Sprintf("myenv=\"%v\" ", s.environmentVariable)
|
||||||
|
os.Setenv("myenv", s.environmentVariable)
|
||||||
|
}
|
||||||
|
|
||||||
if s.document != "" {
|
if s.document != "" {
|
||||||
if s.dontFormatInputForDoc {
|
if s.dontFormatInputForDoc {
|
||||||
formattedDoc = s.document + "\n"
|
formattedDoc = s.document + "\n"
|
||||||
@ -188,14 +201,15 @@ func documentInput(w *bufio.Writer, s expressionScenario) (string, string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
writeOrPanic(w, "then\n")
|
writeOrPanic(w, "then\n")
|
||||||
|
|
||||||
if s.expression != "" {
|
if s.expression != "" {
|
||||||
writeOrPanic(w, fmt.Sprintf("```bash\nyq %v '%v' %v\n```\n", command, s.expression, files))
|
writeOrPanic(w, fmt.Sprintf("```bash\n%vyq %v '%v' %v\n```\n", envCommand, command, s.expression, files))
|
||||||
} else {
|
} else {
|
||||||
writeOrPanic(w, fmt.Sprintf("```bash\nyq %v %v\n```\n", command, files))
|
writeOrPanic(w, fmt.Sprintf("```bash\n%vyq %v %v\n```\n", envCommand, command, files))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
writeOrPanic(w, "Running\n")
|
writeOrPanic(w, "Running\n")
|
||||||
writeOrPanic(w, fmt.Sprintf("```bash\nyq %v --null-input '%v'\n```\n", command, s.expression))
|
writeOrPanic(w, fmt.Sprintf("```bash\n%vyq %v --null-input '%v'\n```\n", envCommand, command, s.expression))
|
||||||
}
|
}
|
||||||
return formattedDoc, formattedDoc2
|
return formattedDoc, formattedDoc2
|
||||||
}
|
}
|
||||||
|
@ -178,6 +178,28 @@ func stringValue(wrapped bool) lex.Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func envOp(strenv bool) lex.Action {
|
||||||
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
value := string(m.Bytes)
|
||||||
|
preferences := &EnvOpPreferences{}
|
||||||
|
|
||||||
|
if strenv {
|
||||||
|
// strenv( )
|
||||||
|
value = value[7 : len(value)-1]
|
||||||
|
preferences.StringValue = true
|
||||||
|
} else {
|
||||||
|
//env( )
|
||||||
|
value = value[4 : len(value)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
envOperation := CreateValueOperation(value, value)
|
||||||
|
envOperation.OperationType = EnvOp
|
||||||
|
envOperation.Preferences = preferences
|
||||||
|
|
||||||
|
return &Token{TokenType: OperationToken, Operation: envOperation}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func nullValue() lex.Action {
|
func nullValue() lex.Action {
|
||||||
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
return &Token{TokenType: OperationToken, Operation: CreateValueOperation(nil, string(m.Bytes))}, nil
|
return &Token{TokenType: OperationToken, Operation: CreateValueOperation(nil, string(m.Bytes))}, nil
|
||||||
@ -266,6 +288,8 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
lexer.Add([]byte(`~`), nullValue())
|
lexer.Add([]byte(`~`), nullValue())
|
||||||
|
|
||||||
lexer.Add([]byte(`"[^"]*"`), stringValue(true))
|
lexer.Add([]byte(`"[^"]*"`), stringValue(true))
|
||||||
|
lexer.Add([]byte(`strenv\([^\)]+\)`), envOp(true))
|
||||||
|
lexer.Add([]byte(`env\([^\)]+\)`), envOp(false))
|
||||||
|
|
||||||
lexer.Add([]byte(`\[`), literalToken(OpenCollect, false))
|
lexer.Add([]byte(`\[`), literalToken(OpenCollect, false))
|
||||||
lexer.Add([]byte(`\]`), literalToken(CloseCollect, true))
|
lexer.Add([]byte(`\]`), literalToken(CloseCollect, true))
|
||||||
|
Loading…
Reference in New Issue
Block a user