2021-01-08 10:07:46 +00:00
package yqlib
import (
2022-01-26 22:20:53 +00:00
"container/list"
2021-01-11 03:38:53 +00:00
"fmt"
2021-01-08 10:07:46 +00:00
"os"
2021-01-09 01:06:19 +00:00
"strings"
2021-01-08 10:07:46 +00:00
2022-03-19 23:56:50 +00:00
parse "github.com/a8m/envsubst/parse"
2021-01-08 10:07:46 +00:00
yaml "gopkg.in/yaml.v3"
)
2021-01-11 06:13:48 +00:00
type envOpPreferences struct {
2021-01-09 01:06:19 +00:00
StringValue bool
2022-03-19 23:56:50 +00:00
NoUnset bool
NoEmpty bool
FailFast bool
2021-01-09 01:06:19 +00:00
}
2021-01-08 10:07:46 +00:00
2021-02-02 07:17:59 +00:00
func envOperator ( d * dataTreeNavigator , context Context , expressionNode * ExpressionNode ) ( Context , error ) {
2021-01-12 23:18:53 +00:00
envName := expressionNode . Operation . CandidateNode . Node . Value
2021-01-08 10:07:46 +00:00
log . Debug ( "EnvOperator, env name:" , envName )
rawValue := os . Getenv ( envName )
2021-01-13 06:00:53 +00:00
preferences := expressionNode . Operation . Preferences . ( envOpPreferences )
2021-01-09 01:06:19 +00:00
var node * yaml . Node
if preferences . StringValue {
node = & yaml . Node {
Kind : yaml . ScalarNode ,
Tag : "!!str" ,
Value : rawValue ,
}
2021-01-11 03:38:53 +00:00
} else if rawValue == "" {
2021-02-02 07:17:59 +00:00
return Context { } , fmt . Errorf ( "Value for env variable '%v' not provided in env()" , envName )
2021-01-09 01:06:19 +00:00
} else {
var dataBucket yaml . Node
decoder := yaml . NewDecoder ( strings . NewReader ( rawValue ) )
errorReading := decoder . Decode ( & dataBucket )
if errorReading != nil {
2021-02-02 07:17:59 +00:00
return Context { } , errorReading
2021-01-09 01:06:19 +00:00
}
//first node is a doc
2021-01-12 23:00:51 +00:00
node = unwrapDoc ( & dataBucket )
2021-01-09 01:06:19 +00:00
}
log . Debug ( "ENV tag" , node . Tag )
log . Debug ( "ENV value" , node . Value )
log . Debug ( "ENV Kind" , node . Kind )
2021-01-12 08:36:28 +00:00
target := & CandidateNode { Node : node }
2021-01-08 10:07:46 +00:00
2021-02-02 07:17:59 +00:00
return context . SingleChildContext ( target ) , nil
2021-01-08 10:07:46 +00:00
}
2022-01-26 22:20:53 +00:00
func envsubstOperator ( d * dataTreeNavigator , context Context , expressionNode * ExpressionNode ) ( Context , error ) {
var results = list . New ( )
2022-03-19 23:56:50 +00:00
preferences := envOpPreferences { }
if expressionNode . Operation . Preferences != nil {
preferences = expressionNode . Operation . Preferences . ( envOpPreferences )
}
parser := parse . New ( "string" , os . Environ ( ) ,
& parse . Restrictions { NoUnset : preferences . NoUnset , NoEmpty : preferences . NoEmpty } )
if preferences . FailFast {
parser . Mode = parse . Quick
} else {
parser . Mode = parse . AllErrors
}
2022-01-26 22:20:53 +00:00
for el := context . MatchingNodes . Front ( ) ; el != nil ; el = el . Next ( ) {
candidate := el . Value . ( * CandidateNode )
node := unwrapDoc ( candidate . Node )
if node . Tag != "!!str" {
log . Warning ( "EnvSubstOperator, env name:" , node . Tag , node . Value )
return Context { } , fmt . Errorf ( "cannot substitute with %v, can only substitute strings. Hint: Most often you'll want to use '|=' over '=' for this operation" , node . Tag )
}
2022-03-19 23:56:50 +00:00
value , err := parser . Parse ( node . Value )
2022-01-26 22:20:53 +00:00
if err != nil {
return Context { } , err
}
targetNode := & yaml . Node { Kind : yaml . ScalarNode , Value : value , Tag : "!!str" }
result := candidate . CreateReplacement ( targetNode )
results . PushBack ( result )
}
return context . ChildContext ( results ) , nil
}