diff options
| author | Dave Henderson <dhenderson@gmail.com> | 2022-05-28 19:24:48 -0400 |
|---|---|---|
| committer | Dave Henderson <dhenderson@gmail.com> | 2022-05-28 19:49:42 -0400 |
| commit | cec23e66f9bd5022845162ae4dd3f2633b5236fa (patch) | |
| tree | f5caf83d0c92ce80942b2e7ed5e184ffb69e3c2d | |
| parent | e00015a86393e947757dea88cb82b328b35ad8b4 (diff) | |
General refactoring & cleanup
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
| -rw-r--r-- | context.go | 6 | ||||
| -rw-r--r-- | context_test.go | 5 | ||||
| -rw-r--r-- | data/datasource.go | 29 | ||||
| -rw-r--r-- | data/datasource_http.go | 2 | ||||
| -rw-r--r-- | data/datasource_http_test.go | 10 | ||||
| -rw-r--r-- | data/datasource_stdin.go | 20 | ||||
| -rw-r--r-- | data/datasource_stdin_test.go | 7 | ||||
| -rw-r--r-- | data/datasource_test.go | 26 | ||||
| -rw-r--r-- | gomplate.go | 17 | ||||
| -rw-r--r-- | internal/cmd/config.go | 7 | ||||
| -rw-r--r-- | internal/cmd/config_test.go | 29 | ||||
| -rw-r--r-- | template.go | 33 |
12 files changed, 91 insertions, 100 deletions
@@ -6,7 +6,6 @@ import ( "strings" "github.com/hairyhenderson/gomplate/v3/data" - "github.com/hairyhenderson/gomplate/v3/internal/config" ) // context for templates @@ -22,10 +21,11 @@ func (c *tmplctx) Env() map[string]string { return env } -func createTmplContext(ctx context.Context, contexts map[string]config.DataSource, d *data.Data) (interface{}, error) { +// createTmplContext reads the datasources for the given aliases +func createTmplContext(ctx context.Context, aliases []string, d *data.Data) (interface{}, error) { var err error tctx := &tmplctx{} - for a := range contexts { + for _, a := range aliases { if a == "." { return d.Datasource(a) } diff --git a/context_test.go b/context_test.go index 27cf7d94..2b95ebb8 100644 --- a/context_test.go +++ b/context_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/hairyhenderson/gomplate/v3/data" - "github.com/hairyhenderson/gomplate/v3/internal/config" "github.com/stretchr/testify/assert" ) @@ -43,7 +42,7 @@ func TestCreateContext(t *testing.T) { } os.Setenv("foo", "foo: bar") defer os.Unsetenv("foo") - c, err = createTmplContext(ctx, map[string]config.DataSource{"foo": {URL: uf}}, d) + c, err = createTmplContext(ctx, []string{"foo"}, d) assert.NoError(t, err) assert.IsType(t, &tmplctx{}, c) tctx := c.(*tmplctx) @@ -52,7 +51,7 @@ func TestCreateContext(t *testing.T) { os.Setenv("bar", "bar: baz") defer os.Unsetenv("bar") - c, err = createTmplContext(ctx, map[string]config.DataSource{".": {URL: ub}}, d) + c, err = createTmplContext(ctx, []string{"."}, d) assert.NoError(t, err) assert.IsType(t, map[string]interface{}{}, c) ds = c.(map[string]interface{}) diff --git a/data/datasource.go b/data/datasource.go index 539ba122..c010f89d 100644 --- a/data/datasource.go +++ b/data/datasource.go @@ -78,8 +78,9 @@ func (d *Data) lookupReader(scheme string) (func(context.Context, *Source, ...st } // Data - +// Deprecated: will be replaced in future type Data struct { - ctx context.Context + Ctx context.Context Sources map[string]*Source @@ -87,7 +88,7 @@ type Data struct { cache map[string][]byte // headers from the --datasource-header/-H option that don't reference datasources from the commandline - extraHeaders map[string]http.Header + ExtraHeaders map[string]http.Header } // Cleanup - clean up datasources before shutting the process down - things @@ -114,41 +115,41 @@ func NewData(datasourceArgs, headerArgs []string) (*Data, error) { func FromConfig(ctx context.Context, cfg *config.Config) *Data { // XXX: This is temporary, and will be replaced with something a bit cleaner // when datasources are refactored - stdin = cfg.Stdin + ctx = ContextWithStdin(ctx, cfg.Stdin) sources := map[string]*Source{} for alias, d := range cfg.DataSources { sources[alias] = &Source{ Alias: alias, URL: d.URL, - header: d.Header, + Header: d.Header, } } for alias, d := range cfg.Context { sources[alias] = &Source{ Alias: alias, URL: d.URL, - header: d.Header, + Header: d.Header, } } return &Data{ - ctx: ctx, + Ctx: ctx, Sources: sources, - extraHeaders: cfg.ExtraHeaders, + ExtraHeaders: cfg.ExtraHeaders, } } // Source - a data source type Source struct { + Alias string URL *url.URL + Header http.Header // used for http[s]: URLs, nil otherwise fs afero.Fs // used for file: URLs, nil otherwise hc *http.Client // used for http[s]: URLs, nil otherwise vc *vault.Vault // used for vault: URLs, nil otherwise kv *libkv.LibKV // used for consul:, etcd:, zookeeper: & boltdb: URLs, nil otherwise asmpg awssmpGetter // used for aws+smp:, nil otherwise awsSecretsManager awsSecretsManagerGetter // used for aws+sm, nil otherwise - header http.Header // used for http[s]: URLs, nil otherwise - Alias string mediaType string } @@ -246,7 +247,7 @@ func (d *Data) DefineDatasource(alias, value string) (string, error) { s := &Source{ Alias: alias, URL: srcURL, - header: d.extraHeaders[alias], + Header: d.ExtraHeaders[alias], } if d.Sources == nil { d.Sources = make(map[string]*Source) @@ -271,7 +272,7 @@ func (d *Data) lookupSource(alias string) (*Source, error) { source = &Source{ Alias: alias, URL: srcURL, - header: d.extraHeaders[alias], + Header: d.ExtraHeaders[alias], } d.Sources[alias] = source } @@ -304,13 +305,13 @@ func (d *Data) readDataSource(ctx context.Context, alias string, args ...string) // Include - func (d *Data) Include(alias string, args ...string) (string, error) { - data, _, err := d.readDataSource(d.ctx, alias, args...) + data, _, err := d.readDataSource(d.Ctx, alias, args...) return data, err } // Datasource - func (d *Data) Datasource(alias string, args ...string) (interface{}, error) { - data, mimeType, err := d.readDataSource(d.ctx, alias, args...) + data, mimeType, err := d.readDataSource(d.Ctx, alias, args...) if err != nil { return nil, err } @@ -355,7 +356,7 @@ func (d *Data) DatasourceReachable(alias string, args ...string) bool { if !ok { return false } - _, err := d.readSource(d.ctx, source, args...) + _, err := d.readSource(d.Ctx, source, args...) return err == nil } diff --git a/data/datasource_http.go b/data/datasource_http.go index ed1c97b7..03e1ac4c 100644 --- a/data/datasource_http.go +++ b/data/datasource_http.go @@ -34,7 +34,7 @@ func readHTTP(ctx context.Context, source *Source, args ...string) ([]byte, erro if err != nil { return nil, err } - req.Header = source.header + req.Header = source.Header res, err := source.hc.Do(req) if err != nil { return nil, err diff --git a/data/datasource_http_test.go b/data/datasource_http_test.go index e2c13a8f..5d279712 100644 --- a/data/datasource_http_test.go +++ b/data/datasource_http_test.go @@ -58,7 +58,7 @@ func TestHTTPFile(t *testing.T) { hc: client, } data := &Data{ - ctx: context.Background(), + Ctx: context.Background(), Sources: sources, } @@ -88,7 +88,7 @@ func TestHTTPFileWithHeaders(t *testing.T) { Path: "/foo", }, hc: client, - header: http.Header{ + Header: http.Header{ "Foo": {"bar"}, "foo": {"baz"}, "User-Agent": {}, @@ -96,7 +96,7 @@ func TestHTTPFileWithHeaders(t *testing.T) { }, } data := &Data{ - ctx: context.Background(), + Ctx: context.Background(), Sources: sources, } expected := http.Header{ @@ -113,9 +113,9 @@ func TestHTTPFileWithHeaders(t *testing.T) { "User-Agent": {"Go-http-client/1.1"}, } data = &Data{ - ctx: context.Background(), + Ctx: context.Background(), Sources: sources, - extraHeaders: map[string]http.Header{server.URL: expected}, + ExtraHeaders: map[string]http.Header{server.URL: expected}, } actual, err = data.Datasource(server.URL) assert.NoError(t, err) diff --git a/data/datasource_stdin.go b/data/datasource_stdin.go index 007d935b..b8bd0eff 100644 --- a/data/datasource_stdin.go +++ b/data/datasource_stdin.go @@ -4,17 +4,31 @@ import ( "context" "io" "io/ioutil" + "os" "github.com/pkg/errors" ) -// stdin - for overriding in tests -var stdin io.Reader - func readStdin(ctx context.Context, source *Source, args ...string) ([]byte, error) { + stdin := stdinFromContext(ctx) + b, err := ioutil.ReadAll(stdin) if err != nil { return nil, errors.Wrapf(err, "Can't read %s", stdin) } return b, nil } + +type stdinCtxKey struct{} + +func ContextWithStdin(ctx context.Context, r io.Reader) context.Context { + return context.WithValue(ctx, stdinCtxKey{}, r) +} + +func stdinFromContext(ctx context.Context) io.Reader { + if r, ok := ctx.Value(stdinCtxKey{}).(io.Reader); ok { + return r + } + + return os.Stdin +} diff --git a/data/datasource_stdin_test.go b/data/datasource_stdin_test.go index 1b92914e..6cd34133 100644 --- a/data/datasource_stdin_test.go +++ b/data/datasource_stdin_test.go @@ -11,15 +11,12 @@ import ( func TestReadStdin(t *testing.T) { ctx := context.Background() - defer func() { - stdin = nil - }() - stdin = strings.NewReader("foo") + ctx = ContextWithStdin(ctx, strings.NewReader("foo")) out, err := readStdin(ctx, nil) assert.NoError(t, err) assert.Equal(t, []byte("foo"), out) - stdin = errorReader{} + ctx = ContextWithStdin(ctx, errorReader{}) _, err = readStdin(ctx, nil) assert.Error(t, err) } diff --git a/data/datasource_test.go b/data/datasource_test.go index aadcef0e..5badec53 100644 --- a/data/datasource_test.go +++ b/data/datasource_test.go @@ -28,17 +28,17 @@ func TestNewData(t *testing.T) { d, err = NewData([]string{"foo=http:///foo.json"}, []string{}) assert.NoError(t, err) assert.Equal(t, "/foo.json", d.Sources["foo"].URL.Path) - assert.Empty(t, d.Sources["foo"].header) + assert.Empty(t, d.Sources["foo"].Header) d, err = NewData([]string{"foo=http:///foo.json"}, []string{"bar=Accept: blah"}) assert.NoError(t, err) assert.Equal(t, "/foo.json", d.Sources["foo"].URL.Path) - assert.Empty(t, d.Sources["foo"].header) + assert.Empty(t, d.Sources["foo"].Header) d, err = NewData([]string{"foo=http:///foo.json"}, []string{"foo=Accept: blah"}) assert.NoError(t, err) assert.Equal(t, "/foo.json", d.Sources["foo"].URL.Path) - assert.Equal(t, "blah", d.Sources["foo"].header["Accept"][0]) + assert.Equal(t, "blah", d.Sources["foo"].Header["Accept"][0]) } func TestDatasource(t *testing.T) { @@ -344,12 +344,14 @@ func TestMimeTypeWithArg(t *testing.T) { func TestFromConfig(t *testing.T) { ctx := context.Background() + cfg := &config.Config{} + actual := FromConfig(ctx, cfg) expected := &Data{ - ctx: ctx, + Ctx: actual.Ctx, Sources: map[string]*Source{}, } - assert.EqualValues(t, expected, FromConfig(ctx, cfg)) + assert.EqualValues(t, expected, actual) cfg = &config.Config{ DataSources: map[string]config.DataSource{ @@ -358,8 +360,9 @@ func TestFromConfig(t *testing.T) { }, }, } + actual = FromConfig(ctx, cfg) expected = &Data{ - ctx: ctx, + Ctx: actual.Ctx, Sources: map[string]*Source{ "foo": { Alias: "foo", @@ -367,7 +370,7 @@ func TestFromConfig(t *testing.T) { }, }, } - assert.EqualValues(t, expected, FromConfig(ctx, cfg)) + assert.EqualValues(t, expected, actual) cfg = &config.Config{ DataSources: map[string]config.DataSource{ @@ -389,8 +392,9 @@ func TestFromConfig(t *testing.T) { }, }, } + actual = FromConfig(ctx, cfg) expected = &Data{ - ctx: ctx, + Ctx: actual.Ctx, Sources: map[string]*Source{ "foo": { Alias: "foo", @@ -399,18 +403,18 @@ func TestFromConfig(t *testing.T) { "bar": { Alias: "bar", URL: mustParseURL("http://bar.com"), - header: http.Header{ + Header: http.Header{ "Foo": []string{"bar"}, }, }, }, - extraHeaders: map[string]http.Header{ + ExtraHeaders: map[string]http.Header{ "baz": { "Foo": []string{"bar"}, }, }, } - assert.EqualValues(t, expected, FromConfig(ctx, cfg)) + assert.EqualValues(t, expected, actual) } func TestListDatasources(t *testing.T) { diff --git a/gomplate.go b/gomplate.go index a036b392..91d1e026 100644 --- a/gomplate.go +++ b/gomplate.go @@ -26,7 +26,6 @@ type gomplate struct { tmplctx interface{} funcMap template.FuncMap nestedTemplates templateAliases - rootTemplate *template.Template leftDelim, rightDelim string } @@ -128,6 +127,14 @@ func Run(ctx context.Context, cfg *config.Config) error { Metrics = newMetrics() defer runCleanupHooks() + // reset defaults before validation + cfg.ApplyDefaults() + + err := cfg.Validate() + if err != nil { + return fmt.Errorf("failed to validate config: %w\n%+v", err, cfg) + } + d := data.FromConfig(ctx, cfg) log.Debug().Str("data", fmt.Sprintf("%+v", d)).Msg("created data from config") @@ -136,10 +143,16 @@ func Run(ctx context.Context, cfg *config.Config) error { if err != nil { return err } - c, err := createTmplContext(ctx, cfg.Context, d) + + aliases := []string{} + for k := range cfg.Context { + aliases = append(aliases, k) + } + c, err := createTmplContext(ctx, aliases, d) if err != nil { return err } + funcMap := CreateFuncs(ctx, d) err = bindPlugins(ctx, cfg, funcMap) if err != nil { diff --git a/internal/cmd/config.go b/internal/cmd/config.go index 201b867a..6f0c3673 100644 --- a/internal/cmd/config.go +++ b/internal/cmd/config.go @@ -52,13 +52,6 @@ func loadConfig(cmd *cobra.Command, args []string) (*config.Config, error) { cfg.Stdout = cmd.OutOrStdout() cfg.Stderr = cmd.ErrOrStderr() - // reset defaults before validation - cfg.ApplyDefaults() - - err = cfg.Validate() - if err != nil { - return nil, fmt.Errorf("failed to validate merged config: %w\n%+v", err, cfg) - } return cfg, nil } diff --git a/internal/cmd/config_test.go b/internal/cmd/config_test.go index aa7ff753..0a5b38f6 100644 --- a/internal/cmd/config_test.go +++ b/internal/cmd/config_test.go @@ -82,15 +82,9 @@ func TestLoadConfig(t *testing.T) { out, err := loadConfig(cmd, cmd.Flags().Args()) expected := &config.Config{ - InputFiles: []string{"-"}, - OutputFiles: []string{"-"}, - LDelim: "{{", - RDelim: "}}", - PostExecInput: stdin, - PluginTimeout: 5 * time.Second, - Stdin: stdin, - Stdout: stdout, - Stderr: stderr, + Stdin: stdin, + Stdout: stdout, + Stderr: stderr, } assert.NoError(t, err) assert.EqualValues(t, expected, out) @@ -98,15 +92,10 @@ func TestLoadConfig(t *testing.T) { cmd.ParseFlags([]string{"--in", "foo"}) out, err = loadConfig(cmd, cmd.Flags().Args()) expected = &config.Config{ - Input: "foo", - OutputFiles: []string{"-"}, - LDelim: "{{", - RDelim: "}}", - PostExecInput: stdin, - PluginTimeout: 5 * time.Second, - Stdin: stdin, - Stdout: out.Stdout, - Stderr: stderr, + Input: "foo", + Stdin: stdin, + Stdout: out.Stdout, + Stderr: stderr, } assert.NoError(t, err) assert.EqualValues(t, expected, out) @@ -115,13 +104,9 @@ func TestLoadConfig(t *testing.T) { out, err = loadConfig(cmd, cmd.Flags().Args()) expected = &config.Config{ Input: "foo", - LDelim: "{{", - RDelim: "}}", ExecPipe: true, PostExec: []string{"tr", "[a-z]", "[A-Z]"}, PostExecInput: out.PostExecInput, - OutputFiles: []string{"-"}, - PluginTimeout: 5 * time.Second, Stdin: stdin, Stdout: out.Stdout, Stderr: stderr, diff --git a/template.go b/template.go index 4f4d6d36..4a357052 100644 --- a/template.go +++ b/template.go @@ -54,18 +54,13 @@ func copyFuncMap(funcMap template.FuncMap) template.FuncMap { } func (t *tplate) toGoTemplate(g *gomplate) (tmpl *template.Template, err error) { - if g.rootTemplate != nil { - tmpl = g.rootTemplate.New(t.name) - } else { - tmpl = template.New(t.name) - g.rootTemplate = tmpl - } + tmpl = template.New(t.name) tmpl.Option("missingkey=error") funcMap := copyFuncMap(g.funcMap) // the "tmpl" funcs get added here because they need access to the root template and context - addTmplFuncs(funcMap, g.rootTemplate, g.tmplctx, t.name) + addTmplFuncs(funcMap, tmpl, g.tmplctx, t.name) tmpl.Funcs(funcMap) tmpl.Delims(g.leftDelim, g.rightDelim) _, err = tmpl.Parse(t.contents) @@ -206,33 +201,23 @@ func walkDir(dir string, outFileNamer func(string) (string, error), excludeGlob // Unmatched ignorefile rules's files files := matches.UnmatchedFiles for _, file := range files { - nextInPath := filepath.Join(dir, file) - nextOutPath, err := outFileNamer(file) + inFile := filepath.Join(dir, file) + outFile, err := outFileNamer(file) if err != nil { return nil, err } - fMode := mode - if mode == 0 { - stat, perr := fs.Stat(nextInPath) - if perr == nil { - fMode = stat.Mode() - } else { - fMode = dirMode - } + tpl, err := fileToTemplates(inFile, outFile, mode, modeOverride) + if err != nil { + return nil, err } // Ensure file parent dirs - if err = fs.MkdirAll(filepath.Dir(nextOutPath), dirMode); err != nil { + if err = fs.MkdirAll(filepath.Dir(outFile), dirMode); err != nil { return nil, err } - templates = append(templates, &tplate{ - name: nextInPath, - targetPath: nextOutPath, - mode: fMode, - modeOverride: modeOverride, - }) + templates = append(templates, tpl) } return templates, nil |
