Skip to content

Commit

Permalink
envsubst: Add strict mode
Browse files Browse the repository at this point in the history
Incorporate drone/envsubst#34

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
  • Loading branch information
stefanprodan committed Apr 7, 2024
1 parent 03e96b4 commit a3992b6
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 11 deletions.
14 changes: 11 additions & 3 deletions envsubst/eval.go
Expand Up @@ -23,7 +23,7 @@ package envsubst
import "os"

// Eval replaces ${var} in the string based on the mapping function.
func Eval(s string, mapping func(string) string) (string, error) {
func Eval(s string, mapping func(string) (string, bool)) (string, error) {
t, err := Parse(s)
if err != nil {
return s, err
Expand All @@ -34,6 +34,14 @@ func Eval(s string, mapping func(string) string) (string, error) {
// EvalEnv replaces ${var} in the string according to the values of the
// current environment variables. References to undefined variables are
// replaced by the empty string.
func EvalEnv(s string) (string, error) {
return Eval(s, os.Getenv)
func EvalEnv(s string, strict bool) (string, error) {
mapping := Getenv
if strict {
mapping = os.LookupEnv
}
return Eval(s, mapping)
}

func Getenv(s string) (string, bool) {
return os.Getenv(s), true
}
62 changes: 59 additions & 3 deletions envsubst/eval_test.go
Expand Up @@ -20,7 +20,10 @@ limitations under the License.

package envsubst

import "testing"
import (
"errors"
"testing"
)

// test cases sourced from tldp.org
// http://www.tldp.org/LDP/abs/html/parameter-substitution.html
Expand Down Expand Up @@ -230,8 +233,8 @@ func TestExpand(t *testing.T) {
for _, expr := range expressions {
t.Run(expr.input, func(t *testing.T) {
t.Logf(expr.input)
output, err := Eval(expr.input, func(s string) string {
return expr.params[s]
output, err := Eval(expr.input, func(s string) (string, bool) {
return expr.params[s], true
})
if err != nil {
t.Errorf("Want %q expanded but got error %q", expr.input, err)
Expand All @@ -246,3 +249,56 @@ func TestExpand(t *testing.T) {
})
}
}

func TestExpandStrict(t *testing.T) {
var expressions = []struct {
params map[string]string
input string
output string
wantErr error
}{
// text-only
{
params: map[string]string{},
input: "abcdEFGH28ij",
output: "abcdEFGH28ij",
wantErr: nil,
},
// existing
{
params: map[string]string{"foo": "bar"},
input: "${foo}",
output: "bar",
wantErr: nil,
},
// missing
{
params: map[string]string{},
input: "${missing}",
output: "",
wantErr: errVarNotSet,
},
}

for _, expr := range expressions {
t.Run(expr.input, func(t *testing.T) {
t.Logf(expr.input)
output, err := Eval(expr.input, func(s string) (string, bool) {
v, exists := expr.params[s]
return v, exists
})
if expr.wantErr == nil && err != nil {
t.Errorf("Want %q expanded but got error %q", expr.input, err)
}
if expr.wantErr != nil && !errors.Is(err, expr.wantErr) {
t.Errorf("Want error %q but got error %q", expr.wantErr, err)
}
if output != expr.output {
t.Errorf("Want %q expanded to %q, got %q",
expr.input,
expr.output,
output)
}
})
}
}
16 changes: 11 additions & 5 deletions envsubst/template.go
Expand Up @@ -22,8 +22,9 @@ package envsubst

import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"

"github.com/fluxcd/pkg/envsubst/parse"
)
Expand All @@ -36,7 +37,7 @@ type state struct {
node parse.Node // current node

// maps variable names to values
mapper func(string) string
mapper func(string) (value string, exists bool)
}

// Template is the representation of a parsed shell format string.
Expand All @@ -58,15 +59,15 @@ func Parse(s string) (t *Template, err error) {
// ParseFile creates a new shell format template and parses the template
// definition from the named file.
func ParseFile(path string) (*Template, error) {
b, err := ioutil.ReadFile(path)
b, err := os.ReadFile(path)
if err != nil {
return nil, err
}
return Parse(string(b))
}

// Execute applies a parsed template to the specified data mapping.
func (t *Template) Execute(mapping func(string) string) (str string, err error) {
func (t *Template) Execute(mapping func(string) (string, bool)) (str string, err error) {
b := new(bytes.Buffer)
s := new(state)
s.node = t.tree.Root
Expand Down Expand Up @@ -107,6 +108,8 @@ func (t *Template) evalList(s *state, node *parse.ListNode) (err error) {
return nil
}

var errVarNotSet = fmt.Errorf("variable not set (strict mode)")

func (t *Template) evalFunc(s *state, node *parse.FuncNode) error {
var w = s.writer
var buf bytes.Buffer
Expand All @@ -126,8 +129,11 @@ func (t *Template) evalFunc(s *state, node *parse.FuncNode) error {
s.writer = w
s.node = node

v := s.mapper(node.Param)
v, exists := s.mapper(node.Param)

if node.Name == "" && !exists {
return fmt.Errorf("%w: %q", errVarNotSet, node.Param)
}
fn := lookupFunc(node.Name, len(args))

_, err := io.WriteString(s.writer, fn(v, args...))
Expand Down

0 comments on commit a3992b6

Please sign in to comment.