Skip to content

Commit

Permalink
Select the Jsonnet implementation when constructing the loader
Browse files Browse the repository at this point in the history
Add the `path` as a struct member of the Go-jsonnet implementation. We
have this available when we construct the loader. This lets us then drop
the same argument from `EvaluateAnonymousSnippet()` in the interface -
as not all implementations need it.
  • Loading branch information
iainlane committed Aug 24, 2023
1 parent 6d251a5 commit 82ae5ae
Show file tree
Hide file tree
Showing 19 changed files with 88 additions and 68 deletions.
22 changes: 8 additions & 14 deletions pkg/jsonnet/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ import (
"github.com/pkg/errors"
"github.com/rs/zerolog/log"

"github.com/grafana/tanka/pkg/jsonnet/implementation"
"github.com/grafana/tanka/pkg/jsonnet/implementation/goimpl"
"github.com/grafana/tanka/pkg/jsonnet/implementation/types"
"github.com/grafana/tanka/pkg/jsonnet/implementations/goimpl"
"github.com/grafana/tanka/pkg/jsonnet/implementations/types"
"github.com/grafana/tanka/pkg/jsonnet/jpath"
)

Expand Down Expand Up @@ -81,40 +80,35 @@ func (o Opts) Clone() Opts {
// EvaluateFile evaluates the Jsonnet code in the given file and returns the
// result in JSON form. It disregards opts.ImportPaths in favor of automatically
// resolving these according to the specified file.
func EvaluateFile(jsonnetFile string, opts Opts) (string, error) {
func EvaluateFile(impl types.JsonnetImplementation, jsonnetFile string, opts Opts) (string, error) {
evalFunc := func(evaluator types.JsonnetEvaluator) (string, error) {
return evaluator.EvaluateFile(jsonnetFile)
}
data, err := os.ReadFile(jsonnetFile)
if err != nil {
return "", err
}
return evaluateSnippet(evalFunc, jsonnetFile, string(data), opts)
return evaluateSnippet(impl, evalFunc, jsonnetFile, string(data), opts)
}

// Evaluate renders the given jsonnet into a string
// If cache options are given, a hash from the data will be computed and
// the resulting string will be cached for future retrieval
func Evaluate(path, data string, opts Opts) (string, error) {
func Evaluate(path string, impl types.JsonnetImplementation, data string, opts Opts) (string, error) {
evalFunc := func(evaluator types.JsonnetEvaluator) (string, error) {
return evaluator.EvaluateAnonymousSnippet(path, data)
return evaluator.EvaluateAnonymousSnippet(data)
}
return evaluateSnippet(evalFunc, path, data, opts)
return evaluateSnippet(impl, evalFunc, path, data, opts)
}

type evalFunc func(evaluator types.JsonnetEvaluator) (string, error)

func evaluateSnippet(evalFunc evalFunc, path, data string, opts Opts) (string, error) {
func evaluateSnippet(jsonnetImpl types.JsonnetImplementation, evalFunc evalFunc, path, data string, opts Opts) (string, error) {
var cache *FileEvalCache
if opts.CachePath != "" && opts.PathIsCached(path) {
cache = NewFileEvalCache(opts.CachePath)
}

// Create VM
jsonnetImpl, err := implementation.GetByName(opts.JsonnetImplementation)
if err != nil {
return "", err
}
jpath, _, _, err := jpath.Resolve(path, false)
if err != nil {
return "", errors.Wrap(err, "resolving import paths")
Expand Down
19 changes: 11 additions & 8 deletions pkg/jsonnet/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import (
"path/filepath"
"testing"

"github.com/grafana/tanka/pkg/jsonnet/implementations/goimpl"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

var jsonnetImpl = &goimpl.JsonnetGoImplementation{}

const importTreeResult = `[
{
"breed": "apple",
Expand Down Expand Up @@ -51,13 +54,13 @@ const thisFileResult = `{
// To be consistent with the jsonnet executable,
// when evaluating a file, `std.thisFile` should point to the given path
func TestEvaluateFile(t *testing.T) {
result, err := EvaluateFile("testdata/thisFile/main.jsonnet", Opts{})
result, err := EvaluateFile(jsonnetImpl, "testdata/thisFile/main.jsonnet", Opts{})
assert.NoError(t, err)
assert.Equal(t, thisFileResult, result)
}

func TestEvaluateFileDoesntExist(t *testing.T) {
result, err := EvaluateFile("testdata/doesnt-exist/main.jsonnet", Opts{})
result, err := EvaluateFile(jsonnetImpl, "testdata/doesnt-exist/main.jsonnet", Opts{})
assert.EqualError(t, err, "open testdata/doesnt-exist/main.jsonnet: no such file or directory")
assert.Equal(t, "", result)
}
Expand All @@ -69,10 +72,10 @@ func TestEvaluateFileWithCaching(t *testing.T) {
cachePath := filepath.Join(tmp, "cache") // Should be created during caching

// Evaluate two files
result, err := EvaluateFile("testdata/thisFile/main.jsonnet", Opts{CachePath: cachePath})
result, err := EvaluateFile(jsonnetImpl, "testdata/thisFile/main.jsonnet", Opts{CachePath: cachePath})
assert.NoError(t, err)
assert.Equal(t, thisFileResult, result)
result, err = EvaluateFile("testdata/importTree/main.jsonnet", Opts{CachePath: cachePath})
result, err = EvaluateFile(jsonnetImpl, "testdata/importTree/main.jsonnet", Opts{CachePath: cachePath})
assert.NoError(t, err)
assert.Equal(t, importTreeResult, result)

Expand All @@ -82,10 +85,10 @@ func TestEvaluateFileWithCaching(t *testing.T) {
assert.Len(t, readCache, 2)

// Evaluate two files again, same result
result, err = EvaluateFile("testdata/thisFile/main.jsonnet", Opts{CachePath: cachePath})
result, err = EvaluateFile(jsonnetImpl, "testdata/thisFile/main.jsonnet", Opts{CachePath: cachePath})
assert.NoError(t, err)
assert.Equal(t, thisFileResult, result)
result, err = EvaluateFile("testdata/importTree/main.jsonnet", Opts{CachePath: cachePath})
result, err = EvaluateFile(jsonnetImpl, "testdata/importTree/main.jsonnet", Opts{CachePath: cachePath})
assert.NoError(t, err)
assert.Equal(t, importTreeResult, result)

Expand All @@ -95,10 +98,10 @@ func TestEvaluateFileWithCaching(t *testing.T) {
}

// Evaluate two files again, modified cache is returned instead of the actual result
result, err = EvaluateFile("testdata/thisFile/main.jsonnet", Opts{CachePath: cachePath})
result, err = EvaluateFile(jsonnetImpl, "testdata/thisFile/main.jsonnet", Opts{CachePath: cachePath})
assert.NoError(t, err)
assert.Equal(t, "BYfdlr1ZOVwiOfbd89JYTcK-eRQh05bi8ky3k1vVW5o=.json", result)
result, err = EvaluateFile("testdata/importTree/main.jsonnet", Opts{CachePath: cachePath})
result, err = EvaluateFile(jsonnetImpl, "testdata/importTree/main.jsonnet", Opts{CachePath: cachePath})
assert.NoError(t, err)
assert.Equal(t, "R_3hy-dRfOwXN-fezQ50ZF4dnrFcBcbQ9LztR_XWzJA=.json", result)
}
2 changes: 1 addition & 1 deletion pkg/jsonnet/find_importers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ func TestFindImportersForFiles(t *testing.T) {
if filepath.Base(file) != jpath.DefaultEntrypoint {
continue
}
_, err := EvaluateFile(file, Opts{})
_, err := EvaluateFile(jsonnetImpl, file, Opts{})
require.NoError(t, err, "failed to eval %s", file)
}

Expand Down
18 changes: 0 additions & 18 deletions pkg/jsonnet/implementation/implementation.go

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,31 @@ package goimpl

import (
"github.com/google/go-jsonnet"
"github.com/grafana/tanka/pkg/jsonnet/implementation/types"
"github.com/grafana/tanka/pkg/jsonnet/implementations/types"
)

type JsonnetGoVM struct {
vm *jsonnet.VM

path string
}

func (vm *JsonnetGoVM) EvaluateAnonymousSnippet(filename, snippet string) (string, error) {
return vm.vm.EvaluateAnonymousSnippet(filename, snippet)
func (vm *JsonnetGoVM) EvaluateAnonymousSnippet(snippet string) (string, error) {
return vm.vm.EvaluateAnonymousSnippet(vm.path, snippet)
}

func (vm *JsonnetGoVM) EvaluateFile(filename string) (string, error) {
return vm.vm.EvaluateFile(filename)
}

type JsonnetGoImplementation struct{}
type JsonnetGoImplementation struct {
Path string
}

func (i *JsonnetGoImplementation) MakeEvaluator(importPaths []string, extCode map[string]string, tlaCode map[string]string, maxStack int) types.JsonnetEvaluator {
return &JsonnetGoVM{
vm: MakeRawVM(importPaths, extCode, tlaCode, maxStack),

path: i.Path,
}
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package types
// JsonnetEvaluator represents a struct that can evaluate Jsonnet code
// It is configured with import paths, external code and top-level arguments
type JsonnetEvaluator interface {
EvaluateAnonymousSnippet(filename, snippet string) (string, error)
EvaluateAnonymousSnippet(snippet string) (string, error)
EvaluateFile(filename string) (string, error)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/jsonnet/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/google/go-jsonnet/toolutils"
"github.com/pkg/errors"

"github.com/grafana/tanka/pkg/jsonnet/implementation/goimpl"
"github.com/grafana/tanka/pkg/jsonnet/implementations/goimpl"
"github.com/grafana/tanka/pkg/jsonnet/jpath"
)

Expand Down
2 changes: 1 addition & 1 deletion pkg/jsonnet/imports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"sync"
"testing"

"github.com/grafana/tanka/pkg/jsonnet/implementation/goimpl"
"github.com/grafana/tanka/pkg/jsonnet/implementations/goimpl"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down
5 changes: 4 additions & 1 deletion pkg/jsonnet/jpath/jpath_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ import (
"github.com/stretchr/testify/require"

"github.com/grafana/tanka/pkg/jsonnet"
"github.com/grafana/tanka/pkg/jsonnet/implementations/goimpl"
)

var jsonnetImpl = &goimpl.JsonnetGoImplementation{}

func TestResolvePrecedence(t *testing.T) {
s, err := jsonnet.EvaluateFile("./testdata/precedence/environments/default/main.jsonnet", jsonnet.Opts{})
s, err := jsonnet.EvaluateFile(jsonnetImpl, "./testdata/precedence/environments/default/main.jsonnet", jsonnet.Opts{})
require.NoError(t, err)

want := map[string]string{
Expand Down
2 changes: 1 addition & 1 deletion pkg/jsonnet/lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

"github.com/gobwas/glob"
"github.com/google/go-jsonnet/linter"
"github.com/grafana/tanka/pkg/jsonnet/implementation/goimpl"
"github.com/grafana/tanka/pkg/jsonnet/implementations/goimpl"
"github.com/grafana/tanka/pkg/jsonnet/jpath"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
Expand Down
2 changes: 1 addition & 1 deletion pkg/process/data_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"fmt"
"path/filepath"

"github.com/grafana/tanka/pkg/jsonnet/implementation/goimpl"
"github.com/grafana/tanka/pkg/jsonnet/implementations/goimpl"
"github.com/grafana/tanka/pkg/kubernetes/manifest"
)

Expand Down
9 changes: 5 additions & 4 deletions pkg/tanka/evaluators.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import (
"github.com/pkg/errors"

"github.com/grafana/tanka/pkg/jsonnet"
"github.com/grafana/tanka/pkg/jsonnet/implementations/types"
"github.com/grafana/tanka/pkg/jsonnet/jpath"
)

// EvalJsonnet evaluates the jsonnet environment at the given file system path
func evalJsonnet(path string, opts jsonnet.Opts) (raw string, err error) {
func evalJsonnet(path string, impl types.JsonnetImplementation, opts jsonnet.Opts) (raw string, err error) {
entrypoint, err := jpath.Entrypoint(path)
if err != nil {
return "", err
Expand All @@ -37,14 +38,14 @@ function(%s)
`, tlaJoin, entrypoint, tlaJoin, opts.EvalScript)
}

raw, err = jsonnet.Evaluate(path, evalScript, opts)
raw, err = jsonnet.Evaluate(path, impl, evalScript, opts)
if err != nil {
return "", errors.Wrap(err, "evaluating jsonnet")
return "", fmt.Errorf("evaluating jsonnet in path '%s': %w", path, err)
}
return raw, nil
}

raw, err = jsonnet.EvaluateFile(entrypoint, opts)
raw, err = jsonnet.EvaluateFile(impl, entrypoint, opts)
if err != nil {
return "", errors.Wrap(err, "evaluating jsonnet")
}
Expand Down
7 changes: 5 additions & 2 deletions pkg/tanka/evaluators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ import (
"testing"

"github.com/grafana/tanka/pkg/jsonnet"
"github.com/grafana/tanka/pkg/jsonnet/implementations/goimpl"
"github.com/stretchr/testify/assert"
)

var jsonnetImpl = &goimpl.JsonnetGoImplementation{}

func TestEvalJsonnet(t *testing.T) {
var tlaCode jsonnet.InjectedCode
// Pass in the mandatory parameters as TLA codes, but note that only `foo`
Expand All @@ -27,7 +30,7 @@ func TestEvalJsonnet(t *testing.T) {

// This will fail intermittently if TLAs are passed as positional
// parameters.
json, err := evalJsonnet("testdata/cases/withtlas", opts)
json, err := evalJsonnet("testdata/cases/withtlas", jsonnetImpl, opts)
assert.NoError(t, err)
assert.Equal(t, `"foovalue"`, strings.TrimSpace(json))
}
Expand All @@ -43,7 +46,7 @@ func TestEvalJsonnetWithExpression(t *testing.T) {

// This will fail intermittently if TLAs are passed as positional
// parameters.
json, err := evalJsonnet("testdata/cases/object", opts)
json, err := evalJsonnet("testdata/cases/object", jsonnetImpl, opts)
assert.NoError(t, err)
assert.Equal(t, `"object"`, strings.TrimSpace(json))
})
Expand Down
7 changes: 5 additions & 2 deletions pkg/tanka/inline.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"path/filepath"
"sort"

"github.com/grafana/tanka/pkg/jsonnet/implementations/types"
"github.com/grafana/tanka/pkg/jsonnet/jpath"
"github.com/grafana/tanka/pkg/kubernetes/manifest"
"github.com/grafana/tanka/pkg/process"
Expand All @@ -16,7 +17,9 @@ import (
// InlineLoader loads an environment that is specified inline from within
// Jsonnet. The Jsonnet output is expected to hold a tanka.dev/Environment type,
// Kubernetes resources are expected at the `data` key of this very type
type InlineLoader struct{}
type InlineLoader struct {
jsonnetImpl types.JsonnetImplementation
}

func (i *InlineLoader) Load(path string, opts LoaderOpts) (*v1alpha1.Environment, error) {
if opts.Name != "" {
Expand Down Expand Up @@ -110,7 +113,7 @@ func (i *InlineLoader) Eval(path string, opts LoaderOpts) (interface{}, error) {
// Can't provide env as extVar, as we need to evaluate Jsonnet first to know it
opts.ExtCode.Set(environmentExtCode, `error "Using tk.env and std.extVar('tanka.dev/environment') is only supported for static environments. Directly access this data using standard Jsonnet instead."`)

raw, err := evalJsonnet(path, opts.JsonnetOpts)
raw, err := evalJsonnet(path, i.jsonnetImpl, opts.JsonnetOpts)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 82ae5ae

Please sign in to comment.