Skip to content

Commit

Permalink
fixup! fixup! Support a config file to use instead of commandline arg…
Browse files Browse the repository at this point in the history
…uments
  • Loading branch information
hairyhenderson committed Apr 10, 2020
1 parent 1df0a0b commit 97a2150
Show file tree
Hide file tree
Showing 16 changed files with 556 additions and 84 deletions.
24 changes: 24 additions & 0 deletions cmd/gomplate/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package main
import (
"context"
"fmt"
"time"

"github.com/hairyhenderson/gomplate/v3/conv"
"github.com/hairyhenderson/gomplate/v3/env"
"github.com/hairyhenderson/gomplate/v3/internal/config"

Expand All @@ -26,6 +28,7 @@ var fs = afero.NewOsFs()
// - validates the final config
// - converts the config to a *gomplate.Config for further use (TODO: eliminate this part)
func loadConfig(cmd *cobra.Command, args []string) (*config.Config, error) {
ctx := cmd.Context()
flagConfig, err := cobraConfig(cmd, args)
if err != nil {
return nil, err
Expand All @@ -41,6 +44,11 @@ func loadConfig(cmd *cobra.Command, args []string) (*config.Config, error) {
cfg = cfg.MergeFrom(flagConfig)
}

cfg, err = applyEnvVars(ctx, cfg)
if err != nil {
return nil, err
}

// reset defaults before validation
cfg.ApplyDefaults()

Expand Down Expand Up @@ -227,3 +235,19 @@ func processIncludes(includes, excludes []string) []string {
out = append(out, excludes...)
return out
}

func applyEnvVars(ctx context.Context, cfg *config.Config) (*config.Config, error) {
if to := env.Getenv("GOMPLATE_PLUGIN_TIMEOUT"); cfg.PluginTimeout == 0 && to != "" {
t, err := time.ParseDuration(to)
if err != nil {
return nil, fmt.Errorf("GOMPLATE_PLUGIN_TIMEOUT set to invalid value %q: %w", to, err)
}
cfg.PluginTimeout = t
}

if !cfg.SuppressEmpty && conv.ToBool(env.Getenv("GOMPLATE_SUPPRESS_EMPTY", "false")) {
cfg.SuppressEmpty = true
}

return cfg, nil
}
80 changes: 80 additions & 0 deletions cmd/gomplate/config_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package main

import (
"context"
"os"
"testing"
"time"

"github.com/hairyhenderson/gomplate/v3/internal/config"

Expand Down Expand Up @@ -79,6 +81,7 @@ func TestLoadConfig(t *testing.T) {
RDelim: "}}",
PostExecInput: os.Stdin,
OutWriter: os.Stdout,
PluginTimeout: 5 * time.Second,
}
assert.NoError(t, err)
assert.EqualValues(t, expected, out)
Expand All @@ -92,6 +95,7 @@ func TestLoadConfig(t *testing.T) {
RDelim: "}}",
PostExecInput: os.Stdin,
OutWriter: os.Stdout,
PluginTimeout: 5 * time.Second,
}
assert.NoError(t, err)
assert.EqualValues(t, expected, out)
Expand All @@ -106,6 +110,8 @@ func TestLoadConfig(t *testing.T) {
PostExec: []string{"tr", "[a-z]", "[A-Z]"},
PostExecInput: out.PostExecInput,
OutWriter: out.PostExecInput,
OutputFiles: []string{"-"},
PluginTimeout: 5 * time.Second,
}
assert.NoError(t, err)
assert.EqualValues(t, expected, out)
Expand Down Expand Up @@ -176,3 +182,77 @@ func TestPickConfigFile(t *testing.T) {
assert.True(t, req)
assert.Equal(t, "config.file", cf)
}

func TestApplyEnvVars_PluginTimeout(t *testing.T) {
os.Setenv("GOMPLATE_PLUGIN_TIMEOUT", "bogus")

ctx := context.TODO()
cfg := &config.Config{}
_, err := applyEnvVars(ctx, cfg)
assert.Error(t, err)

cfg = &config.Config{
PluginTimeout: 2 * time.Second,
}
expected := &config.Config{
PluginTimeout: 2 * time.Second,
}
actual, err := applyEnvVars(ctx, cfg)
assert.NoError(t, err)
assert.EqualValues(t, expected, actual)

os.Setenv("GOMPLATE_PLUGIN_TIMEOUT", "2s")
defer os.Unsetenv("GOMPLATE_PLUGIN_TIMEOUT")

cfg = &config.Config{}
actual, err = applyEnvVars(ctx, cfg)
assert.NoError(t, err)
assert.EqualValues(t, expected, actual)

cfg = &config.Config{
PluginTimeout: 100 * time.Millisecond,
}
expected = &config.Config{
PluginTimeout: 100 * time.Millisecond,
}
actual, err = applyEnvVars(ctx, cfg)
assert.NoError(t, err)
assert.EqualValues(t, expected, actual)

}

func TestApplyEnvVars_SuppressEmpty(t *testing.T) {
os.Setenv("GOMPLATE_SUPPRESS_EMPTY", "bogus")
defer os.Unsetenv("GOMPLATE_SUPPRESS_EMPTY")

ctx := context.TODO()
cfg := &config.Config{}
expected := &config.Config{
SuppressEmpty: false,
}
actual, err := applyEnvVars(ctx, cfg)
assert.NoError(t, err)
assert.EqualValues(t, expected, actual)

os.Setenv("GOMPLATE_SUPPRESS_EMPTY", "true")

cfg = &config.Config{}
expected = &config.Config{
SuppressEmpty: true,
}
actual, err = applyEnvVars(ctx, cfg)
assert.NoError(t, err)
assert.EqualValues(t, expected, actual)

os.Setenv("GOMPLATE_SUPPRESS_EMPTY", "false")

cfg = &config.Config{
SuppressEmpty: true,
}
expected = &config.Config{
SuppressEmpty: true,
}
actual, err = applyEnvVars(ctx, cfg)
assert.NoError(t, err)
assert.EqualValues(t, expected, actual)
}
20 changes: 18 additions & 2 deletions data/datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

"github.com/pkg/errors"

"github.com/hairyhenderson/gomplate/v3/internal/config"
"github.com/hairyhenderson/gomplate/v3/libkv"
"github.com/hairyhenderson/gomplate/v3/vault"
)
Expand Down Expand Up @@ -126,10 +127,25 @@ func NewData(datasourceArgs, headerArgs []string) (*Data, error) {
}

// FromConfig - internal use only!
func FromConfig(sources map[string]*Source, extraHeaders map[string]http.Header) *Data {
func FromConfig(cfg *config.Config) *Data {
sources := map[string]*Source{}
for alias, d := range cfg.DataSources {
sources[alias] = &Source{
Alias: alias,
URL: d.URL,
header: d.Header,
}
}
for alias, d := range cfg.Context {
sources[alias] = &Source{
Alias: alias,
URL: d.URL,
header: d.Header,
}
}
return &Data{
Sources: sources,
extraHeaders: extraHeaders,
extraHeaders: cfg.ExtraHeaders,
}
}

Expand Down
69 changes: 69 additions & 0 deletions data/datasource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package data

import (
"fmt"
"net/http"
"net/url"
"runtime"
"strings"
"testing"

"github.com/hairyhenderson/gomplate/v3/internal/config"
"github.com/spf13/afero"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -411,3 +413,70 @@ func TestQueryParse(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, expected, u)
}

func TestFromConfig(t *testing.T) {
cfg := &config.Config{}
expected := &Data{
Sources: map[string]*Source{},
}
assert.EqualValues(t, expected, FromConfig(cfg))

cfg = &config.Config{
DataSources: map[string]config.DSConfig{
"foo": {
URL: mustParseURL("http://example.com"),
},
},
}
expected = &Data{
Sources: map[string]*Source{
"foo": {
Alias: "foo",
URL: mustParseURL("http://example.com"),
},
},
}
assert.EqualValues(t, expected, FromConfig(cfg))

cfg = &config.Config{
DataSources: map[string]config.DSConfig{
"foo": {
URL: mustParseURL("http://foo.com"),
},
},
Context: map[string]config.DSConfig{
"bar": {
URL: mustParseURL("http://bar.com"),
Header: http.Header{
"Foo": []string{"bar"},
},
},
},
ExtraHeaders: map[string]http.Header{
"baz": {
"Foo": []string{"bar"},
},
},
}
expected = &Data{
Sources: map[string]*Source{
"foo": {
Alias: "foo",
URL: mustParseURL("http://foo.com"),
},
"bar": {
Alias: "bar",
URL: mustParseURL("http://bar.com"),
header: http.Header{
"Foo": []string{"bar"},
},
},
},
extraHeaders: map[string]http.Header{
"baz": {
"Foo": []string{"bar"},
},
},
}
assert.EqualValues(t, expected, FromConfig(cfg))
}
24 changes: 24 additions & 0 deletions docs/content/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,20 @@ plugins:
lolcat: /home/hairyhenderson/go/bin/lolcat
```

## `pluginTimeout`

See [`--plugin`](../usage/#--plugin).

Sets the timeout for running plugins. By default, plugins will time out after 5
seconds. This value can be set to override this default. The value must be
a valid [duration](../functions/time/#time-parseduration) such as `10s` or `3m`.

```yaml
plugins:
figlet: /usr/local/bin/figlet
pluginTimeout: 500ms
```

## `postExec`

See [post-template command execution](../usage/#post-template-command-execution).
Expand All @@ -309,6 +323,16 @@ Overrides the right template delimiter.
rightDelim: '))'
```

## `suppressEmpty`

See _[Suppressing empty output](../usage/#suppressing-empty-output)_

Suppresses empty output (i.e. output consisting of only whitespace). Can also be set with the `GOMPLATE_SUPPRESS_EMPTY` environment variable.

```yaml
suppressEmpty: true
```

## `templates`

See [`--template`/`-t`](../usage/#--template-t).
Expand Down
3 changes: 2 additions & 1 deletion docs/content/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ post-exec command.

## Suppressing empty output

Sometimes it can be desirable to suppress empty output (i.e. output consisting of only whitespace). To do so, set `GOMPLATE_SUPPRESS_EMPTY=true` in your environment:
Sometimes it can be desirable to suppress empty output (i.e. output consisting of only whitespace). To do so, set `suppressEmpty: true` in your [config][] file, or `GOMPLATE_SUPPRESS_EMPTY=true` in your environment:

```console
$ export GOMPLATE_SUPPRESS_EMPTY=true
Expand All @@ -290,5 +290,6 @@ cat: out: No such file or directory

[default context]: ../syntax/#the-context
[context]: ../syntax/#the-context
[config]: ../config/#suppressempty
[external templates]: ../syntax/#external-templates
[`.gitignore`]: https://git-scm.com/docs/gitignore
4 changes: 2 additions & 2 deletions gomplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func RunTemplatesWithContext(ctx context.Context, cfg *config.Config) error {
Metrics = newMetrics()
defer runCleanupHooks()

d := data.FromConfig(cfg.Sources(), cfg.ExtraHeaders)
d := data.FromConfig(cfg)
log.Debug().Str("data", fmt.Sprintf("%+v", d)).Msg("created data from config")

addCleanupHook(d.Cleanup)
Expand All @@ -139,7 +139,7 @@ func RunTemplatesWithContext(ctx context.Context, cfg *config.Config) error {
return err
}
funcMap := Funcs(d)
err = bindPlugins(ctx, cfg.Plugins, funcMap)
err = bindPlugins(ctx, cfg, funcMap)
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit 97a2150

Please sign in to comment.