Skip to content
This repository has been archived by the owner on Nov 17, 2021. It is now read-only.

Commit

Permalink
Detect imported extvars and TLAs via sentinel path
Browse files Browse the repository at this point in the history
When a Jsonnet consults an Importer for a path nominated by an
external variable or top-level argument file-based command-line flag,
the "importedFrom" parameter passed to the Importer.Import method is
not a valid URL, but is instead a sentinel placeholder value (namely,
an empty string). Detect these sentinel values and use the current
working directory as the base URL instead when resolving relative
import paths.
  • Loading branch information
Steve Harris committed Oct 6, 2019
1 parent 16949d6 commit 59cec69
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 8 deletions.
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ func JsonnetVM(cmd *cobra.Command) (*jsonnet.VM, error) {
return nil, fmt.Errorf("Unable to determine current working directory: %v", err)
}

vm.Importer(utils.MakeUniversalImporter(searchUrls))
vm.Importer(utils.MakeUniversalImporter(searchUrls, dirURL(cwd)))

for _, spec := range []struct {
flagName string
Expand Down
21 changes: 14 additions & 7 deletions utils/importer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"net/http"
"net/url"
"os"
"regexp"
"strings"
"time"

Expand All @@ -19,8 +18,6 @@ import (

var errNotFound = errors.New("Not found")

var extVarKindRE = regexp.MustCompile("^<(?:extvar|top-level-arg):.+>$")

//go:generate go-bindata -nometadata -ignore .*_test\.|~$DOLLAR -pkg $GOPACKAGE -o bindata.go -prefix ../ ../lib/...
func newInternalFS(prefix string) http.FileSystem {
// Asset/AssetDir returns `fmt.Errorf("Asset %s not found")`,
Expand Down Expand Up @@ -62,7 +59,7 @@ A real-world example:
will be resolved as https://raw.githubusercontent.com/ksonnet/ksonnet-lib/master/ksonnet.beta.2/k8s.libsonnet
and downloaded from that location.
*/
func MakeUniversalImporter(searchURLs []*url.URL) jsonnet.Importer {
func MakeUniversalImporter(searchURLs []*url.URL, extVarBaseURL *url.URL) jsonnet.Importer {
// Reconstructed copy of http.DefaultTransport (to avoid
// modifying the default)
t := &http.Transport{
Expand All @@ -83,13 +80,15 @@ func MakeUniversalImporter(searchURLs []*url.URL) jsonnet.Importer {

return &universalImporter{
BaseSearchURLs: searchURLs,
extVarBaseURL: extVarBaseURL,
HTTPClient: &http.Client{Transport: t},
cache: map[string]jsonnet.Contents{},
}
}

type universalImporter struct {
BaseSearchURLs []*url.URL
extVarBaseURL *url.URL
HTTPClient *http.Client
cache map[string]jsonnet.Contents
}
Expand Down Expand Up @@ -154,9 +153,17 @@ func (importer *universalImporter) expandImportToCandidateURLs(importedFrom, imp
return []*url.URL{importedPathURL}, nil
}

importDirURL, err := url.Parse(importedFrom)
if err != nil {
return nil, fmt.Errorf("Invalid import dir %q: %v", importedFrom, err)
var importDirURL *url.URL
// Is the import coming from a source nominated by the "--ext-code-file," "--ext-str-file,"
// "--tla-code-file," or "--tla-str-file flags"? If so, resolve relative import paths against
// the specially configured base directory.
if importedFrom == "" {
importDirURL = importer.extVarBaseURL
} else {
importDirURL, err = url.Parse(importedFrom)
if err != nil {
return nil, fmt.Errorf("Invalid import dir %q", importedFrom)
}
}

candidateURLs := make([]*url.URL, 1, len(importer.BaseSearchURLs)+1)
Expand Down
15 changes: 15 additions & 0 deletions utils/importer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ func TestExpandImportToCandidateURLs(t *testing.T) {
BaseSearchURLs: []*url.URL{
{Scheme: "file", Path: "/first/base/search/"},
},
extVarBaseURL: &url.URL{
Scheme: "file",
Path: "/current/working/dir/",
},
}

t.Run("Absolute URL in import statement yields a single candidate", func(t *testing.T) {
Expand All @@ -53,4 +57,15 @@ func TestExpandImportToCandidateURLs(t *testing.T) {
t.Errorf("Expected %v, got %v", expected, urls)
}
})

t.Run("Relative URL in import statement used as external variable or TLA yields candidate relative to base URL", func(t *testing.T) {
urls, _ := importer.expandImportToCandidateURLs("", "../sought.jsonnet")
expected := []*url.URL{
{Scheme: "file", Host: "", Path: "/current/working/sought.jsonnet"},
{Scheme: "file", Host: "", Path: "/first/base/sought.jsonnet"},
}
if !reflect.DeepEqual(urls, expected) {
t.Errorf("Expected %v, got %v", expected, urls)
}
})
}

0 comments on commit 59cec69

Please sign in to comment.