diff --git a/.gitignore b/.gitignore index 061a3d6..da49504 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ tags /local /spiff /spiff++ -/hack /godoc *.coverprofile spiff_darwin_amd64.zip diff --git a/Gopkg.lock b/Gopkg.lock deleted file mode 100644 index 0b81028..0000000 --- a/Gopkg.lock +++ /dev/null @@ -1,345 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - branch = "master" - digest = "1:c12310d3e2b5a97b89dba30d1d006e00b564e04ec4f2d4b5d1631e97e86a8b42" - name = "github.com/cloudfoundry-incubator/candiedyaml" - packages = ["."] - pruneopts = "UT" - revision = "a41693b7b7afb422c7ecb1028458ab27da047bbb" - -[[projects]] - digest = "1:80057945464ffb5b0da1f026beb8df0e8dbd098eaf771a349291bed2cd29a83e" - name = "github.com/fsnotify/fsnotify" - packages = ["."] - pruneopts = "UT" - revision = "45d7d09e39ef4ac08d493309fa031790c15bfe8a" - version = "v1.4.9" - -[[projects]] - digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10" - name = "github.com/hashicorp/hcl" - packages = [ - ".", - "hcl/ast", - "hcl/parser", - "hcl/printer", - "hcl/scanner", - "hcl/strconv", - "hcl/token", - "json/parser", - "json/scanner", - "json/token", - ] - pruneopts = "UT" - revision = "8cb6e5b959231cc1119e43259c4a608f9c51a241" - version = "v1.0.0" - -[[projects]] - digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be" - name = "github.com/inconshreveable/mousetrap" - packages = ["."] - pruneopts = "UT" - revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" - version = "v1.0" - -[[projects]] - digest = "1:fae336644ff950d61b17ed30a0e82d710ab56e792321048f31afc82a3aa8375a" - name = "github.com/magiconair/properties" - packages = ["."] - pruneopts = "UT" - revision = "e55ec40311b90df900426eae806bb80a40154583" - version = "v1.8.3" - -[[projects]] - branch = "master" - digest = "1:79d4c7eac6cf9f9fd5c17cdc6536f28fc9532798f61ac1efa3a57152c379f221" - name = "github.com/mandelsoft/filepath" - packages = ["pkg/filepath"] - pruneopts = "UT" - revision = "3df73d378d552504d3df40fd7b6d8b00c12b4427" - -[[projects]] - digest = "1:e3bff19a88b38e751206f3f28599a9e3d23617255d4747c5fc9ea43691b0bb37" - name = "github.com/mandelsoft/vfs" - packages = [ - "pkg/osfs", - "pkg/projectionfs", - "pkg/utils", - "pkg/vfs", - ] - pruneopts = "UT" - revision = "d03d33d5889a612bddefccdd689094cc517b374a" - version = "v0.1" - -[[projects]] - digest = "1:aff0e9185b5df855488a42e064cb479e994636d3cefa47d053495123d086add4" - name = "github.com/mitchellh/mapstructure" - packages = ["."] - pruneopts = "UT" - revision = "9e1e4717f8567d7ead72d070d064ad17d444a67e" - version = "v1.3.3" - -[[projects]] - digest = "1:a9f00de9b605c251f5f1eba5d34c238131f0a7d38f6e7126c6bacc073f314865" - name = "github.com/nxadm/tail" - packages = [ - ".", - "ratelimiter", - "util", - "watch", - "winfile", - ] - pruneopts = "UT" - revision = "327c577245448d8192115e77a76ea3d6aee88202" - version = "v1.4.4" - -[[projects]] - digest = "1:e6097a089184d8efef123f5c66dc543069f2273806ba552e6d214294cfb7615a" - name = "github.com/onsi/ginkgo" - packages = [ - ".", - "config", - "internal/codelocation", - "internal/containernode", - "internal/failer", - "internal/global", - "internal/leafnodes", - "internal/remote", - "internal/spec", - "internal/spec_iterator", - "internal/specrunner", - "internal/suite", - "internal/testingtproxy", - "internal/writer", - "reporters", - "reporters/stenographer", - "reporters/stenographer/support/go-colorable", - "reporters/stenographer/support/go-isatty", - "types", - ] - pruneopts = "UT" - revision = "6d83527acb3f6cda405ce47a475d480117098381" - version = "v1.14.1" - -[[projects]] - digest = "1:a74054ea234c0ccf5e30e9ac9a438e6db25db2828f2ac636481d21bc3cfcf0b1" - name = "github.com/onsi/gomega" - packages = [ - ".", - "format", - "gbytes", - "gexec", - "internal/assertion", - "internal/asyncassertion", - "internal/oraclematcher", - "internal/testingtsupport", - "matchers", - "matchers/support/goraph/bipartitegraph", - "matchers/support/goraph/edge", - "matchers/support/goraph/node", - "matchers/support/goraph/util", - "types", - ] - pruneopts = "UT" - revision = "d7eb503b14592ef8cefacd3c9589398c7decaf23" - version = "v1.10.2" - -[[projects]] - digest = "1:ba7c8395a3bdd3b44d40ba36ff6eb283b583a3db865c02a952b89a1aa639081b" - name = "github.com/pelletier/go-toml" - packages = ["."] - pruneopts = "UT" - revision = "65ca8064882c8c308e5c804c5d5443d409e0738c" - version = "v1.8.1" - -[[projects]] - digest = "1:5bc51628f10ee2e983badf7e302531fd87db15badfb675389450b8765cb3149f" - name = "github.com/spf13/afero" - packages = [ - ".", - "mem", - ] - pruneopts = "UT" - revision = "a4ea980f2d023f22c7eede4c142190115449de5b" - version = "v1.4.0" - -[[projects]] - digest = "1:ff4cd55a3666b6ea3a876c9e133bfb54d6c812e725409a773f2c94a0b3a92f4f" - name = "github.com/spf13/cast" - packages = ["."] - pruneopts = "UT" - revision = "1ffadf551085444af981432dd0f6d1160c11ec64" - version = "v1.3.1" - -[[projects]] - digest = "1:1e80255eea46af2e2db7da90f95e4b5cfe84f3b58d9a8598ec35b0f2a75c60e4" - name = "github.com/spf13/cobra" - packages = ["."] - pruneopts = "UT" - revision = "6607e6b8603f56adb027298ee6695e06ffb3a819" - version = "0.0.7" - -[[projects]] - digest = "1:1b753ec16506f5864d26a28b43703c58831255059644351bbcb019b843950900" - name = "github.com/spf13/jwalterweatherman" - packages = ["."] - pruneopts = "UT" - revision = "94f6ae3ed3bceceafa716478c5fbf8d29ca601a1" - version = "v1.1.0" - -[[projects]] - digest = "1:524b71991fc7d9246cc7dc2d9e0886ccb97648091c63e30eef619e6862c955dd" - name = "github.com/spf13/pflag" - packages = ["."] - pruneopts = "UT" - revision = "2e9d26c8c37aae03e3f9d4e90b7116f5accb7cab" - version = "v1.0.5" - -[[projects]] - digest = "1:b3027d4cb73b6576e8818c1012389dbcd8385e34bb8e4ee024891214c4338725" - name = "github.com/spf13/viper" - packages = ["."] - pruneopts = "UT" - revision = "3826be313591f83193f048520482a7b3cf17d506" - version = "v1.7.1" - -[[projects]] - digest = "1:f4b32291cad5efac2bfdba89ccde6aa04618b62ce06c1a571da2dc4f3f2677fb" - name = "github.com/subosito/gotenv" - packages = ["."] - pruneopts = "UT" - revision = "2ef7124db659d49edac6aa459693a15ae36c671a" - version = "v1.2.0" - -[[projects]] - branch = "master" - digest = "1:4a02b656f2fdded85986e2bf64dcdc2277a8124626d12ef49f9d87fd600d78d4" - name = "golang.org/x/crypto" - packages = [ - "bcrypt", - "blowfish", - "chacha20", - "curve25519", - "ed25519", - "ed25519/internal/edwards25519", - "internal/subtle", - "md4", - "poly1305", - "ssh", - "ssh/internal/bcrypt_pbkdf", - ] - pruneopts = "UT" - revision = "5c72a883971a4325f8c62bf07b6d38c20ea47a6a" - -[[projects]] - branch = "master" - digest = "1:8c294aabd4396170f5bcbb763d558e4c8d21ded4b2a1618dfb664e58a4fffeef" - name = "golang.org/x/net" - packages = [ - "html", - "html/atom", - "html/charset", - ] - pruneopts = "UT" - revision = "62affa334b73ec65ed44a326519ac12c421905e3" - -[[projects]] - branch = "master" - digest = "1:54af96607722c8391392608c659997d4c51a7844c697689d22d42f282ddd9582" - name = "golang.org/x/sys" - packages = [ - "cpu", - "internal/unsafeheader", - "unix", - ] - pruneopts = "UT" - revision = "288bc346aa3906399979ee2fc63bacf4c43e04c9" - -[[projects]] - digest = "1:517b82807b3218687e9eb32fe11de9cb07a38d06554d04cd1965c0441360c0b3" - name = "golang.org/x/text" - packages = [ - "encoding", - "encoding/charmap", - "encoding/htmlindex", - "encoding/internal", - "encoding/internal/identifier", - "encoding/japanese", - "encoding/korean", - "encoding/simplifiedchinese", - "encoding/traditionalchinese", - "encoding/unicode", - "internal/gen", - "internal/language", - "internal/language/compact", - "internal/tag", - "internal/triegen", - "internal/ucd", - "internal/utf8internal", - "language", - "runes", - "transform", - "unicode/cldr", - "unicode/norm", - ] - pruneopts = "UT" - revision = "23ae387dee1f90d29a23c0e87ee0b46038fbed0e" - version = "v0.3.3" - -[[projects]] - branch = "master" - digest = "1:918a46e4a2fb83df33f668f5a6bd51b2996775d073fce1800d3ec01b0a5ddd2b" - name = "golang.org/x/xerrors" - packages = [ - ".", - "internal", - ] - pruneopts = "UT" - revision = "5ec99f83aff198f5fbd629d6c8d8eb38a04218ca" - -[[projects]] - digest = "1:e5b45b5c171a805052785685402c31e4a2f3872a7bc2a12fa8c36818149fa437" - name = "gopkg.in/ini.v1" - packages = ["."] - pruneopts = "UT" - revision = "fcd0515f91612282aba5f5231a7dd71487e6dd8f" - version = "v1.61.0" - -[[projects]] - branch = "v1" - digest = "1:0caa92e17bc0b65a98c63e5bc76a9e844cd5e56493f8fdbb28fad101a16254d9" - name = "gopkg.in/tomb.v1" - packages = ["."] - pruneopts = "UT" - revision = "dd632973f1e7218eb1089048e0798ec9ae7dceb8" - -[[projects]] - digest = "1:d7f1bd887dc650737a421b872ca883059580e9f8314d601f88025df4f4802dce" - name = "gopkg.in/yaml.v2" - packages = ["."] - pruneopts = "UT" - revision = "0b1645d91e851e735d3e23330303ce81f70adbe3" - version = "v2.3.0" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - input-imports = [ - "github.com/cloudfoundry-incubator/candiedyaml", - "github.com/mandelsoft/vfs/pkg/osfs", - "github.com/mandelsoft/vfs/pkg/vfs", - "github.com/onsi/ginkgo", - "github.com/onsi/gomega", - "github.com/onsi/gomega/gbytes", - "github.com/onsi/gomega/gexec", - "github.com/spf13/cobra", - "github.com/spf13/viper", - "golang.org/x/crypto/bcrypt", - "golang.org/x/crypto/curve25519", - "golang.org/x/crypto/md4", - "golang.org/x/crypto/ssh", - ] - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml deleted file mode 100644 index ec14658..0000000 --- a/Gopkg.toml +++ /dev/null @@ -1,64 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" -# -# [prune] -# non-go = false -# go-tests = true -# unused-packages = true - - -#[[constraint]] -# name = "github.com/cloudfoundry-incubator/candiedyaml" -# revision = "a41693b7b7afb422c7ecb1028458ab27da047bbb" - -[[constraint]] - name = "github.com/mandelsoft/vfs" - version = "v0.1" - -[[constraint]] - name = "github.com/spf13/cobra" - version = "0.0.3" - -[[constraint]] - name = "github.com/onsi/ginkgo" - version = "1.7.0" - -[[constraint]] - name = "github.com/onsi/gomega" - version = "1.4.3" - -[[override]] - name = "github.com/pointlander/peg" - revision = "1d0268dfff9bca9748dc9105a214ace2f5c594a8" - #revision = "9437239f9b1caa84a099b0be9ea5a11f1b3cc6e2" - -[[override]] - name = "gopkg.in/fsnotify.v1" - source = "https://github.com/fsnotify/fsnotify.git" - -[prune] - go-tests = true - unused-packages = true - -# [[prune.project]] -# name = "github.com/cloudfoundry-incubator/candiedyaml" -# go-tests = false -# unused-packages = false diff --git a/Makefile b/Makefile index 5b7ba92..53e741e 100644 --- a/Makefile +++ b/Makefile @@ -1,40 +1,45 @@ VERBOSE=-v -all: grammar test release +all: vendor grammar test release grammar: - go get github.com/pointlander/peg - (cd $(GOPATH)/src/github.com/pointlander/peg; git checkout 1d0268dfff9bca9748dc9105a214ace2f5c594a8; go install .) - peg dynaml/dynaml.peg + go generate ./... release: spiff_linux_amd64.zip spiff_darwin_amd64.zip spiff_linux_ppc64le.zip -linux: ensure +linux: GOOS=linux GOARCH=amd64 go build -o spiff++/spiff++ . -test: ensure +test: go test $(VERBOSE) ./... -spiff_linux_amd64.zip: ensure +spiff_linux_amd64.zip: GOOS=linux GOARCH=amd64 go build -o spiff++/spiff++ . rm -f spiff++/spiff_linux_amd64.zip (cd spiff++; zip spiff_linux_amd64.zip spiff++) rm spiff++/spiff++ -spiff_darwin_amd64.zip: ensure +spiff_darwin_amd64.zip: GOOS=darwin GOARCH=amd64 go build -o spiff++/spiff++ . rm -f spiff++/spiff_spiff_darwin_amd64.zip (cd spiff++; zip spiff_darwin_amd64.zip spiff++) rm spiff++/spiff++ -spiff_linux_ppc64le.zip: ensure +spiff_linux_ppc64le.zip: GOOS=linux GOARCH=ppc64le go build -o spiff++/spiff++ . rm -f spiff++/spiff_linux_ppc64le.zip (cd spiff++; zip spiff_linux_ppc64le.zip spiff++) rm spiff++/spiff++ -ensure: - dep ensure +.PHONY: vendor +vendor: + go mod vendor + +clean: + rm -rf ./spiff++ + +tidy: + go mod tidy # restore patched version of candiedyaml/decode.go #git checkout -- vendor/github.com/cloudfoundry-incubator/candiedyaml/decode.go #git checkout -- vendor/github.com/cloudfoundry-incubator/candiedyaml/emitter.go diff --git a/README.md b/README.md index 48193db..a711694 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,8 @@ Contents: - [(( validate(value,"dnsdomain") ))](#-validatevaluednsdomain-) - [(( check(value,"dnsdomain") ))](#-checkvaluednsdomain-) - [(( error("message") ))](#-errormessage-) + - [Math](#math) + - [Conversions](#conversions) - [Accessing External Content](#accessing-external-content) - [(( read("file.yml") ))](#-readfileyml-) - [(( exec("command", arg1, arg2) ))](#-execcommand-arg1-arg2-) @@ -177,6 +179,7 @@ Contents: - [Special Literals](#special-literals) - [Access to evaluation context](#access-to-evaluation-context) - [Operation Priorities](#operation-priorities) + - [String Interpolation](#string-interpolation) - [Structural Auto-Merge](#structural-auto-merge) - [Bringing it all together](#bringing-it-all-together) - [Useful to Know](#useful-to-know) @@ -2173,6 +2176,10 @@ an expression evaluating to either a string denoting a reference or a string list denoting the list of path elements for the reference. If no argument or an undefined (`~~`) is given, the actual field path is used. +Please note, that a given sole reference will not be evaluated as expression, +if its value should be used, it must be transformed to an expression, for example +by denoting `(ref)` or `[] ref` for a list expression. + Alternatively the `merge` operation could be used, for example `merge foo.bar`. The difference is that `stub` does not merge, therefore the field will still be merged (with the original path in the document). ### `(( eval(foo "." bar ) ))` @@ -2905,6 +2912,37 @@ Another scenario could be omitting a descriptive message for missing required fields by using an error expression as (default) value for a field intended to be defined in an upstream stub. +### Math + +*dynaml* support various math functions: + +returning integers: `ceil`, `floor`, `round` and `roundtoeven` + +returning floats or integers: `abs` + +returning floats: `sin`,`cos`, `sinh`, `cosh`, `asin`, `acos`, `asinh`,`acosh`, + `sqrt`, `exp`, `log`, `log10`, + +### Conversions + +*dynaml* supports various type conversions between `integer`, `float`, `bool` +and `string` values by appropriate functions. + +e.g.: + + +```yaml +value: (( integer("5") )) +``` + +converts a string to an integer value. + +Converting an integer to a string accepts an optional additional integer +argument for specifying the base for conversion, for example `string(55,2)` +will result in `"110111"`. The default base is 10. The base must be between +2 and 36. + + ### Accessing External Content _Spiff_ supports access to content outside of the template and sub files. It is @@ -5003,6 +5041,64 @@ The following levels are supported (from low priority to high priority) The complete grammar can be found in [dynaml.peg](dynaml/dynaml.peg). +## String Interpolation + +**Attention:** This is an alpha feature. It must be enabled on the command +line with the `--interpolation` option. Also for the spiff library it must +explicitly be enabled. By adding the key `interpolation` to the feature list +stored in the environment variable `SPIFF_FEATURES` this feature will be enabled +by default. + +Typically a complete value can either be a literal or a dynaml expression. +For string literals it is possible to use an interpolation syntax to embed +dynaml expressions into strings. + +For example + +```yaml +data: test +interpolation: this is a (( data )) +``` + +replaces the part between the double brackets by the result +of the described expression evaluation. Here the brackets can be escaped +by the usual escaping (`((!`) syntax. + +Those string literals will implicitly be converted to complete flat dynaml +expressions. The example above will therefore be converted into + +`(( "this is a " data ))` + +which is the regular dynaml equivalent. The escaping is very ticky, and +may be there are still problems. Quotes inside an embedded dynaml expression +can be escaped to enable quotes in string literals. + +Incomplete or partial interpolation expressions will be ignored and +just used a s string. + +Strings inside a dynaml expression are NOT directly interpolated again, thus + +```yaml +data: "test" +interpolated: "this is a (( length(\"(( data ))\") data ))" +``` + +will resolve `interpolation` to `this is 10test` and not to `this is 4test`. + +But if the final string after the expression evaluation again describes a string +interpolation it will be processed, again. + +```yaml +data: test +interpolation: this is a (( "(( data ))" data )) +``` + +will resolve `interpolation` to `this is testtest`. + +The embedded dynaml expression must be concatenatable with strings. + + + # Structural Auto-Merge By default `spiff` performs a deep structural merge of its first argument, the template file, with the given stub files. The merge is processed from right to left, providing an intermediate merged stub for every step. This means, that for every step all expressions must be locally resolvable. diff --git a/cmd/encrypt.go b/cmd/encrypt.go index 6026c4e..f6d48cd 100644 --- a/cmd/encrypt.go +++ b/cmd/encrypt.go @@ -11,6 +11,7 @@ import ( "github.com/spf13/cobra" "github.com/mandelsoft/spiff/dynaml/passwd" + "github.com/mandelsoft/spiff/features" "github.com/mandelsoft/spiff/yaml" ) @@ -55,7 +56,7 @@ func encrypt(decrypt bool, args []string) { log.Fatalln(fmt.Sprintf("error reading data [%s]:", path.Clean(filePath)), err) } - key := os.Getenv("SPIFF_ENCRYPTION_KEY") + key := features.EncryptionKey() method := passwd.TRIPPLEDES v := "" if len(args) > 1 { diff --git a/cmd/merge.go b/cmd/merge.go index ab55bab..ad1de0c 100644 --- a/cmd/merge.go +++ b/cmd/merge.go @@ -14,6 +14,7 @@ import ( "github.com/mandelsoft/spiff/debug" "github.com/mandelsoft/spiff/dynaml" + "github.com/mandelsoft/spiff/features" "github.com/mandelsoft/spiff/flow" "github.com/mandelsoft/spiff/legacy/candiedyaml" "github.com/mandelsoft/spiff/yaml" @@ -24,6 +25,7 @@ var outputPath string var selection []string var expr string var split bool +var interpolation bool var processingOptions flow.Options var state string var bindings string @@ -51,8 +53,12 @@ var mergeCmd = &cobra.Command{ } func init() { + + set := features.Features() + _, interpolation = set[features.INTERPOLATION] rootCmd.AddCommand(mergeCmd) + mergeCmd.Flags().BoolVar(&interpolation, "interpolation", interpolation, "enable interpolation alpha feature") mergeCmd.Flags().BoolVar(&asJSON, "json", false, "print output in json format") mergeCmd.Flags().BoolVar(&debug.DebugFlag, "debug", false, "Print state info") mergeCmd.Flags().BoolVar(&processingOptions.Partial, "partial", false, "Allow partial evaluation only") @@ -197,14 +203,19 @@ func merge(stdin bool, templateFilePath string, opts flow.Options, json, split b " -: depending on a node with an error" var binding dynaml.Binding - if bindingYAML != nil { - values, ok := bindingYAML.Value().(map[string]yaml.Node) - if !ok { - log.Fatalln("bindings must be given as map") - } + if bindingYAML != nil || interpolation { + defstate := flow.NewDefaultState().SetInterpolation(interpolation) binding = flow.NewEnvironment( - nil, "context").WithLocalScope(values) + nil, "context", defstate) + if bindingYAML != nil { + values, ok := bindingYAML.Value().(map[string]yaml.Node) + if !ok { + log.Fatalln("bindings must be given as map") + } + binding = binding.WithLocalScope(values) + } } + prepared, err := flow.PrepareStubs(binding, processingOptions.Partial, stubs...) if !processingOptions.Partial && err != nil { log.Fatalln("error generating manifest:", err, legend) diff --git a/cmd/root.go b/cmd/root.go index 1a6d71e..0927263 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -17,7 +17,7 @@ var cfgFile string var rootCmd = &cobra.Command{ Use: "spiff", Short: "YAML in-domain templating processor", - Version: "v1.6.1", + Version: "v1.7.0-beta-1", } // Execute adds all child commands to the root command and sets flags appropriately. diff --git a/dynaml/convert.go b/dynaml/convert.go new file mode 100644 index 0000000..1c38ca3 --- /dev/null +++ b/dynaml/convert.go @@ -0,0 +1,127 @@ +package dynaml + +import ( + "fmt" + "strconv" +) + +func init() { + RegisterFunction("string", func_string) + RegisterFunction("integer", func_integer) + RegisterFunction("float", func_float) + RegisterFunction("bool", func_bool) +} + +func func_string(arguments []interface{}, binding Binding) (interface{}, EvaluationInfo, bool) { + info := DefaultInfo() + if len(arguments) != 1 { + if _, ok := arguments[0].(int64); ok { + if len(arguments) != 2 { + return info.Error("string for integers requires one or two arguments") + } + } else { + return info.Error("string requires one argument") + } + } + switch v := arguments[0].(type) { + case string: + return v, info, true + case int64: + base := 10 + if len(arguments) == 2 { + if b, ok := arguments[1].(int64); !ok { + return info.Error("base argument for string requires integer value") + } else { + base = int(b) + } + if 2 > base || base > 36 { + return info.Error("base argument for string requires integer value >=2 and <=36 ") + } + } + return strconv.FormatInt(v, base), info, true + case float64: + return fmt.Sprintf("%g", v), info, true + case bool: + if v { + return "true", info, true + } + return "false", info, true + default: + return info.Error("cannot convert %T to string", v) + } +} + +func func_integer(arguments []interface{}, binding Binding) (interface{}, EvaluationInfo, bool) { + info := DefaultInfo() + if len(arguments) != 1 { + return info.Error("integer requires one argument") + } + switch v := arguments[0].(type) { + case string: + i, err := strconv.ParseInt(v, 10, 64) + if err != nil { + return info.Error("%q is no integer value: %s", err) + } + return i, info, true + case int64: + return v, info, true + case float64: + return int64(v), info, true + case bool: + if v { + return 1, info, true + } + return 0, info, true + default: + return info.Error("cannot convert %T to integer", v) + } +} + +func func_float(arguments []interface{}, binding Binding) (interface{}, EvaluationInfo, bool) { + info := DefaultInfo() + if len(arguments) != 1 { + return info.Error("float requires one argument") + } + switch v := arguments[0].(type) { + case string: + f, err := strconv.ParseFloat(v, 64) + if err != nil { + return info.Error("%q is no float value: %s", err) + } + return f, info, true + case int64: + return float64(v), info, true + case float64: + return v, info, true + case bool: + if v { + return float64(1), info, true + } + return float64(0), info, true + default: + return info.Error("cannot convert %T to float", v) + } +} + +func func_bool(arguments []interface{}, binding Binding) (interface{}, EvaluationInfo, bool) { + info := DefaultInfo() + if len(arguments) != 1 { + return info.Error("bool requires one argument") + } + switch v := arguments[0].(type) { + case string: + i, err := strconv.ParseBool(v) + if err != nil { + return info.Error("%q is no bool value: %s", err) + } + return i, info, true + case int64: + return v != 0, info, true + case float64: + return v != 0, info, true + case bool: + return v, info, true + default: + return info.Error("cannot convert %T to bool", v) + } +} diff --git a/dynaml/expression.go b/dynaml/expression.go index b49ceb8..90098ee 100644 --- a/dynaml/expression.go +++ b/dynaml/expression.go @@ -24,6 +24,9 @@ type State interface { FileAccessAllowed() bool FileSystem() vfs.VFS GetFunctions() Registry + InterpolationEnabled() bool + + EnableInterpolation() } type Binding interface { diff --git a/dynaml/floatmath.go b/dynaml/floatmath.go new file mode 100644 index 0000000..308bd38 --- /dev/null +++ b/dynaml/floatmath.go @@ -0,0 +1,77 @@ +package dynaml + +import ( + "math" + "reflect" + "runtime" + "strings" +) + +var float_functions = []func(float64) float64{ + math.Floor, math.Ceil, math.Round, math.RoundToEven, + math.Abs, + math.Sin, math.Cos, math.Sinh, math.Cosh, + math.Asin, math.Acos, math.Asinh, math.Acosh, + math.Sqrt, math.Exp, math.Log, math.Log10, +} + +func init() { + for _, f := range float_functions { + s := strings.Split(runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name(), ".") + n := strings.ToLower(s[len(s)-1]) + f := f + RegisterFunction(n, func(arguments []interface{}, binding Binding) (interface{}, EvaluationInfo, bool) { + return _float(n, f, arguments) + }) + } +} + +func _float(name string, f func(float64) float64, arguments []interface{}) (val interface{}, info EvaluationInfo, ok bool) { + info = DefaultInfo() + defer func() { + if r := recover(); r != nil { + val, info, ok = info.Error("%s", r) + } + }() + if len(arguments) != 1 { + return info.Error("%s requires one argument", name) + } + if name == "ceil" || name == "floor" || name == "round" || name == "roundtoeven" { + switch v := arguments[0].(type) { + case int64: + return v, info, true + case float64: + return int64(f(v)), info, true + case bool: + if v { + return 1, info, true + } + return 0, info, true + default: + return info.Error("invalid argument type for %s: %T", name, v) + } + } else { + if name == "abs" { + switch v := arguments[0].(type) { + case int64: + if v < 0 { + return -v, info, true + } + return v, info, true + } + } + var r float64 + switch v := arguments[0].(type) { + case int64: + r = f(float64(v)) + case float64: + r = f(v) + default: + return info.Error("invalid argument type for %s: %T", name, v) + } + if math.IsNaN(r) { + return info.Error("%s: NaN", name) + } + return r, info, true + } +} diff --git a/dynaml/parser.go b/dynaml/parser.go index 2c7aaf7..50cbcdc 100644 --- a/dynaml/parser.go +++ b/dynaml/parser.go @@ -1,3 +1,5 @@ +//go:generate go run -v ../vendor/github.com/pointlander/peg dynaml.peg + package dynaml import ( diff --git a/dynaml/qualified_expression.go b/dynaml/qualified_expression.go index c928670..168d552 100644 --- a/dynaml/qualified_expression.go +++ b/dynaml/qualified_expression.go @@ -13,7 +13,6 @@ type QualifiedExpr struct { } func (e QualifiedExpr) Evaluate(binding Binding, locally bool) (interface{}, EvaluationInfo, bool) { - root, info, ok := e.Expression.Evaluate(binding, locally) if !ok { debug.Debug("base of qualified expression failed: %s\n", info.Issue.Issue) @@ -22,6 +21,11 @@ func (e QualifiedExpr) Evaluate(binding Binding, locally bool) (interface{}, Eva locally = locally || info.Raw if !isLocallyResolvedValue(root) { debug.Debug("not locally resolved: %v\n", root) + if root != nil { + if ex, ok := root.(Expression); ok { + return QualifiedExpr{ex, e.Reference}, info, true + } + } return e, info, true } if !locally && !isResolvedValue(root) { diff --git a/dynaml/read.go b/dynaml/read.go index a42887a..1d1ae97 100644 --- a/dynaml/read.go +++ b/dynaml/read.go @@ -152,7 +152,7 @@ func asTemplate(n yaml.Node, binding Binding) TemplateValue { e, ok = m["<<"] } if ok { - s := yaml.EmbeddedDynaml(e) + s := yaml.EmbeddedDynaml(e, binding.GetState().InterpolationEnabled()) if s != nil && templ_pattern.MatchString(*s) { found = true break diff --git a/dynaml/stub.go b/dynaml/stub.go index 285b120..6f3cbe7 100644 --- a/dynaml/stub.go +++ b/dynaml/stub.go @@ -1,8 +1,9 @@ package dynaml import ( - "github.com/mandelsoft/spiff/yaml" "strings" + + "github.com/mandelsoft/spiff/yaml" ) func (e CallExpr) stub(binding Binding) (interface{}, EvaluationInfo, bool) { diff --git a/dynaml/unresolved_check.go b/dynaml/unresolved_check.go index 294c262..0e32233 100644 --- a/dynaml/unresolved_check.go +++ b/dynaml/unresolved_check.go @@ -188,7 +188,7 @@ func FindUnresolvedNodes(root yaml.Node, context ...string) (result []Unresolved // ) case string: - if s := yaml.EmbeddedDynaml(root); s != nil { + if s := yaml.EmbeddedDynaml(root, false); s != nil { _, err := Parse(*s, dummy, dummy) if err != nil { nodes = append(nodes, UnresolvedNode{ @@ -312,7 +312,7 @@ func isResolvedValue(val interface{}) bool { return true case string: - if yaml.EmbeddedDynaml(NewNode(val, nil)) != nil { + if yaml.EmbeddedDynaml(NewNode(val, nil), false) != nil { return false } return true diff --git a/features/features.go b/features/features.go new file mode 100644 index 0000000..cd322ce --- /dev/null +++ b/features/features.go @@ -0,0 +1,39 @@ +package features + +import ( + "os" + "strings" +) + +const INTERPOLATION = "interpolation" + +func SetFeature(features map[string]struct{}, f string, val bool) { + if val { + features[f] = struct{}{} + } else { + delete(features, f) + } +} + +func Features() map[string]struct{} { + features := map[string]struct{}{} + // setup defaults + SetFeature(features, INTERPOLATION, true) + setting := os.Getenv("SPIFF_FEATURES") + for _, f := range strings.Split(setting, ",") { + f = strings.ToLower(strings.TrimSpace(f)) + no := strings.HasPrefix(f, "no") + if no { + f = f[2:] + } + switch f { + case INTERPOLATION: + SetFeature(features, INTERPOLATION, !no) + } + } + return features +} + +func EncryptionKey() string { + return os.Getenv("SPIFF_ENCRYPTION_KEY") +} diff --git a/flow/cascade.go b/flow/cascade.go index 0eb2bed..af16272 100644 --- a/flow/cascade.go +++ b/flow/cascade.go @@ -34,7 +34,7 @@ func Apply(outer dynaml.Binding, template yaml.Node, prepared []yaml.Node, opts result = Cleanup(result, discardTemporary) } if !opts.PreserveEscapes { - result = Cleanup(result, unescapeDynaml) + result = Cleanup(result, unescapeDynamlFunc(outer)) } } return result, err @@ -56,8 +56,13 @@ func discardTemporary(node yaml.Node) (yaml.Node, CleanupFunction) { return node, discardTemporary } -func unescapeDynaml(node yaml.Node) (yaml.Node, CleanupFunction) { - return yaml.UnescapeDynaml(node), unescapeDynaml +func unescapeDynamlFunc(binding dynaml.Binding) CleanupFunction { + interpol := binding != nil && binding.GetState().InterpolationEnabled() + var f CleanupFunction + f = func(node yaml.Node) (yaml.Node, CleanupFunction) { + return yaml.UnescapeDynaml(node, interpol), f + } + return f } func discardLocal(node yaml.Node) (yaml.Node, CleanupFunction) { diff --git a/flow/cascade_as_helper_test.go b/flow/cascade_as_helper_test.go index 99a6e9a..816bd19 100644 --- a/flow/cascade_as_helper_test.go +++ b/flow/cascade_as_helper_test.go @@ -20,8 +20,8 @@ func (matcher *CascadeAsMatcher) Match(source interface{}) (success bool, err er if source == nil && matcher.Expected == nil { return false, fmt.Errorf("Refusing to compare to .") } - - matcher.actual, err = Cascade(nil, source.(yaml.Node), Options{}, matcher.Stubs...) + env := NewEnvironment(nil, "", NewDefaultState().SetInterpolation(true)) + matcher.actual, err = Cascade(env, source.(yaml.Node), Options{}, matcher.Stubs...) if err != nil { return false, err } diff --git a/flow/cascade_test.go b/flow/cascade_test.go index 43dc2be..f7ef43d 100644 --- a/flow/cascade_test.go +++ b/flow/cascade_test.go @@ -1313,6 +1313,19 @@ foo: Expect(source).To(CascadeAs(resolved)) }) + It("ignores nodes with escape", func() { + source := parseYAML(` +--- +foo: ((!template_only.foo)) +`) + + resolved := parseYAML(` +--- +foo: ((template_only.foo)) +`) + + Expect(source).To(CascadeAs(resolved)) + }) It("ignores nodes with escaped escape", func() { source := parseYAML(` --- @@ -1322,6 +1335,19 @@ foo: ((!!template_only.foo)) resolved := parseYAML(` --- foo: ((!template_only.foo)) +`) + + Expect(source).To(CascadeAs(resolved)) + }) + It("ignores nodes with escaped interpolation", func() { + source := parseYAML(` +--- +foo: x ((!template_only.foo)) +`) + + resolved := parseYAML(` +--- +foo: x ((template_only.foo)) `) Expect(source).To(CascadeAs(resolved)) diff --git a/flow/environment.go b/flow/environment.go index 640dfa9..3fea075 100644 --- a/flow/environment.go +++ b/flow/environment.go @@ -2,13 +2,13 @@ package flow import ( "fmt" - "os" "path/filepath" "reflect" "strings" "github.com/mandelsoft/spiff/debug" "github.com/mandelsoft/spiff/dynaml" + "github.com/mandelsoft/spiff/features" "github.com/mandelsoft/spiff/yaml" ) @@ -128,6 +128,9 @@ func (e DefaultEnvironment) CurrentSourceName() string { } func (e DefaultEnvironment) GetRootBinding() map[string]yaml.Node { + if e.scope == nil { + return nil + } return e.scope.root.local } @@ -300,13 +303,13 @@ func NewEnvironment(stubs []yaml.Node, source string, optstate ...*State) dynaml state = optstate[0] } if state == nil { - state = NewState(os.Getenv("SPIFF_ENCRYPTION_KEY"), MODE_OS_ACCESS|MODE_FILE_ACCESS) + state = NewState(features.EncryptionKey(), MODE_OS_ACCESS|MODE_FILE_ACCESS) } return DefaultEnvironment{state: state, stubs: stubs, sourceName: source, currentSourceName: source, outer: nil, active: true, binding: true} } func NewProcessLocalEnvironment(stubs []yaml.Node, source string) dynaml.Binding { - state := NewState(os.Getenv("SPIFF_ENCRYPTION_KEY"), 0) + state := NewState(features.EncryptionKey(), 0) return DefaultEnvironment{state: state, stubs: stubs, sourceName: source, currentSourceName: source, outer: nil, active: true} } @@ -320,7 +323,7 @@ func CleanupEnvironment(binding dynaml.Binding) { func NewNestedEnvironment(stubs []yaml.Node, source string, outer dynaml.Binding) dynaml.Binding { var state *State if outer == nil { - state = NewState(os.Getenv("SPIFF_ENCRYPTION_KEY"), MODE_OS_ACCESS|MODE_FILE_ACCESS) + state = NewDefaultState() } return DefaultEnvironment{state: state, stubs: stubs, sourceName: source, currentSourceName: source, outer: outer, active: true} } @@ -400,7 +403,9 @@ func getOuters(env *DefaultEnvironment) (yaml.Node, yaml.Node) { if e, ok := outer.(DefaultEnvironment); ok && e.binding { bindings = outer } - list = append(list, node(outer.GetRootBinding())) + if b := outer.GetRootBinding(); b != nil { + list = append(list, node(b)) + } outer = outer.Outer() } } diff --git a/flow/flow.go b/flow/flow.go index 5a6ad73..d520d7f 100644 --- a/flow/flow.go +++ b/flow/flow.go @@ -312,7 +312,7 @@ func flowMap(root yaml.Node, env dynaml.Binding) yaml.Node { } // still ignore non dynaml value (might be strange but compatible) replace = base.ReplaceFlag() - parseError := yaml.EmbeddedDynaml(base) != nil + parseError := yaml.EmbeddedDynaml(base, env.GetState().InterpolationEnabled()) != nil if !ok && base.Value() != nil && !parseError { err = fmt.Errorf("require map value for '<<' insert, found '%s'", dynaml.ExpressionType(base.Value())) } @@ -449,7 +449,7 @@ func flowList(root yaml.Node, env dynaml.Binding) yaml.Node { func FlowString(root yaml.Node, env dynaml.Binding) (yaml.Node, error) { - sub := yaml.EmbeddedDynaml(root) + sub := yaml.EmbeddedDynaml(root, env.GetState().InterpolationEnabled()) if sub == nil { return root, nil } @@ -560,7 +560,7 @@ func processMerges(orig yaml.Node, root []yaml.Node, env dynaml.Binding) (interf spliced = append(spliced, inlineNew...) } } - if ok || result.Value() == nil || yaml.EmbeddedDynaml(result) == nil { + if ok || result.Value() == nil || yaml.EmbeddedDynaml(result, env.GetState().InterpolationEnabled()) == nil { // still ignore non dynaml value (might be strange but compatible) redirectPath = result.RedirectPath() if result.Merged() { diff --git a/flow/flow_as_helper_test.go b/flow/flow_as_helper_test.go index 19cd61d..5653e2d 100644 --- a/flow/flow_as_helper_test.go +++ b/flow/flow_as_helper_test.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/cloudfoundry-incubator/candiedyaml" + "github.com/mandelsoft/spiff/yaml" ) @@ -23,7 +24,8 @@ func (matcher *FlowAsMatcher) Match(source interface{}) (success bool, err error return false, fmt.Errorf("Refusing to compare to .") } - matcher.actual, err = Flow(source.(yaml.Node), matcher.Stubs...) + env := NewEnvironment(nil, "", NewDefaultState().SetInterpolation(true)) + matcher.actual, err = NestedFlow(env, source.(yaml.Node), matcher.Stubs...) if err != nil { return false, err } diff --git a/flow/flow_test.go b/flow/flow_test.go index a011f86..6be3f36 100644 --- a/flow/flow_test.go +++ b/flow/flow_test.go @@ -7525,6 +7525,17 @@ fail: (( catch( 1 / 0 ) )) fail: error: division by zero valid: false +`) + Expect(source).To(FlowAs(resolved)) + }) + It("catch error message", func() { + source := parseYAML(` +--- +fail: (( catch( 1 / 0 ).error )) +`) + resolved := parseYAML(` +--- +fail: division by zero `) Expect(source).To(FlowAs(resolved)) }) @@ -8447,6 +8458,121 @@ url: userinfo: username: user password: pass +`) + Expect(source).To(FlowAs(resolved)) + }) + }) + + Context("string interpolation", func() { + It("handles expressions in strings", func() { + source := parseYAML(` +--- +data: "test" +interpolated: this is a (( data )) +`) + + resolved := parseYAML(` +--- +data: "test" +interpolated: this is a test +`) + Expect(source).To(FlowAs(resolved)) + }) + + It("handles expressions in strings", func() { + source := parseYAML(` +--- +data: "test" +interpolated: "this is a (( \"super \" data ))" +`) + + resolved := parseYAML(` +--- +data: "test" +interpolated: this is a super test +`) + Expect(source).To(FlowAs(resolved)) + }) + It("handles bracket expressions in strings", func() { + source := parseYAML(` +--- +data: "interpol" +interpolated: "this is a ((( ( data ( data )) ))) hell" +`) + + resolved := parseYAML(` +--- +data: "interpol" +interpolated: this is a (interpolinterpol) hell +`) + Expect(source).To(FlowAs(resolved)) + }) + It("re-evaluates expressions", func() { + source := parseYAML(` +--- +data: "test" +interpolated: "this is a (( \"(( data ))\" data ))" +`) + + resolved := parseYAML(` +--- +data: "test" +interpolated: this is a testtest +`) + Expect(source).To(FlowAs(resolved)) + }) + + It("does not handle interpolation in interpolation", func() { + source := parseYAML(` +--- +data: "test" +interpolated: "this is a (( length(\"(( data ))\") data ))" +`) + + resolved := parseYAML(` +--- +data: "test" +interpolated: this is a 10test +`) + Expect(source).To(FlowAs(resolved)) + }) + }) + Context("math", func() { + It("sqrt", func() { + source := parseYAML(` +--- +data: (( sqrt(25) )) +fail: (( catch(sqrt(-1)) )) +`) + + resolved := parseYAML(` +--- +data: 5.0 +fail: + error: 'sqrt: NaN' + valid: false +`) + Expect(source).To(FlowAs(resolved)) + }) + It("int/float", func() { + source := parseYAML(` +--- +int: (( abs(-25) )) +float: (( abs(-1.5) )) +ceil: (( ceil(1.5) )) +floor: (( floor(1.5) )) +round1: (( round(1.4) )) +round2: (( round(1.5) )) +`) + + resolved := parseYAML(` +--- +int: 25 +float: 1.5 +ceil: 2 +floor: 1 +round1: 1 +round2: 2 `) Expect(source).To(FlowAs(resolved)) }) diff --git a/flow/state.go b/flow/state.go index 86a9508..e1e4cfd 100644 --- a/flow/state.go +++ b/flow/state.go @@ -14,18 +14,20 @@ import ( "github.com/mandelsoft/spiff/debug" "github.com/mandelsoft/spiff/dynaml" + "github.com/mandelsoft/spiff/features" ) const MODE_FILE_ACCESS = 1 // support file system access const MODE_OS_ACCESS = 2 // support os commands like pipe and exec type State struct { - files map[string]string // content hash to temp file name - fileCache map[string][]byte // file content cache - key string // default encryption key - mode int - fileSystem vfs.VFS // virtual filesystem to use for filesystem based operations - functions dynaml.Registry + files map[string]string // content hash to temp file name + fileCache map[string][]byte // file content cache + key string // default encryption key + mode int + fileSystem vfs.VFS // virtual filesystem to use for filesystem based operations + functions dynaml.Registry + interpolation bool } var _ dynaml.State = &State{} @@ -49,11 +51,28 @@ func NewState(key string, mode int, optfs ...vfs.FileSystem) *State { } } +func NewDefaultState() *State { + return NewState(features.EncryptionKey(), MODE_OS_ACCESS|MODE_FILE_ACCESS) +} + func (s *State) SetFunctions(f dynaml.Registry) *State { s.functions = f return s } +func (s *State) EnableInterpolation() { + s.interpolation = true +} + +func (s *State) SetInterpolation(b bool) *State { + s.interpolation = b + return s +} + +func (s *State) InterpolationEnabled() bool { + return s.interpolation +} + func (s *State) OSAccessAllowed() bool { return s.mode&MODE_OS_ACCESS != 0 } diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..8ba94d8 --- /dev/null +++ b/go.mod @@ -0,0 +1,27 @@ +module github.com/mandelsoft/spiff + +go 1.16 + +require ( + github.com/cloudfoundry-incubator/candiedyaml v0.0.0-20170901234223-a41693b7b7af + github.com/magiconair/properties v1.8.3 // indirect + github.com/mandelsoft/vfs v0.0.0-20201002080026-d03d33d5889a + github.com/mitchellh/mapstructure v1.3.3 // indirect + github.com/onsi/ginkgo v1.14.1 + github.com/onsi/gomega v1.10.2 + github.com/pelletier/go-toml v1.8.1 // indirect + github.com/pointlander/compress v1.1.0 // indirect + github.com/pointlander/jetset v1.0.0 // indirect + github.com/pointlander/peg v0.0.0-20160608205303-1d0268dfff9b + github.com/spf13/afero v1.4.0 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/cobra v0.0.7 + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.7.1 + golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a + golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect + golang.org/x/sys v0.0.0-20200915084602-288bc346aa39 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + gopkg.in/ini.v1 v1.61.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..cc2edaa --- /dev/null +++ b/go.sum @@ -0,0 +1,397 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/b4b4r07/go-pipe v0.0.0-20191010045404-84b446f57366/go.mod h1:1ymsiQNa3qebVEEVtuIdhtAXRfjO4qFCFq1bBUOT2HE= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudfoundry-incubator/candiedyaml v0.0.0-20170901234223-a41693b7b7af h1:6Cpkahw28+gcBdnXQL7LcMTX488+6jl6hfoTMRT6Hm4= +github.com/cloudfoundry-incubator/candiedyaml v0.0.0-20170901234223-a41693b7b7af/go.mod h1:dOLSIXcRQJiDS1vlrYFNJicoHNZLsBKideE+70hGdV4= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/joncalhoun/pipe v0.0.0-20170510025636-72505674a733/go.mod h1:2MNFZhLx2HMHTN4xKH6FhpoQWqmD8Ato8QOE2hp5hY4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.3 h1:kJSsc6EXkBLgr3SphHk9w5mtjn0bjlR4JYEXKrJ45rQ= +github.com/magiconair/properties v1.8.3/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mandelsoft/filepath v0.0.0-20200909114706-3df73d378d55 h1:mFdiUG86O2iW+iDEpZKXf64efMWO4JvDT+zN3znUGIc= +github.com/mandelsoft/filepath v0.0.0-20200909114706-3df73d378d55/go.mod h1:n4xEiUD2HNHnn2w5ZKF0qgjDecHVCWAl5DxZ7+pcFU8= +github.com/mandelsoft/vfs v0.0.0-20201002080026-d03d33d5889a h1:j7Hu1c0F1HyevcYWh3TdCJrHHpFSbRhbaOh71JCqbFM= +github.com/mandelsoft/vfs v0.0.0-20201002080026-d03d33d5889a/go.mod h1:74aV7kulg9C434HiI3zNALN79QHc9IZMN+SI4UdLn14= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= +github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= +github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pointlander/compress v1.1.0 h1:5fUcQV2qEHvk0OpILH6eltwluN5VnwiYrkc1wjGUHnU= +github.com/pointlander/compress v1.1.0/go.mod h1:q5NXNGzqj5uPnVuhGkZfmgHqNUhf15VLi6L9kW0VEc0= +github.com/pointlander/jetset v1.0.0 h1:bNlaNAX7cDPID9SlcogmXlDWq0KcRJSpKwHXaAM3bGQ= +github.com/pointlander/jetset v1.0.0/go.mod h1:zY6+WHRPB10uzTajloHtybSicLW1bf6Rz0eSaU9Deng= +github.com/pointlander/peg v0.0.0-20160608205303-1d0268dfff9b h1:R5e+/H/+1WqgiqPVk+zSHPQNan9p8p9hr6C+pEdzk8s= +github.com/pointlander/peg v0.0.0-20160608205303-1d0268dfff9b/go.mod h1:WJTMcgeWYr6fZz4CwHnY1oWZCXew8GWCF93FaAxPrh4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.4.0 h1:jsLTaI1zwYO3vjrzHalkVcIHXTNmdQFepW4OI8H3+x8= +github.com/spf13/afero v1.4.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.7 h1:FfTH+vuMXOas8jmfb5/M7dzEYx7LpcLb7a0LPe34uOU= +github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA= +golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200915084602-288bc346aa39 h1:356XA7ITklAU2//sYkjFeco+dH1bCRD8XCJ9FIEsvo4= +golang.org/x/sys v0.0.0-20200915084602-288bc346aa39/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.61.0 h1:LBCdW4FmFYL4s/vDZD1RQYX7oAR6IjujCYgMdbHBR10= +gopkg.in/ini.v1 v1.61.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/pipe.v2 v2.0.0-20140414041502-3c2ca4d52544/go.mod h1:UhTeH/yXCK/KY7TX24mqPkaQ7gZeqmWd/8SSS8B3aHw= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/hack/peg b/hack/peg new file mode 100755 index 0000000..abe03fd --- /dev/null +++ b/hack/peg @@ -0,0 +1,11 @@ +#!/bin/bash + +current_dir="$(pwd)" +if ! readlink -f . &>/dev/null; then + echo "you're probably on OSX. Please install gnu readlink -- otherwise you're missing the most useful readlink flag." + exit 1 +fi +tool_dir="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" +cd "${tool_dir}/../vendor/github.com/pointlander/peg" +echo go run -v . "${current_dir}/$1" +go run -v . "${current_dir}/$1" diff --git a/hack/tools.go b/hack/tools.go new file mode 100644 index 0000000..5429fb5 --- /dev/null +++ b/hack/tools.go @@ -0,0 +1,7 @@ +// +build tools + +package tools + +import ( + _ "github.com/pointlander/peg" +) diff --git a/libraries/certs/README.md b/libraries/certs/README.md index f138f51..c4da003 100644 --- a/libraries/certs/README.md +++ b/libraries/certs/README.md @@ -26,7 +26,7 @@ when using the functions in a stateful scenario. ## Generate a self signed Certificate for dedicated common name ``` - selfSignedCA(, =false, =[]) -> state + selfSignedCA(, =false, =[], relindex=0) -> state ``` The _value_ field provides the fields: @@ -37,7 +37,7 @@ The _value_ field provides the fields: ## Generate a Key/Certificate Pair ``` - keyCertForCA(, , =false, =[]) -> state + keyCertForCA(, , =false, =[], relindex=0) -> state ``` the certificate specification uses the format for the @@ -54,7 +54,7 @@ The _value_ field provides the fields: ## Generate a Certificate with an explicitly managed Specification ``` - keyCert(, =false, =[]) -> state + keyCert(, =false, =[], relindex=0) -> state ``` the certificate specification uses the format for the @@ -70,7 +70,7 @@ The _value_ field provides the fields: ## Generate an SSH Key Pair ``` - sshKey(=2048, =false, =[]) -> state + sshKey(=2048, =false, =[], relindex=0) -> state ``` The _value_ field provides the fields: @@ -81,7 +81,7 @@ The _value_ field provides the fields: ## Generate a Random Secret with a dedicated Length ``` - secret(, , =false, =[]) -> string + secret(, , =false, =[], relindex=0) -> string ``` If no `default` (`~`) is given a random string consisting of alphanumeric @@ -92,7 +92,7 @@ The _value_ field directly contains the secret value. ## Generate a Wireguard Key Pair ``` - wireguardKey(=false, =[]) -> state + wireguardKey(=false, =[], relindex=0) -> state ``` The _value_ field provides the fields: @@ -107,7 +107,7 @@ is typically the state yaml. This is handled in the [state](../state/README.md) library. But this only works correctly if the state expression directly generates the state fields. -The optional relpath parameter can be used to adjust the stub access +The optional `relpath` parameter can be used to adjust the stub access (for accessing old state) in case of generating multiple state instances with `map`/`sum` generating implicit intermediate sub structures between the field containing the lambda expression and the generated state field. @@ -122,3 +122,7 @@ state: <<: (( &state(merge none) )) wireguard: (( map{names|m|-> utilities.certs.wireguardKey(false, [m])} )) ``` + +The optional `relindex` parameter is used together with the `relpath` parameter. +It specifies the relative location (from the end) where the relative path +should be inserted into the path. diff --git a/libraries/certs/certs.yaml b/libraries/certs/certs.yaml index 0c9522e..63a6b91 100644 --- a/libraries/certs/certs.yaml +++ b/libraries/certs/certs.yaml @@ -17,21 +17,21 @@ utilities: # offered fields in the value field: # key and pub # - wireguardKey: (( |update=false,relpath=[]|->utilities.state.data("",_.templates.wireguard_value,update,relpath) )) + wireguardKey: (( |update=false,relpath=[],relindex=0|->utilities.state.data("",_.templates.wireguard_value,update,relpath,relindex) )) # # generate a ssh key with the state library # offered fields in the value field: # key and pub # - sshKey: (( |size=2048,update=false,relpath=[]|->utilities.state.standard(_.sshKeySpec(size),update,relpath) )) + sshKey: (( |size=2048,update=false,relpath=[],relindex=0|->utilities.state.standard(_.sshKeySpec(size),update,relpath,relindex) )) # # generate a self signed CA with the state library # offered fields in the value field: # key, pub and cert # - selfSignedCA: (( |cn,update=false,relpath=[]|->_.keyCert(_.caSpec(cn),update,relpath) )) + selfSignedCA: (( |cn,update=false,relpath=[],relindex=0|->_.keyCert(_.caSpec(cn),update,relpath,relindex) )) # # generate a key and cert signed by the given ca. @@ -40,7 +40,7 @@ utilities: # offered fields in the value field: # key, pub and cert # - keyCertForCA: (( |certspec,ca,update=false,relpath=[]|->_.keyCert({$caCert=ca.value.cert, $caPrivateKey=ca.value.key} certspec,update,relpath) )) + keyCertForCA: (( |certspec,ca,update=false,relpath=[],relindex=0|->_.keyCert({$caCert=ca.value.cert, $caPrivateKey=ca.value.key} certspec,update,relpath,relindex) )) # # generate a certificate state for a given cert spec @@ -49,14 +49,14 @@ utilities: # offered fields in the value field: # key, pub and cert # - keyCert: (( |certspec,update=false,relpath=[]|->utilities.state.standard(_.keyCertSpec(certspec),update, relpath) )) + keyCert: (( |certspec,update=false,relpath=[],relindex=0|->utilities.state.standard(_.keyCertSpec(certspec),update, relpath, relindex) )) # # generate a secret value, if no default is given # the length parameter specifies the length of the generated secret. # - secret: (( |default,length,update=false,relpath=[]|->utilities.state.valuedata(default,_.templates.secret, update,relpath) )) + secret: (( |default,length,update=false,relpath=[],relindex=0|->utilities.state.valuedata(default,_.templates.secret, update,relpath,relindex) )) ####################### # helper funcions diff --git a/libraries/state/README.md b/libraries/state/README.md index 053ce87..1401342 100644 --- a/libraries/state/README.md +++ b/libraries/state/README.md @@ -135,6 +135,7 @@ A simplified certificate support can be found in the field. - _<update>_: bool: (optional) setting to true enforces a value update - _<relpath>_: []: (optional) additional path segments for state access +- _<relindex>_: 0: (optional) relative location (from the end) to insert the additional path segments It generates a state map with two fields: @@ -152,6 +153,7 @@ It generates a state map with two fields: from its value - _<update>_: bool: (optional) setting to true enforces a value update - _<relpath>_: []: (optional) additional path segments for state access +- _<relindex>_: 0: (optional) relative location (from the end) to insert the additional path segments ## Standard State Handling @@ -162,6 +164,7 @@ It generates a state map with two fields: - _<spec>_: map: structure containing the specification for this state value - _<update>_: bool: (optional) setting to true enforces a value update - _<relpath>_: []: (optional) additional path segments for state access +- _<relindex>_: 0: (optional) relative location (from the end) to insert the additional path segments This function is a wrapper for the one above. The _spec_ map must contain two fields: @@ -176,7 +179,7 @@ to access the same field containing the state lambda in the stub which is typically the state yaml. But this only works correctly if the state expression directly generates the state fields. -The optional relpath parameter can be used to adjust the stub access +The optional `relpath` parameter can be used to adjust the stub access (for accessing old state) in case of generating multiple state instances with `map`/`sum` generating implicit intermediate sub structures between the field containing the lambda expression and the generated state field. @@ -191,3 +194,6 @@ state: <<: (( &state(merge none) )) wireguard: (( map{names|m|-> utilities.certs.wireguardKey(false, [m])} )) ``` +The optional `relindex` parameter is used together with the `relpath` parameter. +It specifies the relative location (from the end) where the relative path +should be inserted into the path. diff --git a/libraries/state/state.yaml b/libraries/state/state.yaml index c7b134e..afa5025 100644 --- a/libraries/state/state.yaml +++ b/libraries/state/state.yaml @@ -33,6 +33,7 @@ # generate the state value using the state field # forceupdate: bool: setting to true encorces a value update # relpath: []: optional relative stub path +# relindex: 0: path index to insert relative path # # - utilities.state.valuedata(input,new,forceupdate=false) # @@ -43,6 +44,7 @@ # directly generate the state value # forceupdate: bool: setting to true encorces a value update # relpath: []: optional relative stub path +# relindex: 0: path index to insert relative path # # # - utilities.state.standard(spec,forceupdate=false) @@ -51,6 +53,7 @@ # for this state value # forceupdate: bool: setting to true encorces a value update # relpath: []: optional relative stub path +# relindex: 0: path index to insert relative path # # the _spec_ map must contain two fields: # input: any the input data used to generate the state @@ -59,13 +62,19 @@ # a template using the `input` binding to # generate the state value # +# +# - utilities.state.state(state) +# +# state: state ref: state value for given state ref utilities: <<: (( &inject &temporary(merge || ~) )) state: - valuedata: (( |input,new,update=false,relpath=[]|-> ($old=stub(__ctx.PATH relpath) || ~~) { $input=input, $value= ( !update -and old.input == input ? old.value :~) // type(new) == "template" ? (*new) :new } )) - data: (( |input,new,update=false,relpath=[]|-> ($old=stub(__ctx.PATH relpath) || ~~) { $input=input, $value= ( !update -and old.input == input ? old.value :~) // type(new) == "template" ? (*new).state :new } )) + adjustPath: (( |relpath,n|->($p=__ctx.PATH) p[..length(p) - n - 1] relpath p[length(p) - n..] )) + state: (( |state|-> state.value )) + valuedata: (( |input,new,update=false,relpath=[],relindex=0|-> ($path=_.adjustPath(relpath,relindex)) ($old=stub((path)) || ~~) { $input=input, $value= ( !update -and old.input == input ? old.value :~) // type(new) == "template" ? (*new) :new } )) + data: (( |input,new,update=false,relpath=[],relindex=0|-> ($path=_.adjustPath(relpath,relindex)) ($old=stub((path)) || ~~) { $input=input, $value= ( !update -and old.input == input ? old.value :~) // type(new) == "template" ? (*new).state :new } )) - standard: (( |data,update=false,relpath=[]|-> _.data(data.input, data.value,update) )) + standard: (( |data,update=false,relpath=[],relindex=0|-> _.data(data.input, data.value,update,relpath,relindex) )) diff --git a/spiffing/spiff.go b/spiffing/spiff.go index 19a6a4e..9442c56 100644 --- a/spiffing/spiff.go +++ b/spiffing/spiff.go @@ -5,12 +5,11 @@ package spiffing import ( - "os" - "github.com/mandelsoft/vfs/pkg/osfs" "github.com/mandelsoft/vfs/pkg/vfs" "github.com/mandelsoft/spiff/dynaml" + "github.com/mandelsoft/spiff/features" "github.com/mandelsoft/spiff/flow" "github.com/mandelsoft/spiff/yaml" ) @@ -62,12 +61,13 @@ func (s *sourceData) Data() ([]byte, error) { //////////////////////////////////////////////////////////////////////////////// type spiff struct { - key string - mode int - fs vfs.FileSystem - opts flow.Options - values map[string]yaml.Node - functions Functions + key string + mode int + fs vfs.FileSystem + opts flow.Options + values map[string]yaml.Node + functions Functions + interpolation bool binding dynaml.Binding } @@ -79,9 +79,12 @@ func NewFunctions() Functions { // New create a new default spiff context. func New() Spiff { + set := features.Features() + _, interpolation := set[features.INTERPOLATION] return &spiff{ - key: os.Getenv("SPIFF_ENCRYPTION_KEY"), - mode: MODE_DEFAULT, + key: features.EncryptionKey(), + mode: MODE_DEFAULT, + interpolation: interpolation, } } @@ -90,6 +93,13 @@ func (s *spiff) reset() Spiff { return s } +// WithInterpolation creates a new context with +// enabled/disabled string interpolation feature +func (s spiff) WithInterpolation(b bool) Spiff { + s.interpolation = b + return s.reset() +} + // WithEncryptionKey creates a new context with // dedicated encryption key used for the spiff encryption feature func (s spiff) WithEncryptionKey(key string) Spiff { @@ -160,7 +170,10 @@ func (s *spiff) FileSource(path string) Source { func (s *spiff) Cascade(template Node, stubs []Node, states ...Node) (Node, error) { if s.binding == nil { s.binding = flow.NewEnvironment( - nil, "context", flow.NewState(s.key, s.mode, s.fs).SetFunctions(s.functions)) + nil, "context", + flow.NewState(s.key, s.mode, s.fs). + SetFunctions(s.functions). + SetInterpolation(s.interpolation)) if s.values != nil { s.binding = s.binding.WithLocalScope(s.values) } diff --git a/vendor/github.com/mandelsoft/filepath/cmd/ojoin/example/version b/vendor/github.com/mandelsoft/filepath/cmd/ojoin/example/version deleted file mode 120000 index 28b45cd..0000000 --- a/vendor/github.com/mandelsoft/filepath/cmd/ojoin/example/version +++ /dev/null @@ -1 +0,0 @@ -versions/v1 \ No newline at end of file diff --git a/vendor/github.com/mandelsoft/filepath/cmd/osyml/example/src/versions/current b/vendor/github.com/mandelsoft/filepath/cmd/osyml/example/src/versions/current deleted file mode 120000 index 587c3e8..0000000 --- a/vendor/github.com/mandelsoft/filepath/cmd/osyml/example/src/versions/current +++ /dev/null @@ -1 +0,0 @@ -../../version \ No newline at end of file diff --git a/vendor/github.com/mandelsoft/filepath/cmd/osyml/example/src/versions/v1/modules/test b/vendor/github.com/mandelsoft/filepath/cmd/osyml/example/src/versions/v1/modules/test deleted file mode 120000 index 277a128..0000000 --- a/vendor/github.com/mandelsoft/filepath/cmd/osyml/example/src/versions/v1/modules/test +++ /dev/null @@ -1 +0,0 @@ -../../../pool/test \ No newline at end of file diff --git a/vendor/github.com/mandelsoft/filepath/cmd/osyml/example/version b/vendor/github.com/mandelsoft/filepath/cmd/osyml/example/version deleted file mode 120000 index 7fda260..0000000 --- a/vendor/github.com/mandelsoft/filepath/cmd/osyml/example/version +++ /dev/null @@ -1 +0,0 @@ -src/versions/v1 \ No newline at end of file diff --git a/vendor/github.com/mandelsoft/vfs/test/pkg b/vendor/github.com/mandelsoft/vfs/test/pkg deleted file mode 120000 index 4394270..0000000 --- a/vendor/github.com/mandelsoft/vfs/test/pkg +++ /dev/null @@ -1 +0,0 @@ -../pkg \ No newline at end of file diff --git a/vendor/github.com/mandelsoft/vfs/test/sub/d/sub b/vendor/github.com/mandelsoft/vfs/test/sub/d/sub deleted file mode 120000 index b1f01da..0000000 --- a/vendor/github.com/mandelsoft/vfs/test/sub/d/sub +++ /dev/null @@ -1 +0,0 @@ -../../sub \ No newline at end of file diff --git a/vendor/modules.txt b/vendor/modules.txt new file mode 100644 index 0000000..7337456 --- /dev/null +++ b/vendor/modules.txt @@ -0,0 +1,161 @@ +# github.com/cloudfoundry-incubator/candiedyaml v0.0.0-20170901234223-a41693b7b7af +## explicit +github.com/cloudfoundry-incubator/candiedyaml +# github.com/fsnotify/fsnotify v1.4.9 +github.com/fsnotify/fsnotify +# github.com/hashicorp/hcl v1.0.0 +github.com/hashicorp/hcl +github.com/hashicorp/hcl/hcl/ast +github.com/hashicorp/hcl/hcl/parser +github.com/hashicorp/hcl/hcl/printer +github.com/hashicorp/hcl/hcl/scanner +github.com/hashicorp/hcl/hcl/strconv +github.com/hashicorp/hcl/hcl/token +github.com/hashicorp/hcl/json/parser +github.com/hashicorp/hcl/json/scanner +github.com/hashicorp/hcl/json/token +# github.com/inconshreveable/mousetrap v1.0.0 +github.com/inconshreveable/mousetrap +# github.com/magiconair/properties v1.8.3 +## explicit +github.com/magiconair/properties +# github.com/mandelsoft/filepath v0.0.0-20200909114706-3df73d378d55 +github.com/mandelsoft/filepath/pkg/filepath +# github.com/mandelsoft/vfs v0.0.0-20201002080026-d03d33d5889a +## explicit +github.com/mandelsoft/vfs/pkg/osfs +github.com/mandelsoft/vfs/pkg/projectionfs +github.com/mandelsoft/vfs/pkg/utils +github.com/mandelsoft/vfs/pkg/vfs +# github.com/mitchellh/mapstructure v1.3.3 +## explicit +github.com/mitchellh/mapstructure +# github.com/nxadm/tail v1.4.4 +github.com/nxadm/tail +github.com/nxadm/tail/ratelimiter +github.com/nxadm/tail/util +github.com/nxadm/tail/watch +github.com/nxadm/tail/winfile +# github.com/onsi/ginkgo v1.14.1 +## explicit +github.com/onsi/ginkgo +github.com/onsi/ginkgo/config +github.com/onsi/ginkgo/internal/codelocation +github.com/onsi/ginkgo/internal/containernode +github.com/onsi/ginkgo/internal/failer +github.com/onsi/ginkgo/internal/global +github.com/onsi/ginkgo/internal/leafnodes +github.com/onsi/ginkgo/internal/remote +github.com/onsi/ginkgo/internal/spec +github.com/onsi/ginkgo/internal/spec_iterator +github.com/onsi/ginkgo/internal/specrunner +github.com/onsi/ginkgo/internal/suite +github.com/onsi/ginkgo/internal/testingtproxy +github.com/onsi/ginkgo/internal/writer +github.com/onsi/ginkgo/reporters +github.com/onsi/ginkgo/reporters/stenographer +github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable +github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty +github.com/onsi/ginkgo/types +# github.com/onsi/gomega v1.10.2 +## explicit +github.com/onsi/gomega +github.com/onsi/gomega/format +github.com/onsi/gomega/gbytes +github.com/onsi/gomega/gexec +github.com/onsi/gomega/internal/assertion +github.com/onsi/gomega/internal/asyncassertion +github.com/onsi/gomega/internal/oraclematcher +github.com/onsi/gomega/internal/testingtsupport +github.com/onsi/gomega/matchers +github.com/onsi/gomega/matchers/support/goraph/bipartitegraph +github.com/onsi/gomega/matchers/support/goraph/edge +github.com/onsi/gomega/matchers/support/goraph/node +github.com/onsi/gomega/matchers/support/goraph/util +github.com/onsi/gomega/types +# github.com/pelletier/go-toml v1.8.1 +## explicit +github.com/pelletier/go-toml +# github.com/pointlander/compress v1.1.0 +## explicit +github.com/pointlander/compress +# github.com/pointlander/jetset v1.0.0 +## explicit +github.com/pointlander/jetset +# github.com/pointlander/peg v0.0.0-20160608205303-1d0268dfff9b +## explicit +github.com/pointlander/peg +# github.com/spf13/afero v1.4.0 +## explicit +github.com/spf13/afero +github.com/spf13/afero/mem +# github.com/spf13/cast v1.3.1 +## explicit +github.com/spf13/cast +# github.com/spf13/cobra v0.0.7 +## explicit +github.com/spf13/cobra +# github.com/spf13/jwalterweatherman v1.1.0 +## explicit +github.com/spf13/jwalterweatherman +# github.com/spf13/pflag v1.0.5 +## explicit +github.com/spf13/pflag +# github.com/spf13/viper v1.7.1 +## explicit +github.com/spf13/viper +# github.com/subosito/gotenv v1.2.0 +github.com/subosito/gotenv +# golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a +## explicit +golang.org/x/crypto/bcrypt +golang.org/x/crypto/blowfish +golang.org/x/crypto/chacha20 +golang.org/x/crypto/curve25519 +golang.org/x/crypto/ed25519 +golang.org/x/crypto/ed25519/internal/edwards25519 +golang.org/x/crypto/internal/subtle +golang.org/x/crypto/md4 +golang.org/x/crypto/poly1305 +golang.org/x/crypto/ssh +golang.org/x/crypto/ssh/internal/bcrypt_pbkdf +# golang.org/x/net v0.0.0-20200904194848-62affa334b73 +## explicit +golang.org/x/net/html +golang.org/x/net/html/atom +golang.org/x/net/html/charset +# golang.org/x/sys v0.0.0-20200915084602-288bc346aa39 +## explicit +golang.org/x/sys/cpu +golang.org/x/sys/internal/unsafeheader +golang.org/x/sys/unix +# golang.org/x/text v0.3.3 +golang.org/x/text/encoding +golang.org/x/text/encoding/charmap +golang.org/x/text/encoding/htmlindex +golang.org/x/text/encoding/internal +golang.org/x/text/encoding/internal/identifier +golang.org/x/text/encoding/japanese +golang.org/x/text/encoding/korean +golang.org/x/text/encoding/simplifiedchinese +golang.org/x/text/encoding/traditionalchinese +golang.org/x/text/encoding/unicode +golang.org/x/text/internal/language +golang.org/x/text/internal/language/compact +golang.org/x/text/internal/tag +golang.org/x/text/internal/utf8internal +golang.org/x/text/language +golang.org/x/text/runes +golang.org/x/text/transform +golang.org/x/text/unicode/norm +# golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 +## explicit +golang.org/x/xerrors +golang.org/x/xerrors/internal +# gopkg.in/ini.v1 v1.61.0 +## explicit +gopkg.in/ini.v1 +# gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 +gopkg.in/tomb.v1 +# gopkg.in/yaml.v2 v2.3.0 +gopkg.in/yaml.v2 diff --git a/yaml/interpolation.go b/yaml/interpolation.go new file mode 100644 index 0000000..0647c7b --- /dev/null +++ b/yaml/interpolation.go @@ -0,0 +1,131 @@ +package yaml + +import ( + "encoding/json" + "strings" +) + +func StringToExpression(s string) string { + str, expr := convertToExpression(s, false) + if expr == nil { + return *str + } + return "(( " + *expr + " ))" +} + +func convertToExpression(s string, unescape bool) (*string, *string) { + mask := false + quote := false + start := false + ob := 0 + lvl := 0 + expr := "" + str := "" + result := "" + found := false + + for _, c := range s { + if start { + if quote { + // in quotes in expr + switch c { + case '"': + if !mask { + quote = false + } + mask = false + case '\\': + mask = !mask + default: + mask = false + } + expr = expr + string(c) + } else { + // in expr outside quotes + switch c { + case '(': + lvl++ + case ')': + if lvl > 0 { + lvl-- + } else { + ob++ + if ob == 2 { + start = false + ob = 0 + found = addExpr(&result, &str, &expr, false, unescape) || found + } + } + case '"': + quote = true + } + if start { + expr = expr + string(c) + } + if c != ')' { + ob = 0 + } + } + } else { + // regular string + switch c { + case '(': + ob++ + default: + if ob >= 2 { + start = true + str = str[:len(str)-2] + expr = string(c) + ob = 0 + } + } + if !start { + str = str + string(c) + if c != '(' { + ob = 0 + } + } + } + } + + if start { + str = str + "((" + expr + expr = "" + } + found = addExpr(&result, &str, &expr, true, unescape) || found + if found { + return nil, &result + } + return &str, nil +} + +func addExpr(result, str, expr *string, final, unescape bool) bool { + if unescape && strings.HasPrefix(*expr, "!") { + *str += "((" + (*expr)[1:] + ")" + *expr = "" + } + if strings.HasPrefix(*expr, "!") { + *str += "((" + *expr + ")" + *expr = "" + } + if *expr == "" && (*result == "" || !final) { + return false + } + if *str != "" { + r, _ := json.Marshal(*str) + if *result != "" { + *result += " " + } + *result = *result + string(r) + } + if *expr != "" { + *expr = strings.TrimSpace((*expr)[:len(*expr)-1]) + } + if *result != "" && *expr != "" { + *result += " " + } + *result += *expr + *expr = "" + *str = "" + return true +} diff --git a/yaml/interpolation_test.go b/yaml/interpolation_test.go new file mode 100644 index 0000000..81461df --- /dev/null +++ b/yaml/interpolation_test.go @@ -0,0 +1,101 @@ +package yaml + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func checkConvert(o, r string) { + c := StringToExpression(o) + Expect(c).To(Equal(r)) +} + +func checkUnescape(o, r string) { + str, expr := convertToExpression(o, true) + Expect(expr).To(BeNil()) + Expect(str).To(Not(BeNil())) + Expect(*str).To(Equal(r)) +} + +var _ = Describe("Convert String", func() { + + s := "\\(" + _ = s + Context("no substitution", func() { + It("handles regular string", func() { + checkConvert("test", "test") + }) + It("handles partial subst", func() { + checkConvert("test(", "test(") + checkConvert("test((", "test((") + checkConvert("((test)", "((test)") + checkConvert("xx((test)", "xx((test)") + checkConvert("xx((tes\"t))", "xx((tes\"t))") + }) + + Context("substitution", func() { + It("handles single", func() { + checkConvert("(( a + b ))", "(( a + b ))") + checkConvert("start (( a + b )) end", "(( \"start \" a + b \" end\" ))") + checkConvert("start (( a + b ))", "(( \"start \" a + b ))") + checkConvert("(( a + b )) end", "(( a + b \" end\" ))") + checkConvert(" (( a + b )) ", "(( \" \" a + b \" \" ))") + }) + It("handles multiple", func() { + checkConvert("start (( a )) middle (( b )) end", "(( \"start \" a \" middle \" b \" end\" ))") + }) + + It("handles brackets", func() { + checkConvert("a start ((( a ))) end", "(( \"a start (\" a \") end\" ))") + }) + + It("brackets in expression", func() { + checkConvert("a start (( ( b ( a )) )) end", "(( \"a start \" ( b ( a )) \" end\" ))") + checkConvert("a start ((( ( b ( a )) ))) end", "(( \"a start (\" ( b ( a )) \") end\" ))") + }) + + It("handles quotes", func() { + checkConvert("a start (( \"a\" b \"c\" )) end", "(( \"a start \" \"a\" b \"c\" \" end\" ))") + checkConvert("b start (( \"))\" b )) end", "(( \"b start \" \"))\" b \" end\" ))") + checkConvert("c start (( \"a(( x ))\" b )) end", "(( \"c start \" \"a(( x ))\" b \" end\" ))") + checkConvert("d start (( \"\\\"))\\\" \" b )) end", "(( \"d start \" \"\\\"))\\\" \" b \" end\" ))") + }) + + It("handles mask", func() { + checkConvert("a start \\(( a )) end", "(( \"a start \\\\\" a \" end\" ))") + checkConvert("b start (\\( a )) end", "b start (\\( a )) end") + + checkConvert("c start (( \"\\\"\" )) end", "(( \"c start \" \"\\\"\" \" end\" ))") + checkConvert("d start (( \\ )) end", "(( \"d start \" \\ \" end\" ))") + checkConvert("e start (( \\\\ )) end", "(( \"e start \" \\\\ \" end\" ))") + }) + + It("handles mask at end", func() { + checkConvert("a start (( a \\))) end", "(( \"a start \" a \\ \") end\" ))") + checkConvert("b start (( a \\\\))) end", "(( \"b start \" a \\\\ \") end\" ))") + }) + + It("escaped expr", func() { + checkConvert("a start ((! a \\))) end", "a start ((! a \\))) end") + }) + It("mixed escaped expr", func() { + checkConvert("a (( b )) start ((! a )) end", "(( \"a \" b \" start ((! a )) end\" ))") + }) + }) + }) + + Context("unescaping", func() { + It("unescapes simple expr", func() { + checkConvert("a start ((! a )) end", "a start ((! a )) end") + checkUnescape("b start ((! a )) end", "b start (( a )) end") + }) + It("unescapes double escaped expr", func() { + checkConvert("a start ((!! a )) end", "a start ((!! a )) end") + checkUnescape("b start ((!! a )) end", "b start ((! a )) end") + }) + It("handles incomplete expr", func() { + checkConvert("a start ((!! a ) end", "a start ((!! a ) end") + checkUnescape("b start ((!! a ) end", "b start ((!! a ) end") + }) + }) +}) diff --git a/yaml/node.go b/yaml/node.go index b2f09f0..84ae2fd 100644 --- a/yaml/node.go +++ b/yaml/node.go @@ -439,7 +439,7 @@ func (n AnnotatedNode) EquivalentToNode(o Node) bool { return b } -func EmbeddedDynaml(root Node) *string { +func EmbeddedDynaml(root Node, interpol bool) *string { rootString, ok := root.Value().(string) if !ok { return nil @@ -450,11 +450,16 @@ func EmbeddedDynaml(root Node) *string { if !strings.HasPrefix(sub, "!") { return &sub } + return nil + } + if !interpol { + return nil } - return nil + _, expr := convertToExpression(rootString, false) + return expr } -func UnescapeDynaml(root Node) Node { +func UnescapeDynaml(root Node, interpol bool) Node { if root.Value() == nil { return root } @@ -466,6 +471,13 @@ func UnescapeDynaml(root Node) Node { if strings.HasPrefix(sub, "!") { return NewNode("(("+sub[1:]+"))", root.SourceName()) } + return root + } + if interpol { + str, _ := convertToExpression(value, true) + if str != nil && *str != value { + return NewNode(*str, root.SourceName()) + } } case map[string]Node: new := map[string]Node{}