Skip to content

Commit

Permalink
fix(cli/jsonnet): do static import analysis on environment level
Browse files Browse the repository at this point in the history
All of our current commands take environments, only the import analysis works on
plain files ... this has no benefit, it actually makes the implementation
harder, as we cannot use stable paths there.

Switches to environments as the target.
  • Loading branch information
sh0rez committed Jan 6, 2020
1 parent f8c7660 commit 8012c65
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 28 deletions.
27 changes: 18 additions & 9 deletions cmd/tk/tool.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,12 @@ func jpathCmd() *cobra.Command {

func importsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "imports <file>",
Short: "list all transitive imports of a file",
Use: "imports <directory>",
Short: "list all transitive imports of an environment",
Args: cobra.ExactArgs(1),
Annotations: map[string]string{
"args": "baseDir",
},
Run: func(cmd *cobra.Command, args []string) {
var modFiles []string
if cmd.Flag("check").Changed {
Expand All @@ -64,22 +67,28 @@ func importsCmd() *cobra.Command {
}
}

f, err := filepath.Abs(args[0])
dir, err := filepath.Abs(args[0])
if err != nil {
log.Fatalln("Opening file:", err)
log.Fatalln("Loading environment:", err)
}

deps, err := jsonnet.TransitiveImports(f)
fi, err := os.Stat(dir)
if err != nil {
log.Fatalln("resolving imports:", err)
log.Fatalln("Loading environment:", err)
}

if !fi.IsDir() {
log.Fatalln("The argument must be an environment's directory, but this does not seem to be the case.")
}

// include main.jsonnet as well
deps = append(deps, f)
deps, err := jsonnet.TransitiveImports(dir)
if err != nil {
log.Fatalln("Resolving imports:", err)
}

root, err := gitRoot()
if err != nil {
log.Fatalln("invoking git:", err)
log.Fatalln("Invoking git:", err)
}
if modFiles != nil {
for _, m := range modFiles {
Expand Down
34 changes: 26 additions & 8 deletions pkg/jsonnet/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package jsonnet
import (
"io/ioutil"
"path/filepath"
"sort"

jsonnet "github.com/google/go-jsonnet"
"github.com/google/go-jsonnet/ast"
Expand All @@ -13,14 +14,21 @@ import (
"github.com/grafana/tanka/pkg/jsonnet/native"
)

// TransitiveImports returns all recursive imports of a file
func TransitiveImports(filename string) ([]string, error) {
sonnet, err := ioutil.ReadFile(filename)
// TransitiveImports returns all recursive imports of an environment
func TransitiveImports(dir string) ([]string, error) {
dir, err := filepath.Abs(dir)
if err != nil {
return nil, err
}

mainFile := filepath.Join(dir, "main.jsonnet")

sonnet, err := ioutil.ReadFile(mainFile)
if err != nil {
return nil, errors.Wrap(err, "opening file")
}

jpath, _, _, err := jpath.Resolve(filepath.Dir(filename))
jpath, _, rootDir, err := jpath.Resolve(dir)
if err != nil {
return nil, errors.Wrap(err, "resolving JPATH")
}
Expand All @@ -37,9 +45,17 @@ func TransitiveImports(filename string) ([]string, error) {
}

imports := make([]string, 0)
err = importRecursive(&imports, vm, node, "main.jsonnet")
if err = importRecursive(&imports, vm, node, "main.jsonnet"); err != nil {
return nil, err
}

uniq := append(uniqueStringSlice(imports), mainFile)
for i := range uniq {
uniq[i], _ = filepath.Rel(rootDir, uniq[i])
}
sort.Strings(uniq)

return uniqueStringSlice(imports), err
return uniq, nil
}

// importRecursive takes a Jsonnet VM and recursively imports the AST. Every
Expand All @@ -56,7 +72,8 @@ func importRecursive(list *[]string, vm *jsonnet.VM, node ast.Node, currentPath
return errors.Wrap(err, "importing jsonnet")
}

*list = append(*list, foundAt)
abs, _ := filepath.Abs(foundAt)
*list = append(*list, abs)

if err := importRecursive(list, vm, contents, foundAt); err != nil {
return err
Expand All @@ -71,7 +88,8 @@ func importRecursive(list *[]string, vm *jsonnet.VM, node ast.Node, currentPath
return errors.Wrap(err, "importing string")
}

*list = append(*list, foundAt)
abs, _ := filepath.Abs(foundAt)
*list = append(*list, abs)

// neither `import` nor `importstr`, probably object or similar: try children
default:
Expand Down
19 changes: 10 additions & 9 deletions pkg/jsonnet/imports_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package jsonnet

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -10,15 +11,15 @@ import (
// TestTransitiveImports checks that TransitiveImports is able to report all
// recursive imports of a file
func TestTransitiveImports(t *testing.T) {
imports, err := TransitiveImports("testdata/main.jsonnet")
imports, err := TransitiveImports("testdata")
fmt.Println(imports)
require.NoError(t, err)
assert.ElementsMatch(t, []string{
"testdata/trees.jsonnet",

"testdata/trees/apple.jsonnet",
"testdata/trees/cherry.jsonnet",
"testdata/trees/peach.jsonnet",

"testdata/trees/generic.libsonnet",
assert.Equal(t, []string{
"main.jsonnet",
"trees.jsonnet",
"trees/apple.jsonnet",
"trees/cherry.jsonnet",
"trees/generic.libsonnet",
"trees/peach.jsonnet",
}, imports)
}
6 changes: 4 additions & 2 deletions pkg/kubernetes/kubernetes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ func TestReconcile(t *testing.T) {

for _, c := range tests {
t.Run(c.name, func(t *testing.T) {
got, err := Reconcile(c.deep.(map[string]interface{}), c.spec, c.targets)
config := v1alpha1.New()
config.Spec = c.spec
got, err := Reconcile(c.deep.(map[string]interface{}), *config, c.targets)

require.Equal(t, c.err, err)
assert.ElementsMatch(t, c.flat, got)
Expand All @@ -99,7 +101,7 @@ func TestReconcile(t *testing.T) {
func TestReconcileOrder(t *testing.T) {
got := make([]manifest.List, 10)
for i := 0; i < 10; i++ {
r, err := Reconcile(testDataDeep().deep.(map[string]interface{}), v1alpha1.Spec{}, nil)
r, err := Reconcile(testDataDeep().deep.(map[string]interface{}), *v1alpha1.New(), nil)
require.NoError(t, err)
got[i] = r
}
Expand Down

0 comments on commit 8012c65

Please sign in to comment.