From 20624eecd58899fbca9335947427654d8414f9a0 Mon Sep 17 00:00:00 2001 From: schmidtw Date: Sat, 23 Sep 2023 20:25:46 -0700 Subject: [PATCH 1/2] Update the configureation and main fx code. --- .gitignore | 2 + config.go | 72 ++++++++++++++++++++++++++++++- go.mod | 2 + go.sum | 7 +++ invalid.yml | 5 +++ main.go | 114 ++++++++++++++++-------------------------------- main_test.go | 120 ++++++++++++++++++++++++++++----------------------- 7 files changed, 192 insertions(+), 130 deletions(-) create mode 100644 invalid.yml diff --git a/.gitignore b/.gitignore index 058cad6..e5df055 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ go.work xmidt-agent internal/jwtxt/cmd/example/* + +*.dot diff --git a/config.go b/config.go index 0623709..735937a 100644 --- a/config.go +++ b/config.go @@ -3,9 +3,79 @@ package main -import "github.com/xmidt-org/sallust" +import ( + "fmt" + "os" + + "github.com/goschtalt/goschtalt" + "github.com/xmidt-org/sallust" + "gopkg.in/dealancer/validate.v2" +) type Config struct { SpecialValue string Logger sallust.Config } + +// Collect and process the configuration files and env vars and +// produce a configuration object. +func provideConfig(cli *CLI) (*goschtalt.Config, error) { + gs, err := goschtalt.New( + goschtalt.StdCfgLayout(applicationName, cli.Files...), + goschtalt.ConfigIs("two_words"), + goschtalt.DefaultUnmarshalOptions( + goschtalt.WithValidator( + goschtalt.ValidatorFunc(validate.Validate), + ), + ), + + // Seed the program with the default, built-in configuration. + // Mark this as a default so it is ordered correctly. + goschtalt.AddValue("built-in", goschtalt.Root, defaultConfig, + goschtalt.AsDefault()), + ) + if err != nil { + return nil, err + } + + if cli.Show { + // handleCLIShow handles the -s/--show option where the configuration is + // shown, then the program is exited. + // + // Exit with success because if the configuration is broken it will be + // very hard to debug where the problem originates. This way you can + // see the configuration and then run the service with the same + // configuration to see the error. + + fmt.Fprintln(os.Stdout, gs.Explain().String()) + + out, err := gs.Marshal() + if err != nil { + fmt.Fprintln(os.Stderr, err) + } else { + fmt.Fprintln(os.Stdout, "## Final Configuration\n---\n"+string(out)) + } + + os.Exit(0) + } + + var tmp Config + err = gs.Unmarshal(goschtalt.Root, &tmp) + if err != nil { + fmt.Fprintln(os.Stderr, "There is a critical error in the configuration.") + fmt.Fprintln(os.Stderr, "Run with -s/--show to see the configuration.") + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + + // Exit here to prevent a very difficult to debug error from occurring. + os.Exit(0) + } + + return gs, nil +} + +// ----------------------------------------------------------------------------- +// Keep the default configuration at the bottom of the file so it is easy to +// see what the default configuration is. +// ----------------------------------------------------------------------------- + +var defaultConfig = Config{} diff --git a/go.mod b/go.mod index 2708a94..c708734 100644 --- a/go.mod +++ b/go.mod @@ -15,12 +15,14 @@ require ( github.com/xmidt-org/wrp-go/v3 v3.2.0 go.uber.org/fx v1.20.0 go.uber.org/zap v1.26.0 + gopkg.in/dealancer/validate.v2 v2.1.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/uuid v1.3.1 // indirect github.com/goschtalt/approx v1.0.0 // indirect + github.com/leodido/go-urn v1.1.0 // indirect github.com/miekg/dns v1.1.25 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index 12ae694..7dcbf7e 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,7 @@ github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +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/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI= @@ -30,6 +31,8 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= +github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg= github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -40,6 +43,8 @@ github.com/psanford/memfs v0.0.0-20210214183328-a001468d78ef h1:NKxTG6GVGbfMXc2m github.com/psanford/memfs v0.0.0-20210214183328-a001468d78ef/go.mod h1:tcaRap0jS3eifrEEllL6ZMd9dg8IlDpi2S1oARrQ+NI= github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= @@ -86,6 +91,8 @@ gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/dealancer/validate.v2 v2.1.0 h1:XY95SZhVH1rBe8uwtnQEsOO79rv8GPwK+P3VWhQfJbA= +gopkg.in/dealancer/validate.v2 v2.1.0/go.mod h1:EipWMj8hVO2/dPXVlYRe9yKcgVd5OttpQDiM1/wZ0DE= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/invalid.yml b/invalid.yml new file mode 100644 index 0000000..27a16d8 --- /dev/null +++ b/invalid.yml @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: 2023 Comcast Cable Communications Management, LLC +# SPDX-License-Identifier: Apache-2.0 +--- +invalid: + invalid: invalid diff --git a/main.go b/main.go index b7ec70e..d8cba33 100644 --- a/main.go +++ b/main.go @@ -36,28 +36,28 @@ var ( type CLI struct { Dev bool `optional:"" short:"d" help:"Run in development mode."` Show bool `optional:"" short:"s" help:"Show the configuration and exit."` + Graph string `optional:"" short:"g" help:"Output the dependency graph to the specified file."` Files []string `optional:"" short:"f" help:"Specific configuration files or directories."` } -// xmidiAgent is the main entry point for the program. It is responsible for -// setting up the dependency injection framework and invoking the program. -func xmidtAgent(args []string) error { +// xmidtAgent is the main entry point for the program. It is responsible for +// setting up the dependency injection framework and returning the app object. +func xmidtAgent(args []string) (*fx.App, error) { var ( gscfg *goschtalt.Config - // Capture if the program is being run in dev mode so the extra stuff - // is output as requested. - dev devMode + // Capture the dependency tree in case we need to debug something. + g fx.DotGraph - // Capture if the program should gracefully exit early & without - // reporting an error via logging. - early earlyExit + // Capture the command line arguments. + cli *CLI ) app := fx.New( fx.Supply(cliArgs(args)), - fx.Supply(&early), - fx.Supply(&dev), + fx.Populate(&g), + fx.Populate(&gscfg), + fx.Populate(&cli), fx.WithLogger(func(log *zap.Logger) fxevent.Logger { return &fxevent.ZapLogger{Logger: log} @@ -66,54 +66,29 @@ func xmidtAgent(args []string) error { fx.Provide( provideCLI, provideLogger, - - // Collect and process the configuration files and env vars and - // produce a configuration object. - func(cli *CLI) (*goschtalt.Config, error) { - return goschtalt.New( - goschtalt.StdCfgLayout(applicationName, cli.Files...), - goschtalt.ConfigIs("two_words"), - - // Seed the program with the default, built-in configuration - goschtalt.AddValue("built-in", goschtalt.Root, - Config{ - SpecialValue: "default", - }, - goschtalt.AsDefault(), // Mark this as a default so it is ordered correctly - ), - ) - }, + provideConfig, goschtalt.UnmarshalFunc[sallust.Config]("logger", goschtalt.Optional()), ), - fx.Invoke( - handleCLIShow, - func(gs *goschtalt.Config) { - gscfg = gs - }, - ), + fx.Invoke(), ) - if dev { - defer func() { - fmt.Fprintln(os.Stderr, gscfg.Explain().String()) - }() + if cli != nil && cli.Graph != "" { + _ = os.WriteFile(cli.Graph, []byte(g), 0600) } - if err := app.Err(); err != nil || early { - return err + if err := app.Err(); err != nil { + return nil, err } - app.Run() - - return nil + return app, nil } func main() { - err := xmidtAgent(os.Args[1:]) - + app, err := xmidtAgent(os.Args[1:]) if err == nil { + app.Run() return } @@ -121,37 +96,28 @@ func main() { os.Exit(-1) } -// Provides a named type so it's a bit easier to flow through & use in fx. -type earlyExit bool - -// Provides a named type so it's a bit easier to flow through & use in fx. -type devMode bool - // Provides a named type so it's a bit easier to flow through & use in fx. type cliArgs []string -// handleCLIShow handles the -s/--show option where the configuration is shown, -// then the program is exited. -func handleCLIShow(cli *CLI, cfg *goschtalt.Config, early *earlyExit) { - if !cli.Show { - return - } +// Handle the CLI processing and return the processed input. +func provideCLI(args cliArgs) (*CLI, error) { + return provideCLIWithOpts(args, false) +} - fmt.Fprintln(os.Stdout, cfg.Explain().String()) +func provideCLIWithOpts(args cliArgs, testOpts bool) (*CLI, error) { + var cli CLI - out, err := cfg.Marshal() - if err != nil { - fmt.Fprintln(os.Stderr, err) - } else { - fmt.Fprintln(os.Stdout, "## Final Configuration\n---\n"+string(out)) - } + // Create a no-op option to satisfy the kong.New() call. + var opt kong.Option = kong.OptionFunc( + func(*kong.Kong) error { + return nil + }, + ) - *early = earlyExit(true) -} + if testOpts { + opt = kong.Writers(nil, nil) + } -// Handle the CLI processing and return the processed input. -func provideCLI(args cliArgs, dev *devMode, early *earlyExit) (*CLI, error) { - var cli CLI parser, err := kong.New(&cli, kong.Name(applicationName), kong.Description("The cpe agent for Xmidt service.\n"+ @@ -161,25 +127,21 @@ func provideCLI(args cliArgs, dev *devMode, early *earlyExit) (*CLI, error) { fmt.Sprintf("\tBuilt By: %s\n", builtBy), ), kong.UsageOnError(), + opt, ) if err != nil { return nil, err } - parser.Exit = func(i int) { - // Exit early on error, but we still need to return the CLI object - // otherwise fx will complain & hide the useful message we want to print. - *early = earlyExit(true) + if testOpts { + parser.Exit = func(_ int) { panic("exit") } } - fmt.Printf("parser: %p\n", parser) _, err = parser.Parse(args) if err != nil { parser.FatalIfErrorf(err) } - // Mark the devMode state so the collector can be output - *dev = devMode(cli.Dev) return &cli, nil } diff --git a/main_test.go b/main_test.go index b96aa74..b6f5295 100644 --- a/main_test.go +++ b/main_test.go @@ -4,9 +4,10 @@ package main import ( + "context" "testing" + "time" - "github.com/goschtalt/goschtalt" _ "github.com/goschtalt/goschtalt/pkg/typical" _ "github.com/goschtalt/yaml-decoder" _ "github.com/goschtalt/yaml-encoder" @@ -15,49 +16,12 @@ import ( "github.com/xmidt-org/sallust" ) -func Test_handleCLIShow(t *testing.T) { - gs, err := goschtalt.New() - require.NoError(t, err) - require.NotNil(t, gs) - - tests := []struct { - description string - cli *CLI - cfg *goschtalt.Config - expectEarly bool - }{ - { - description: "early exit", - cli: &CLI{ - Show: true, - }, - cfg: gs, - expectEarly: true, - }, { - description: "no early exit", - cli: &CLI{}, - cfg: gs, - }, - } - for _, tc := range tests { - t.Run(tc.description, func(t *testing.T) { - assert := assert.New(t) - - var early earlyExit - handleCLIShow(tc.cli, tc.cfg, &early) - - assert.Equal(tc.expectEarly, bool(early)) - }) - } -} - func Test_provideCLI(t *testing.T) { tests := []struct { description string args cliArgs - earlyExit bool - dev bool want CLI + exits bool expectedErr error }{ { @@ -65,31 +29,36 @@ func Test_provideCLI(t *testing.T) { }, { description: "dev mode", args: cliArgs{"-d"}, - dev: true, want: CLI{Dev: true}, }, { description: "invalid argument", args: cliArgs{"-w"}, - earlyExit: true, + exits: true, }, { description: "invalid argument", args: cliArgs{"-d", "-w"}, - earlyExit: true, + exits: true, + }, { + description: "help", + args: cliArgs{"-h"}, + exits: true, }, } for _, tc := range tests { t.Run(tc.description, func(t *testing.T) { assert := assert.New(t) - var devMode devMode - var earlyExit earlyExit - got, err := provideCLI(tc.args, &devMode, &earlyExit) + if tc.exits { + assert.Panics(func() { + _, _ = provideCLIWithOpts(tc.args, true) + }) + } else { + got, err := provideCLI(tc.args) - assert.ErrorIs(err, tc.expectedErr) - want := tc.want - assert.Equal(&want, got) - assert.Equal(tc.earlyExit, bool(earlyExit)) - assert.Equal(tc.dev, bool(devMode)) + assert.ErrorIs(err, tc.expectedErr) + want := tc.want + assert.Equal(&want, got) + } }) } } @@ -98,24 +67,69 @@ func Test_xmidtAgent(t *testing.T) { tests := []struct { description string args []string + duration time.Duration expectedErr error + panic bool }{ { description: "show config and exit", args: []string{"-s"}, - }, - { + panic: true, + }, { description: "show help and exit", args: []string{"-h"}, + panic: true, + }, { + description: "confirm invalid config file check works", + args: []string{"-f", "invalid.yml"}, + panic: true, + }, { + description: "enable debug mode", + args: []string{"-d"}, + }, { + description: "output graph", + args: []string{"-g", "graph.dot"}, + }, { + description: "start and stop", + duration: time.Millisecond, }, } for _, tc := range tests { t.Run(tc.description, func(t *testing.T) { assert := assert.New(t) + require := require.New(t) + + if tc.panic { + assert.Panics(func() { + _, _ = xmidtAgent(tc.args) + }) + return + } - err := xmidtAgent(tc.args) + app, err := xmidtAgent(tc.args) assert.ErrorIs(err, tc.expectedErr) + if tc.expectedErr != nil { + assert.Nil(app) + return + } + + if tc.duration <= 0 { + return + } + + // only run the program for a few seconds to make sure it starts + startCtx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + err = app.Start(startCtx) + require.NoError(err) + + time.Sleep(tc.duration) + + stopCtx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + err = app.Stop(stopCtx) + require.NoError(err) }) } } From f41b18c3066e430971c9c0a638e833e4ae285263 Mon Sep 17 00:00:00 2001 From: schmidtw Date: Sun, 24 Sep 2023 11:30:56 -0700 Subject: [PATCH 2/2] Update dependencies. --- go.mod | 11 ++++++----- go.sum | 27 ++++++++++++++++++++------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index c708734..1a05bd6 100644 --- a/go.mod +++ b/go.mod @@ -22,16 +22,17 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/uuid v1.3.1 // indirect github.com/goschtalt/approx v1.0.0 // indirect - github.com/leodido/go-urn v1.1.0 // indirect - github.com/miekg/dns v1.1.25 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/miekg/dns v1.1.56 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/ugorji/go/codec v1.2.11 // indirect go.uber.org/dig v1.17.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 // indirect - golang.org/x/net v0.0.0-20190923162816-aa69164e4478 // indirect - golang.org/x/sys v0.4.0 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.15.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/tools v0.13.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 7dcbf7e..5948c85 100644 --- a/go.sum +++ b/go.sum @@ -31,10 +31,12 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= -github.com/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= +github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -44,7 +46,12 @@ github.com/psanford/memfs v0.0.0-20210214183328-a001468d78ef/go.mod h1:tcaRap0jS github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= @@ -68,23 +75,28 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 h1:ACG4HJsFiNMf47Y4PeRoebLNy/2lXT9EtprMuTFWt1M= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM= gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU= @@ -95,5 +107,6 @@ gopkg.in/dealancer/validate.v2 v2.1.0 h1:XY95SZhVH1rBe8uwtnQEsOO79rv8GPwK+P3VWhQ gopkg.in/dealancer/validate.v2 v2.1.0/go.mod h1:EipWMj8hVO2/dPXVlYRe9yKcgVd5OttpQDiM1/wZ0DE= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=