From 40c62216ec22aa5437d4239f488a63f993f60a3f Mon Sep 17 00:00:00 2001 From: Karan Sharma Date: Sun, 13 Dec 2020 17:49:10 +0530 Subject: [PATCH] feat: remove urfave/cli --- README.md | 2 + TODO.md | 13 +++-- cmd/cli.go | 151 ++++++++++++++++-------------------------------- cmd/help.go | 21 +++++++ cmd/hub.go | 39 ++++++------- cmd/lookup.go | 12 ++-- cmd/parse.go | 58 ++++++++++++------- cmd/resolver.go | 9 ++- go.mod | 7 ++- go.sum | 37 ++++++++---- 10 files changed, 176 insertions(+), 173 deletions(-) create mode 100644 cmd/help.go diff --git a/README.md b/README.md index 071b240..b745db4 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,5 @@ _Command-line DNS client written in Golang_ +# WIP + diff --git a/TODO.md b/TODO.md index 208c79d..d009dd7 100644 --- a/TODO.md +++ b/TODO.md @@ -10,6 +10,7 @@ - [x] Add DOH support - [x] Add DOT support - [x] Add DNS protocol on TCP mode support. +- [ ] Error on NXDomain (Realted upstream [bug](https://github.com/miekg/dns/issues/1198)) ## CLI Features - [ ] `digfile` @@ -18,6 +19,8 @@ - [x] JSON output - [x] Colorized output - [x] Table output +- [ ] Parsing options free-form +- [x] Remove urfave/cli in favour of `flag` ## CLI Grunt - [x] Query args @@ -31,8 +34,8 @@ ## Documentation ## Release Checklist -- [ ] Add packages to all package managers -- [ ] Snap -- [ ] Homebrew -- [ ] Alpine Linux -- [ ] ARM support too +- [ ] Goreleaser + - [ ] Snap + - [ ] Homebrew + - [ ] ARM + diff --git a/cmd/cli.go b/cmd/cli.go index 58673bc..7ba14fd 100644 --- a/cmd/cli.go +++ b/cmd/cli.go @@ -1,129 +1,76 @@ package main import ( + "fmt" "os" - "github.com/urfave/cli/v2" + "github.com/knadh/koanf" + "github.com/knadh/koanf/providers/posflag" + flag "github.com/spf13/pflag" ) var ( // Version and date of the build. This is injected at build-time. buildVersion = "unknown" buildDate = "unknown" + k = koanf.New(".") ) func main() { var ( logger = initLogger() - app = cli.NewApp() ) + // Initialize hub. hub := NewHub(logger, buildVersion) - // Configure CLI app. - app.Name = "doggo" - app.Usage = "Command-line DNS Client" - app.Version = buildVersion - - // Register command line flags. - app.Flags = []cli.Flag{ - &cli.StringSliceFlag{ - Name: "query", - Usage: "Domain name to query", - Destination: hub.QueryFlags.QNames, - }, - &cli.StringSliceFlag{ - Name: "type", - Usage: "Type of DNS record to be queried (A, AAAA, MX etc)", - Destination: hub.QueryFlags.QTypes, - }, - &cli.StringSliceFlag{ - Name: "nameserver", - Usage: "Address of the nameserver to send packets to", - Destination: hub.QueryFlags.Nameservers, - }, - &cli.StringSliceFlag{ - Name: "class", - Usage: "Network class of the DNS record to be queried (IN, CH, HS etc)", - Destination: hub.QueryFlags.QClasses, - }, - &cli.BoolFlag{ - Name: "udp", - Usage: "Use the DNS protocol over UDP", - Aliases: []string{"U"}, - }, - &cli.BoolFlag{ - Name: "tcp", - Usage: "Use the DNS protocol over TCP", - Aliases: []string{"T"}, - Destination: &hub.QueryFlags.UseTCP, - }, - &cli.BoolFlag{ - Name: "https", - Usage: "Use the DNS-over-HTTPS protocol", - Aliases: []string{"H"}, - Destination: &hub.QueryFlags.IsDOH, - }, - &cli.BoolFlag{ - Name: "tls", - Usage: "Use the DNS-over-TLS", - Aliases: []string{"S"}, - Destination: &hub.QueryFlags.IsDOT, - }, - &cli.BoolFlag{ - Name: "ipv6", - Aliases: []string{"6"}, - Usage: "Use IPv6 only", - Destination: &hub.QueryFlags.UseIPv6, - }, - &cli.BoolFlag{ - Name: "ipv4", - Aliases: []string{"4"}, - Usage: "Use IPv4 only", - Destination: &hub.QueryFlags.UseIPv4, - }, - &cli.BoolFlag{ - Name: "time", - Usage: "Display how long it took for the response to arrive", - Destination: &hub.QueryFlags.DisplayTimeTaken, - }, - &cli.BoolFlag{ - Name: "search", - Usage: "Use the search list provided in resolv.conf. It sets the `ndots` parameter as well unless overriden by `ndots` flag.", - Destination: &hub.QueryFlags.UseSearchList, - }, - &cli.IntFlag{ - Name: "ndots", - Usage: "Specify the ndots paramter", - DefaultText: "Default value is that set in `/etc/resolv.conf` or 1 if no `ndots` statement is present.", - Destination: &hub.QueryFlags.Ndots, - }, - &cli.BoolFlag{ - Name: "json", - Aliases: []string{"J"}, - Usage: "Set the output format as JSON", - Destination: &hub.QueryFlags.ShowJSON, - }, - &cli.BoolFlag{ - Name: "debug", - Usage: "Enable verbose logging", - Destination: &hub.QueryFlags.Verbose, - DefaultText: "false", - }, + // Configure Flags + // Use the POSIX compliant pflag lib instead of Go's flag lib. + f := flag.NewFlagSet("config", flag.ContinueOnError) + f.Usage = func() { + fmt.Println(f.FlagUsages()) + os.Exit(0) } - app.Before = hub.loadQueryArgs - app.Action = func(c *cli.Context) error { - if len(hub.QueryFlags.QNames.Value()) == 0 { - cli.ShowAppHelpAndExit(c, 0) - } - hub.Lookup(c) - return nil + // Path to one or more config files to load into koanf along with some config params. + f.StringSliceP("query", "q", []string{}, "Domain name to query") + f.StringSliceP("type", "t", []string{}, "Type of DNS record to be queried (A, AAAA, MX etc)") + f.StringSliceP("class", "c", []string{}, "Network class of the DNS record to be queried (IN, CH, HS etc)") + f.StringSliceP("nameservers", "n", []string{}, "Address of the nameserver to send packets to") + + // Protocol Options + f.BoolP("udp", "U", false, "Use the DNS protocol over UDP") + f.BoolP("tcp", "T", false, "Use the DNS protocol over TCP") + f.BoolP("doh", "H", false, "Use the DNS-over-HTTPS protocol") + f.BoolP("dot", "S", false, "Use the DNS-over-TLS") + + // Resolver Options + f.Bool("search", false, "Use the search list provided in resolv.conf. It sets the `ndots` parameter as well unless overriden by `ndots` flag.") + f.Int("ndots", 1, "Specify the ndots paramter") + + // Output Options + f.BoolP("json", "J", false, "Set the output format as JSON") + f.Bool("time", false, "Display how long it took for the response to arrive") + f.Bool("debug", false, "Enable debug mode") + + // Parse and Load Flags + f.Parse(os.Args[1:]) + if err := k.Load(posflag.Provider(f, ".", k), nil); err != nil { + hub.Logger.Fatalf("error loading flags: %v", err) + fmt.Println(f.FlagUsages()) + os.Exit(0) } // Run the app. hub.Logger.Debug("Starting doggo...") - err := app.Run(os.Args) - if err != nil { - logger.Errorf("oops! we encountered an issue: %s", err) + + // Parse Query Args + hub.loadQueryArgs() + + // Start App + if len(hub.QueryFlags.QNames) == 0 { + fmt.Println(f.FlagUsages()) + os.Exit(0) } + hub.Lookup() + } diff --git a/cmd/help.go b/cmd/help.go new file mode 100644 index 0000000..6d2b339 --- /dev/null +++ b/cmd/help.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + "io" +) + +// Override Help Template +var helpTmpl = `NAME: + {{.Name}} + {{ range $key, $value := . }} +
  • {{ $key }}: {{ $value }}
  • +{{ end }} +` + +func renderCustomHelp(w io.Writer, templ string, data interface{}) { + var helpTmplVars = map[string]string{} + + helpTmplVars["Name"] = "doggo" + fmt.Fprintf(w, helpTmpl, helpTmplVars) +} diff --git a/cmd/hub.go b/cmd/hub.go index 2afec56..ee91d4c 100644 --- a/cmd/hub.go +++ b/cmd/hub.go @@ -4,7 +4,6 @@ import ( "github.com/miekg/dns" "github.com/mr-karan/doggo/pkg/resolvers" "github.com/sirupsen/logrus" - "github.com/urfave/cli/v2" ) // Hub represents the structure for all app wide functions and structs. @@ -14,26 +13,24 @@ type Hub struct { QueryFlags QueryFlags Questions []dns.Question Resolver resolvers.Resolver - cliContext *cli.Context } // QueryFlags is used store the value of CLI flags. type QueryFlags struct { - QNames *cli.StringSlice - QTypes *cli.StringSlice - QClasses *cli.StringSlice - Nameservers *cli.StringSlice - IsDOH bool - IsDOT bool - IsUDP bool - UseTCP bool - UseIPv4 bool - UseIPv6 bool - DisplayTimeTaken bool - ShowJSON bool - Verbose bool - UseSearchList bool - Ndots int + QNames []string `koanf:"query"` + QTypes []string `koanf:"type"` + QClasses []string `koanf:"class"` + Nameservers []string `koanf:"namserver"` + IsDOH bool `koanf:"doh"` + IsDOT bool `koanf:"dot"` + IsUDP bool `koanf:"udp"` + UseTCP bool `koanf:"tcp"` + UseIPv4 bool `koanf:"ipv4"` + UseIPv6 bool `koanf:"ipv6"` + DisplayTimeTaken bool `koanf:"time"` + ShowJSON bool `koanf:"json"` + UseSearchList bool `koanf:"search"` + Ndots int `koanf:"ndots"` } // NewHub initializes an instance of Hub which holds app wide configuration. @@ -43,10 +40,10 @@ func NewHub(logger *logrus.Logger, buildVersion string) *Hub { Logger: logger, Version: buildVersion, QueryFlags: QueryFlags{ - QNames: cli.NewStringSlice(), - QTypes: cli.NewStringSlice(), - QClasses: cli.NewStringSlice(), - Nameservers: cli.NewStringSlice(), + QNames: []string{}, + QTypes: []string{}, + QClasses: []string{}, + Nameservers: []string{}, }, } return hub diff --git a/cmd/lookup.go b/cmd/lookup.go index e8ad87a..d8e6b3a 100644 --- a/cmd/lookup.go +++ b/cmd/lookup.go @@ -6,11 +6,10 @@ import ( "github.com/miekg/dns" "github.com/mr-karan/doggo/pkg/resolvers" "github.com/sirupsen/logrus" - "github.com/urfave/cli/v2" ) // Lookup sends the DNS queries to the server. -func (hub *Hub) Lookup(c *cli.Context) error { +func (hub *Hub) Lookup() error { err := hub.prepareQuestions() if err != nil { return err @@ -30,16 +29,17 @@ func (hub *Hub) prepareQuestions() error { var ( question dns.Question ) - for _, name := range hub.QueryFlags.QNames.Value() { + for _, name := range hub.QueryFlags.QNames { var ( domains []string ndots int ) + ndots = 1 // If `search` flag is specified then fetch the search list // from `resolv.conf` and set the if hub.QueryFlags.UseSearchList { - list, n, err := fetchDomainList(name, hub.cliContext.IsSet("ndots"), hub.QueryFlags.Ndots) + list, n, err := fetchDomainList(name, false, hub.QueryFlags.Ndots) if err != nil { return err } @@ -55,10 +55,10 @@ func (hub *Hub) prepareQuestions() error { }).Debug("Attmepting to resolve") question.Name = d // iterate on a list of query types. - for _, q := range hub.QueryFlags.QTypes.Value() { + for _, q := range hub.QueryFlags.QTypes { question.Qtype = dns.StringToType[strings.ToUpper(q)] // iterate on a list of query classes. - for _, c := range hub.QueryFlags.QClasses.Value() { + for _, c := range hub.QueryFlags.QClasses { question.Qclass = dns.StringToClass[strings.ToUpper(c)] // append a new question for each possible pair. hub.Questions = append(hub.Questions, question) diff --git a/cmd/parse.go b/cmd/parse.go index 66c4469..0961f93 100644 --- a/cmd/parse.go +++ b/cmd/parse.go @@ -1,32 +1,35 @@ package main import ( + "os" "strings" "github.com/miekg/dns" "github.com/sirupsen/logrus" - "github.com/urfave/cli/v2" ) -func (hub *Hub) loadQueryArgs(c *cli.Context) error { +func (hub *Hub) loadQueryArgs() error { // set log level - if c.Bool("debug") { + if k.Bool("debug") { // Set logger level hub.Logger.SetLevel(logrus.DebugLevel) } else { hub.Logger.SetLevel(logrus.InfoLevel) } - hub.cliContext = c - err := hub.loadFreeArgs(c) + err := hub.loadNamedArgs() + + err = hub.loadFreeArgs() if err != nil { - cli.Exit("Error parsing arguments", -1) + hub.Logger.WithError(err).Error("Error parsing arguments") + hub.Logger.Exit(2) } - err = hub.initResolver(c) + err = hub.initResolver() if err != nil { - cli.Exit("Error parsing nameservers", -1) + hub.Logger.WithError(err).Error("Error parsing nameservers") + hub.Logger.Exit(2) } - hub.loadFallbacks(c) + hub.loadFallbacks() return err } @@ -37,29 +40,44 @@ func (hub *Hub) loadQueryArgs(c *cli.Context) error { // pattern we deduce the arguments and map it to internal query // options. In case an argument isn't able to fit in any of the existing // pattern it is considered to be a "query name". -func (hub *Hub) loadFreeArgs(c *cli.Context) error { - for _, arg := range c.Args().Slice() { +func (hub *Hub) loadFreeArgs() error { + args := os.Args[1:] + for _, arg := range args { + if strings.HasPrefix(arg, "--") || strings.HasPrefix(arg, "-") { + continue + } if strings.HasPrefix(arg, "@") { - hub.QueryFlags.Nameservers.Set(strings.Trim(arg, "@")) + hub.QueryFlags.Nameservers = append(hub.QueryFlags.Nameservers, strings.Trim(arg, "@")) } else if _, ok := dns.StringToType[strings.ToUpper(arg)]; ok { - hub.QueryFlags.QTypes.Set(arg) + hub.QueryFlags.QTypes = append(hub.QueryFlags.QTypes, arg) } else if _, ok := dns.StringToClass[strings.ToUpper(arg)]; ok { - hub.QueryFlags.QClasses.Set(arg) + hub.QueryFlags.QClasses = append(hub.QueryFlags.QClasses, arg) } else { // if nothing matches, consider it's a query name. - hub.QueryFlags.QNames.Set(arg) + hub.QueryFlags.QNames = append(hub.QueryFlags.QNames, arg) } } return nil } +// loadNamedArgs checks for all flags and loads their +// values inside the Hub. +func (hub *Hub) loadNamedArgs() error { + // Unmarshall flags to the struct. + err := k.Unmarshal("", &hub.QueryFlags) + if err != nil { + return err + } + return nil +} + // loadFallbacks sets fallbacks for options // that are not specified by the user. -func (hub *Hub) loadFallbacks(c *cli.Context) { - if len(hub.QueryFlags.QTypes.Value()) == 0 { - hub.QueryFlags.QTypes.Set("A") +func (hub *Hub) loadFallbacks() { + if len(hub.QueryFlags.QTypes) == 0 { + hub.QueryFlags.QTypes = append(hub.QueryFlags.QTypes, "A") } - if len(hub.QueryFlags.QClasses.Value()) == 0 { - hub.QueryFlags.QClasses.Set("IN") + if len(hub.QueryFlags.QClasses) == 0 { + hub.QueryFlags.QClasses = append(hub.QueryFlags.QClasses, "IN") } } diff --git a/cmd/resolver.go b/cmd/resolver.go index 668719d..95c8e5a 100644 --- a/cmd/resolver.go +++ b/cmd/resolver.go @@ -4,22 +4,21 @@ import ( "runtime" "github.com/mr-karan/doggo/pkg/resolvers" - "github.com/urfave/cli/v2" ) // initResolver checks for various flags and initialises // the correct resolver based on the config. -func (hub *Hub) initResolver(c *cli.Context) error { +func (hub *Hub) initResolver() error { // check if DOH flag is set. if hub.QueryFlags.IsDOH { - rslvr, err := resolvers.NewDOHResolver(hub.QueryFlags.Nameservers.Value()) + rslvr, err := resolvers.NewDOHResolver(hub.QueryFlags.Nameservers) if err != nil { return err } hub.Resolver = rslvr return nil } - if len(hub.QueryFlags.Nameservers.Value()) == 0 { + if len(hub.QueryFlags.Nameservers) == 0 { if runtime.GOOS == "windows" { // TODO: Add a method for reading system default nameserver in windows. } else { @@ -31,7 +30,7 @@ func (hub *Hub) initResolver(c *cli.Context) error { return nil } } else { - rslvr, err := resolvers.NewClassicResolver(hub.QueryFlags.Nameservers.Value(), resolvers.ClassicResolverOpts{ + rslvr, err := resolvers.NewClassicResolver(hub.QueryFlags.Nameservers, resolvers.ClassicResolverOpts{ UseIPv4: hub.QueryFlags.UseIPv4, UseIPv6: hub.QueryFlags.UseIPv6, UseTLS: hub.QueryFlags.IsDOT, diff --git a/go.mod b/go.mod index 8ebc757..99f7171 100644 --- a/go.mod +++ b/go.mod @@ -4,10 +4,11 @@ go 1.15 require ( github.com/fatih/color v1.10.0 - github.com/mattn/go-runewidth v0.0.9 + github.com/knadh/koanf v0.14.0 + github.com/mattn/go-runewidth v0.0.9 // indirect github.com/miekg/dns v1.1.35 github.com/olekukonko/tablewriter v0.0.4 - github.com/rodaine/table v1.0.1 github.com/sirupsen/logrus v1.7.0 - github.com/urfave/cli/v2 v2.3.0 + github.com/spf13/pflag v1.0.5 + github.com/stretchr/testify v1.6.1 // indirect ) diff --git a/go.sum b/go.sum index 102c46b..176b344 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,19 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/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/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +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/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/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/knadh/koanf v0.14.0 h1:h9XeG4wEiEuxdxqv/SbY7TEK+7vzrg/dOaGB+S6+mPo= +github.com/knadh/koanf v0.14.0/go.mod h1:H5mEFsTeWizwFXHKtsITL5ipsLTuAMQoGuQpp+1JL9U= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= @@ -15,24 +23,25 @@ github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/Qd github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs= github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= +github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= 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/rodaine/table v1.0.1 h1:U/VwCnUxlVYxw8+NJiLIuCxA/xa6jL38MY3FYysVWWQ= -github.com/rodaine/table v1.0.1/go.mod h1:UVEtfBsflpeEcD56nF4F5AocNFta0ZuolpSVdPtlmP4= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/rhnvrm/simples3 v0.5.0/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= 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.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= -github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -47,14 +56,20 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=