Merge pull request #3282 from pwittrock/main

Fn framework utilities for parsing templates from directories
This commit is contained in:
Kubernetes Prow Robot
2020-11-30 08:42:50 -08:00
committed by GitHub
12 changed files with 598 additions and 117 deletions

View File

@@ -1,12 +0,0 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
FROM golang:1.13-stretch
ENV CGO_ENABLED=0
WORKDIR /go/src/
COPY . .
RUN go build -v -o /usr/local/bin/function ./
FROM alpine:latest
COPY --from=0 /usr/local/bin/function /usr/local/bin/function
CMD ["function"]

View File

@@ -1,7 +1,6 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: example.com/v1alpha1
kind: Example
key: key
value: value
env:
key: {{ .Key }}
value: {{ .Value }}

View File

@@ -0,0 +1,5 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
spec:
replicas: {{ .Replicas }}

View File

@@ -0,0 +1,14 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
namespace: bar
spec:
template:
spec:
containers:
- name: foo
image: {{ .Image }}

View File

@@ -0,0 +1,4 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package example2

View File

@@ -0,0 +1,241 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
//go:generate go run github.com/markbates/pkger/cmd/pkger -o fn/framework/example2
package example2
import (
"bytes"
"strings"
"testing"
"github.com/markbates/pkger"
"github.com/stretchr/testify/require"
"sigs.k8s.io/kustomize/kyaml/fn/framework"
)
func TestTemplate(t *testing.T) {
type API struct {
Image string `json:"image" yaml:"image"`
}
tpl, err := framework.TemplatesFromDir(pkger.Dir("/fn/framework/example2/data/templates"))(nil)
require.NoError(t, err)
cmd := framework.TemplateCommand{
API: &API{},
Templates: tpl,
}.GetCommand()
var in, out bytes.Buffer
cmd.SetIn(&in)
cmd.SetOut(&out)
in.WriteString(`
apiVersion: config.kubernetes.io/v1alpha1
kind: ResourceList
items:
- apiVersion: v1
kind: Service
functionConfig:
image: baz
`)
require.NoError(t, cmd.Execute())
require.Equal(t, strings.TrimSpace(`
apiVersion: config.kubernetes.io/v1alpha1
kind: ResourceList
items:
- apiVersion: v1
kind: Service
- apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
namespace: bar
annotations:
config.kubernetes.io/index: '0'
spec:
template:
spec:
containers:
- name: foo
image: baz
functionConfig:
image: baz
`), strings.TrimSpace(out.String()))
}
func TestPatchTemplate(t *testing.T) {
type API struct {
Replicas int `json:"replicas" yaml:"replicas"`
}
cmd := framework.TemplateCommand{
API: &API{},
PatchTemplatesFn: framework.PatchTemplatesFromDir(
framework.PT{
Dir: pkger.Dir("/fn/framework/example2/data/patches"),
Selector: func() *framework.Selector {
return &framework.Selector{Names: []string{"foo"}}
},
},
),
}.GetCommand()
var in, out bytes.Buffer
cmd.SetIn(&in)
cmd.SetOut(&out)
in.WriteString(`
apiVersion: config.kubernetes.io/v1alpha1
kind: ResourceList
items:
- apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
spec:
template:
spec:
containers:
- name: foo
image: baz
- apiVersion: apps/v1
kind: Deployment
metadata:
name: bar
spec:
template:
spec:
containers:
- name: foo
image: baz
functionConfig:
replicas: 5
`)
require.NoError(t, cmd.Execute())
require.Equal(t, strings.TrimSpace(`
apiVersion: config.kubernetes.io/v1alpha1
kind: ResourceList
items:
- apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
annotations:
config.kubernetes.io/index: '0'
spec:
template:
spec:
containers:
- name: foo
image: baz
replicas: 5
- apiVersion: apps/v1
kind: Deployment
metadata:
name: bar
spec:
template:
spec:
containers:
- name: foo
image: baz
functionConfig:
replicas: 5
`), strings.TrimSpace(out.String()))
}
func TestContainerPatchTemplate(t *testing.T) {
type API struct {
Key string `json:"key" yaml:"key"`
Value string `json:"value" yaml:"value"`
}
cmd := framework.TemplateCommand{
API: &API{},
PatchContainerTemplatesFn: framework.ContainerPatchTemplatesFromDir(
framework.CPT{
Dir: pkger.Dir("/fn/framework/example2/data/container-patches"),
Selector: func() *framework.Selector {
return &framework.Selector{Names: []string{"foo"}}
},
},
),
}.GetCommand()
var in, out bytes.Buffer
cmd.SetIn(&in)
cmd.SetOut(&out)
in.WriteString(`
apiVersion: config.kubernetes.io/v1alpha1
kind: ResourceList
items:
- apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
spec:
template:
spec:
containers:
- name: a
- name: b
- name: c
- apiVersion: apps/v1
kind: Deployment
metadata:
name: bar
spec:
template:
spec:
containers:
- name: foo
image: baz
functionConfig:
key: Hello
value: World
`)
require.NoError(t, cmd.Execute())
require.Equal(t, strings.TrimSpace(`
apiVersion: config.kubernetes.io/v1alpha1
kind: ResourceList
items:
- apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
spec:
template:
spec:
containers:
- name: a
env:
key: Hello
value: World
- name: b
env:
key: Hello
value: World
- name: c
env:
key: Hello
value: World
- apiVersion: apps/v1
kind: Deployment
metadata:
name: bar
spec:
template:
spec:
containers:
- name: foo
image: baz
functionConfig:
key: Hello
value: World
`), strings.TrimSpace(out.String()))
}

