github.com/grafana/tanka@v0.26.1-0.20240506093700-c22cfc35c21a/pkg/jsonnet/implementations/goimpl/importer.go (about)

     1  package goimpl
     2  
     3  import (
     4  	"path/filepath"
     5  
     6  	jsonnet "github.com/google/go-jsonnet"
     7  )
     8  
     9  const locationInternal = "<internal>"
    10  
    11  // extendedImporter wraps jsonnet.FileImporter to add additional functionality:
    12  // - `import "file.yaml"`
    13  // - `import "tk"`
    14  type extendedImporter struct {
    15  	loaders    []importLoader    // for loading jsonnet from somewhere. First one that returns non-nil is used
    16  	processors []importProcessor // for post-processing (e.g. yaml -> json)
    17  }
    18  
    19  // importLoader are executed before the actual importing. If they return
    20  // something, this value is used.
    21  type importLoader func(importedFrom, importedPath string) (c *jsonnet.Contents, foundAt string, err error)
    22  
    23  // importProcessor are executed after the file import and may modify the result
    24  // further
    25  type importProcessor func(contents, foundAt string) (c *jsonnet.Contents, err error)
    26  
    27  // newExtendedImporter returns a new instance of ExtendedImporter with the
    28  // correct jpaths set up
    29  func newExtendedImporter(jpath []string) *extendedImporter {
    30  	return &extendedImporter{
    31  		loaders: []importLoader{
    32  			tkLoader,
    33  			newFileLoader(&jsonnet.FileImporter{
    34  				JPaths: jpath,
    35  			})},
    36  		processors: []importProcessor{},
    37  	}
    38  }
    39  
    40  // Import implements the functionality offered by the ExtendedImporter
    41  func (i *extendedImporter) Import(importedFrom, importedPath string) (contents jsonnet.Contents, foundAt string, err error) {
    42  	// load using loader
    43  	for _, loader := range i.loaders {
    44  		c, f, err := loader(importedFrom, importedPath)
    45  		if err != nil {
    46  			return jsonnet.Contents{}, "", err
    47  		}
    48  		if c != nil {
    49  			contents = *c
    50  			foundAt = f
    51  			break
    52  		}
    53  	}
    54  
    55  	// check if needs postprocessing
    56  	for _, processor := range i.processors {
    57  		c, err := processor(contents.String(), foundAt)
    58  		if err != nil {
    59  			return jsonnet.Contents{}, "", err
    60  		}
    61  		if c != nil {
    62  			contents = *c
    63  			break
    64  		}
    65  	}
    66  
    67  	return contents, foundAt, nil
    68  }
    69  
    70  // tkLoader provides `tk.libsonnet` from memory (builtin)
    71  func tkLoader(_, importedPath string) (contents *jsonnet.Contents, foundAt string, err error) {
    72  	if importedPath != "tk" {
    73  		return nil, "", nil
    74  	}
    75  
    76  	return &tkLibsonnet, filepath.Join(locationInternal, "tk.libsonnet"), nil
    77  }
    78  
    79  // newFileLoader returns an importLoader that uses jsonnet.FileImporter to source
    80  // files from the local filesystem
    81  func newFileLoader(fi *jsonnet.FileImporter) importLoader {
    82  	return func(importedFrom, importedPath string) (contents *jsonnet.Contents, foundAt string, err error) {
    83  		var c jsonnet.Contents
    84  		c, foundAt, err = fi.Import(importedFrom, importedPath)
    85  		return &c, foundAt, err
    86  	}
    87  }