View File

@@ -1,35 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package main
import (
"fmt"
"os"
"text/template"
"sigs.k8s.io/kustomize/kyaml/fn/framework"
)
func main() {
type api struct {
Key string `json:"key" yaml:"key"`
Value string `json:"value" yaml:"value"`
}
cmd := framework.TemplateCommand{
API: &api{},
Template: template.Must(template.New("example").Parse(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
namespace: default
annotations:
{{ .Key }}: {{ .Value }}
`)),
}.GetCommand()
if err := cmd.Execute(); err != nil {
fmt.Fprintln(cmd.OutOrStderr(), err)
os.Exit(1)
}
}

View File

@@ -0,0 +1,15 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Code generated by pkger; DO NOT EDIT.
// +build !skippkger
package example2
import (
"github.com/markbates/pkger"
"github.com/markbates/pkger/pkging/mem"
)
var _ = pkger.Apply(mem.UnmarshalEmbed([]byte(`1f8b08000000000000ffec996d73a23a1b80ff0a93cfac10de02cc9c0fa53d52dbd5b6da8a7a66a71320626a200e606dedf8df9f01aaf6d9ed0b9e63bb333b8e1f20e14ec29d848b6bf009d064cc33603f818c4659636a660dcaa5e93ccb794c97449a3ee29815974f680a6c20dd6424cda4d982e679ca83a91471294b03e9bdc62268c5339ee697389f00fbdd7144d0c131013658174f78006c708983298e8850d60a014f724c934c60d44f714a49268c792aa404873489049c84c222a579717e3ef7499a909c644297647c9e06a4683ea6d13cc539e5898033a1e8b40144708dd388e46f24399b465288d3054d6e711c1ada7b193730104197f337fa022268e33c9800fb1fd0003f44d0cb3123c0ced339792e7409ce78026c90f05ca0499663c64828f8f35cc0f79832ec3322d044f0e79485428083090122707993329215fd863c6844bce8bc9afb0cd8c99c31119c90d9e6fc9a64f9a6cdb6eaa7166d1ece8bdb7b02b516b08d69b2cee5bfec1997b779f8ef5a4b116fc43c2c3be99334a3e554c206d4c16ab512c1b8caf8dd2d6f4be3441aa738260b9e4e25f280e319238a14e21c4bcf3b90a4df66c542569d150f52710c498e292bab926a33ff1a2e828c2e09b02d4304310f09b015a821cdd4a006cb9adb9c964d155991bf41f84d31aea16ccb9aad180d03299aa919a6f94d366d590622a0d96d584c7535ebd96339f809b907363410428a02cb652445d94448041d469329b05511b4120e6c8874d544c5cddcd010d8ba0c45e016678a2c826e5874248be01287b741c46f6560ff238be5ef87088e8a3bcd662428c6ec150768c8860655d33045d0c98a1ad5b42c8854d35889a0fd76bcb18edf64b812c1f18ef10e4df3499d3650d6a0a959d64a04bdcd62388c07d3ac4cd761d36a9134b9b8d26438aa2eb824298fdfb3194e49797af57c5acccb8f728f4d487aa0e6819a7f0a3545302bd3780297d3a8ee76dc0da12b111457d613583c5049be1d71db6d793b7b43f7b6a6919378c6704e1a6be7a981f49f1aadc10e156d4d76ad80e8c748d7151569fa2f481f63967dc0745585a6b9613a7cc974136a7b663a5af3d34286ac2364edc0f42ac5fa4cdfc4d7663a5234649aa6b2617ab90e6ba89bbf1bead2983efc0cf6edbeae2e56ec7e09d62d16b70cac9e9167043eef91ff67e04bb255d107a67d35d3de64cb8675a0f5e89cf8aaa307314bf0e955d4be3b7ab8e83937d8bd897a6a9f8e0667f3d1a0cb8247c709075deeab67cbef11bf6b353b57dd66945fbbec6ee4e9cb510f9e8ddcfe3c74598cbdfee305759cc06dde61f7266f536d711ccd989f0c8d637a1461a5af5f500791c7a3794fe9ebad536815f561dccc42efc6689de6a875ac7b43ef018e7a8e35befaeb2ff06944aea5d0fb1167289b4851556bdfe26cee19b22f2455438aa1cbb521bbceb02e645fc4ef20cea66c58967610e783381fc4f9ab5f325fabcbeb175979dc45905f6bb09163a8ee24c750b610429aba67394696f589726c982a44667d6e5729d6e7f6267e176e1b4835e0568e8b7538c8f1418ebf905baf92e4b7e8f03270fb7717118f5aa7672c701f6643a5b95c6bf14ddc5ff82ebb1b0edad178207fa2feae67e20301de86fd47058610225545fb556053963f53817564587a6d943e67581ba5dbf8fa2885b20ed18bef0c07053e28f04181bfe855b265e1d748f0663c292433c61f77f1e0575bac11ae68e66e220c95f22fab7d7f252e98fd59226ca282af4a7d7a2beb7fe56ad27b13bf03bd2154745dded0bb5c8783081f44f84be9f53a4d7e8b0b4f029779a3c1d9127bd6fc823a93e0d4597e57870fc7713ef3e32ba3f577b770e47be241e62757e7bed797875e7712ba7f979f94fdb8998fae79348aadfb4d79d0590cbd0ebba00e1d0e5ae781eab0e1929fb78e1d79e4c185ef36e5d175513e8a5aa79dc5c86b977d9565b773ef27dd09f67416242fea8fe55fc6aaea8f22ecc1c948d97cbe3ef3bd66527dbee61ffa7bf5d89283761db4eb4f01d7ea7f000000ffff010000ffff631c0417dc270000`)))

View File

@@ -283,6 +283,9 @@ type TemplateCommand struct {
// Templates is a list of templates to render.
Templates []*template.Template
// TemplatesFn returns a list of templates
TemplatesFn func(*ResourceList) ([]*template.Template, error)
// PatchTemplates is a list of templates to render into Patches and apply.
PatchTemplates []PatchTemplate
@@ -307,8 +310,12 @@ type TemplateCommand struct {
// PreProcess is run on the ResourceList before the template is invoked
PreProcess func(*ResourceList) error
PreProcessFilters []kio.Filter
// PostProcess is run on the ResourceList after the template is invoked
PostProcess func(*ResourceList) error
PostProcessFilters []kio.Filter
}
// ContainerPatchTemplate defines a patch to be applied to containers
@@ -353,6 +360,134 @@ func (tc TemplateCommand) doTemplate(t *template.Template, rl *ResourceList) err
return nil
}
// Defaulter is implemented by APIs to have Default invoked
type Defaulter interface {
Default() error
}
func (tc *TemplateCommand) doPreProcess(rl *ResourceList) error {
// do any preprocessing
if tc.PreProcess != nil {
if err := tc.PreProcess(rl); err != nil {
return err
}
}
// TODO: test this
if tc.PreProcessFilters != nil {
for i := range tc.PreProcessFilters {
fltr := tc.PreProcessFilters[i]
var err error
rl.Items, err = fltr.Filter(rl.Items)
if err != nil {
return err
}
}
}
return nil
}
func (tc *TemplateCommand) doMerge(rl *ResourceList) error {
var err error
if tc.MergeResources {
rl.Items, err = filters.MergeFilter{}.Filter(rl.Items)
}
return err
}
func (tc *TemplateCommand) doPostProcess(rl *ResourceList) error {
// finish up
if tc.PostProcess != nil {
if err := tc.PostProcess(rl); err != nil {
return err
}
}
// TODO: test this
if tc.PostProcessFilters != nil {
for i := range tc.PostProcessFilters {
fltr := tc.PostProcessFilters[i]
var err error
rl.Items, err = fltr.Filter(rl.Items)
if err != nil {
return err
}
}
}
return nil
}
func (tc *TemplateCommand) doTemplates(rl *ResourceList) error {
if tc.Template != nil {
tc.Templates = append(tc.Templates, tc.Template)
}
// TODO: test this
if tc.TemplatesFn != nil {
t, err := tc.TemplatesFn(rl)
if err != nil {
return err
}
tc.Templates = append(tc.Templates, t...)
}
for i := range tc.TemplatesFiles {
tbytes, err := ioutil.ReadFile(tc.TemplatesFiles[i])
if err != nil {
return errors.WrapPrefixf(err, "unable to read template file")
}
t, err := template.New("files").Parse(string(tbytes))
if err != nil {
return errors.WrapPrefixf(err, "unable to parse template files %v", tc.TemplatesFiles)
}
tc.Templates = append(tc.Templates, t)
}
for i := range tc.Templates {
if err := tc.doTemplate(tc.Templates[i], rl); err != nil {
return err
}
}
return nil
}
func (tc *TemplateCommand) doPatchTemplates(rl *ResourceList) error {
if tc.PatchTemplatesFn != nil {
pt, err := tc.PatchTemplatesFn(rl)
if err != nil {
return err
}
tc.PatchTemplates = append(tc.PatchTemplates, pt...)
}
for i := range tc.PatchTemplates {
if err := tc.PatchTemplates[i].Apply(rl); err != nil {
return err
}
}
return nil
}
func (tc *TemplateCommand) doPatchContainerTemplates(rl *ResourceList) error {
if tc.PatchContainerTemplatesFn != nil {
ct, err := tc.PatchContainerTemplatesFn(rl)
if err != nil {
return err
}
tc.PatchContainerTemplates = append(tc.PatchContainerTemplates, ct...)
}
for i := range tc.PatchContainerTemplates {
ct := tc.PatchContainerTemplates[i]
matches, err := ct.Selector.GetMatches(rl)
if err != nil {
return err
}
err = PatchContainersWithTemplate(matches, ct.Template, rl.FunctionConfig, ct.ContainerNames...)
if err != nil {
return err
}
}
return nil
}
// GetCommand returns a new cobra command
func (tc TemplateCommand) GetCommand() *cobra.Command {
rl := ResourceList{
@@ -360,81 +495,29 @@ func (tc TemplateCommand) GetCommand() *cobra.Command {
NoPrintError: true,
}
c := Command(&rl, func() error {
// do any preprocessing
if tc.PreProcess != nil {
if err := tc.PreProcess(&rl); err != nil {
if d, ok := rl.FunctionConfig.(Defaulter); ok {
if err := d.Default(); err != nil {
return err
}
}
if tc.Template != nil {
tc.Templates = append(tc.Templates, tc.Template)
if err := tc.doPreProcess(&rl); err != nil {
return err
}
for i := range tc.TemplatesFiles {
tbytes, err := ioutil.ReadFile(tc.TemplatesFiles[i])
if err != nil {
return errors.WrapPrefixf(err, "unable to read template file")
}
t, err := template.New("files").Parse(string(tbytes))
if err != nil {
return errors.WrapPrefixf(err, "unable to parse template files %v", tc.TemplatesFiles)
}
tc.Templates = append(tc.Templates, t)
if err := tc.doTemplates(&rl); err != nil {
return err
}
for i := range tc.Templates {
if err := tc.doTemplate(tc.Templates[i], &rl); err != nil {
return err
}
if err := tc.doPatchTemplates(&rl); err != nil {
return err
}
if tc.PatchTemplatesFn != nil {
pt, err := tc.PatchTemplatesFn(&rl)
if err != nil {
return err
}
tc.PatchTemplates = append(tc.PatchTemplates, pt...)
if err := tc.doPatchContainerTemplates(&rl); err != nil {
return err
}
for i := range tc.PatchTemplates {
if err := tc.PatchTemplates[i].Apply(&rl); err != nil {
return err
}
if err := tc.doMerge(&rl); err != nil {
return err
}
if tc.PatchContainerTemplatesFn != nil {
ct, err := tc.PatchContainerTemplatesFn(&rl)
if err != nil {
return err
}
tc.PatchContainerTemplates = append(tc.PatchContainerTemplates, ct...)
}
for i := range tc.PatchContainerTemplates {
ct := tc.PatchContainerTemplates[i]
matches, err := ct.Selector.GetMatches(&rl)
if err != nil {
return err
}
err = PatchContainersWithTemplate(matches, ct.Template, rl.FunctionConfig, ct.ContainerNames...)
if err != nil {
return err
}
}
var err error
if tc.MergeResources {
rl.Items, err = filters.MergeFilter{}.Filter(rl.Items)
if err != nil {
return err
}
}
// finish up
if tc.PostProcess != nil {
if err := tc.PostProcess(&rl); err != nil {
return err
}
if err := tc.doPostProcess(&rl); err != nil {
return err
}
return nil
@@ -482,3 +565,10 @@ func execute(rl *ResourceList, function Function, cmd *cobra.Command, args []str
return retErr
}
// Filters returns a function which returns the provided Filters
func Filters(fltrs ...kio.Filter) func(*ResourceList) []kio.Filter {
return func(*ResourceList) []kio.Filter {
return fltrs
}
}

154
kyaml/fn/framework/pkger.go Normal file
View File

@@ -0,0 +1,154 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package framework
import (
"io/ioutil"
"os"
"path"
"strings"
"text/template"
"github.com/markbates/pkger"
)
type TemplatesFn func(*ResourceList) ([]*template.Template, error)
// TemplatesFromDir applies a directory of templates as generated resources.
func TemplatesFromDir(dirs ...pkger.Dir) TemplatesFn {
return func(_ *ResourceList) ([]*template.Template, error) {
var pt []*template.Template
for i := range dirs {
d := dirs[i]
err := pkger.Walk(string(d), func(p string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !strings.HasSuffix(info.Name(), ".template.yaml") {
return nil
}
name := path.Join(string(d), info.Name())
f, err := pkger.Open(name)
if err != nil {
return err
}
b, err := ioutil.ReadAll(f)
if err != nil {
return err
}
t, err := template.New(info.Name()).Parse(string(b))
if err != nil {
return err
}
pt = append(pt, t)
return nil
})
if err != nil {
return nil, err
}
}
return pt, nil
}
}
// PatchTemplatesFn returns a slice of PatchTemplate
type PatchTemplatesFn func(*ResourceList) ([]PatchTemplate, error)
// PT applies a directory of patches using the Selector
type PT struct {
Selector func() *Selector
Dir pkger.Dir
}
// PatchTemplatesFromDir applies a directory of templates as patches.
func PatchTemplatesFromDir(templates ...PT) PatchTemplatesFn {
return func(*ResourceList) ([]PatchTemplate, error) {
var pt []PatchTemplate
for i := range templates {
v := templates[i]
err := pkger.Walk(string(v.Dir), func(p string, info os.FileInfo, err error) error {
if err != nil {
return err
}
name := path.Join(string(v.Dir), info.Name())
if !strings.HasSuffix(info.Name(), ".template.yaml") {
return nil
}
f, err := pkger.Open(name)
if err != nil {
return err
}
b, err := ioutil.ReadAll(f)
if err != nil {
return err
}
t, err := template.New(info.Name()).Parse(string(b))
if err != nil {
return err
}
pt = append(pt, PatchTemplate{Template: t, Selector: v.Selector()})
return nil
})
if err != nil {
return nil, err
}
}
return pt, nil
}
}
// ContainerPatchTemplateFn returns a slice of ContainerPatchTemplate
type ContainerPatchTemplateFn func(*ResourceList) ([]ContainerPatchTemplate, error)
// CPT applies a directory of container patches using the Selector
type CPT struct {
Selector func() *Selector
Dir pkger.Dir
Names []string
}
// ContainerPatchTemplatesFromDir applies a directory of templates as container patches.
func ContainerPatchTemplatesFromDir(templates ...CPT) ContainerPatchTemplateFn {
return func(*ResourceList) ([]ContainerPatchTemplate, error) {
var cpt []ContainerPatchTemplate
for i := range templates {
v := templates[i]
err := pkger.Walk(string(v.Dir), func(p string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !strings.HasSuffix(info.Name(), ".template.yaml") {
return nil
}
name := path.Join(string(v.Dir), info.Name())
f, err := pkger.Open(name)
if err != nil {
return err
}
b, err := ioutil.ReadAll(f)
if err != nil {
return err
}
t, err := template.New(info.Name()).Parse(string(b))
if err != nil {
return err
}
cpt = append(cpt, ContainerPatchTemplate{
PatchTemplate: PatchTemplate{Template: t, Selector: v.Selector()},
ContainerNames: v.Names,
})
return nil
})
if err != nil {
return nil, err
}
}
return cpt, nil
}
}

View File

@@ -8,6 +8,7 @@ require (
github.com/go-openapi/spec v0.19.5
github.com/go-openapi/strfmt v0.19.5
github.com/go-openapi/validate v0.19.8
github.com/markbates/pkger v0.17.1
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00
github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d
github.com/sergi/go-diff v1.1.0

View File

@@ -102,6 +102,8 @@ github.com/go-openapi/validate v0.19.8 h1:YFzsdWIDfVuLvIOF+ZmKjVg1MbPJ1QgY9PihMw
github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/here v0.6.0 h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI=
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
@@ -147,6 +149,8 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/markbates/pkger v0.17.1 h1:/MKEtWqtc0mZvu9OinB9UzVN9iYCwLWuyUv4Bw+PCno=
github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -288,6 +292,7 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
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.2.7/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=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo=