From 41c25b434bf90b52c880bfe488d2a97baadd0b1e Mon Sep 17 00:00:00 2001 From: Graham Clark Date: Sun, 5 Jun 2022 14:52:21 -0400 Subject: [PATCH 01/11] Make dark-mode the default Whenever users have expressed a preference, it's always been for dark-mode. It can be switched back with the console "set dark-mode off" command. --- CHANGELOG.md | 1 + cmd/termshark/termshark.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a78025d..5c9822f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ### Changed +- Dark-mode is now the default in the absence of a specific user-setting. - Fixed a bug that caused mouse-clicks within the hex view to not function correctly if the viewport was not at the top of the data to be displayed. - When focus is in the packet hex view, the mouse wheel will no longer move the cursor - instead it will move diff --git a/cmd/termshark/termshark.go b/cmd/termshark/termshark.go index 661a6a5..bd01ce2 100644 --- a/cmd/termshark/termshark.go +++ b/cmd/termshark/termshark.go @@ -732,7 +732,7 @@ func cmain() int { }() // Initialize application state for dark mode and auto-scroll - ui.DarkMode = termshark.ConfBool("main.dark-mode", false) + ui.DarkMode = termshark.ConfBool("main.dark-mode", true) ui.AutoScroll = termshark.ConfBool("main.auto-scroll", true) ui.PacketColors = termshark.ConfBool("main.packet-colors", true) From 0117c97a5556404b5f6602fd73d9c5ed579afe0c Mon Sep 17 00:00:00 2001 From: Graham Clark Date: Sun, 5 Jun 2022 18:55:10 -0400 Subject: [PATCH 02/11] Rearrange the config file handling code There is a new package called profiles and the config handling code is now there. Instead of using the viper default APIs, I'll now explicitly use a viper struct, and then I'll be able to use the same APIs to switch struct to "load" another profile. --- cmd/termshark/termshark.go | 58 ++++----- configs/profiles/profiles.go | 169 +++++++++++++++++++++++++++ shark/columnformat.go | 3 +- ui/convsui.go | 13 ++- ui/lastline.go | 27 ++--- ui/logsui.go | 3 +- ui/prochandlers.go | 7 +- ui/psmlcols.go | 10 +- ui/searchbyfilter.go | 5 +- ui/streamui.go | 7 +- ui/switchterm.go | 5 +- ui/ui.go | 39 ++++--- ui/wormhole.go | 8 +- utils.go | 135 +++++---------------- widgets/search/search.go | 19 +-- widgets/streamwidget/streamwidget.go | 7 +- 16 files changed, 306 insertions(+), 209 deletions(-) create mode 100644 configs/profiles/profiles.go diff --git a/cmd/termshark/termshark.go b/cmd/termshark/termshark.go index bd01ce2..1fd9ef7 100644 --- a/cmd/termshark/termshark.go +++ b/cmd/termshark/termshark.go @@ -21,6 +21,7 @@ import ( "github.com/gcla/termshark/v2" "github.com/gcla/termshark/v2/capinfo" "github.com/gcla/termshark/v2/cli" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/convs" "github.com/gcla/termshark/v2/pcap" "github.com/gcla/termshark/v2/shark" @@ -133,8 +134,6 @@ func cmain() int { // processes start running, they use the same tty line discipline. system.RegisterForSignals(sigChan) - viper.SetConfigName("termshark") // no need to include file extension - looks for file called termshark.ini for example - stdConf := configdir.New("", "termshark") dirs := stdConf.QueryFolders(configdir.Cache) if err := dirs[0].CreateParentDir("dummy"); err != nil { @@ -144,17 +143,10 @@ func cmain() int { if err := dirs[0].CreateParentDir("dummy"); err != nil { fmt.Fprintf(os.Stderr, "Warning: could not create config dir: %v\n", err) } - viper.AddConfigPath(dirs[0].Path) - - if f, err := os.OpenFile(filepath.Join(dirs[0].Path, "termshark.toml"), os.O_RDONLY|os.O_CREATE, 0666); err != nil { - fmt.Fprintf(os.Stderr, "Warning: could not create initial config file: %v\n", err) - } else { - f.Close() - } - err := viper.ReadInConfig() + err := profiles.ReadDefaultConfig(dirs[0].Path) if err != nil { - fmt.Println("Config file not found...") + fmt.Fprintf(os.Stderr, fmt.Sprintf("%s\n", err.Error())) } if os.Getenv("TERMSHARK_CAPTURE_MODE") == "1" { @@ -312,7 +304,7 @@ func cmain() int { // Allow the user to override the shell's TERM variable this way. Perhaps the user runs // under screen/tmux, and the TERM variable doesn't reflect the fact their preferred // terminal emumlator supports 256 colors. - termVar := termshark.ConfString("main.term", "") + termVar := profiles.ConfString("main.term", "") if termVar != "" { fmt.Fprintf(os.Stderr, "Configuration file overrides TERM setting, using TERM=%s\n", termVar) os.Setenv("TERM", termVar) @@ -533,7 +525,7 @@ func cmain() int { } debug := false - if (opts.Debug.Set && opts.Debug.Val == true) || (!opts.Debug.Set && termshark.ConfBool("main.debug", false)) { + if (opts.Debug.Set && opts.Debug.Val == true) || (!opts.Debug.Set && profiles.ConfBool("main.debug", false)) { debug = true } @@ -575,7 +567,7 @@ func cmain() int { // Here, tsharkBin is a fully-qualified tshark binary that exists on the fs (absent race // conditions...) - valids := termshark.ConfStrings("main.validated-tsharks") + valids := profiles.ConfStrings("main.validated-tsharks") if !termshark.StringInSlice(tsharkBin, valids) { tver, err := termshark.TSharkVersion(tsharkBin) @@ -592,24 +584,24 @@ func cmain() int { } valids = append(valids, tsharkBin) - termshark.SetConf("main.validated-tsharks", valids) + profiles.SetConf("main.validated-tsharks", valids) } // If the last tshark we used isn't the same as the current one, then remove the cached fields // data structure so it can be regenerated. - if tsharkBin != termshark.ConfString("main.last-used-tshark", "") { + if tsharkBin != profiles.ConfString("main.last-used-tshark", "") { termshark.DeleteCachedFields() } // Write out the last-used tshark path. We do this to make the above fields cache be consistent // with the tshark binary we're using. - termshark.SetConf("main.last-used-tshark", tsharkBin) + profiles.SetConf("main.last-used-tshark", tsharkBin) // Determine if the current binary supports color. Tshark will fail with an error if it's too old // and you supply the --color flag. Assume true, and check if our current binary is not in the // validate list. ui.PacketColorsSupported = true - colorTsharks := termshark.ConfStrings("main.color-tsharks") + colorTsharks := profiles.ConfStrings("main.color-tsharks") if !termshark.StringInSlice(tsharkBin, colorTsharks) { ui.PacketColorsSupported, err = termshark.TSharkSupportsColor(tsharkBin) @@ -617,7 +609,7 @@ func cmain() int { ui.PacketColorsSupported = false } else { colorTsharks = append(colorTsharks, tsharkBin) - termshark.SetConf("main.color-tsharks", colorTsharks) + profiles.SetConf("main.color-tsharks", colorTsharks) } } @@ -732,24 +724,24 @@ func cmain() int { }() // Initialize application state for dark mode and auto-scroll - ui.DarkMode = termshark.ConfBool("main.dark-mode", true) - ui.AutoScroll = termshark.ConfBool("main.auto-scroll", true) - ui.PacketColors = termshark.ConfBool("main.packet-colors", true) + ui.DarkMode = profiles.ConfBool("main.dark-mode", true) + ui.AutoScroll = profiles.ConfBool("main.auto-scroll", true) + ui.PacketColors = profiles.ConfBool("main.packet-colors", true) // Set them up here so they have access to any command-line flags that // need to be passed to the tshark commands used - pdmlArgs := termshark.ConfStringSlice("main.pdml-args", []string{}) - psmlArgs := termshark.ConfStringSlice("main.psml-args", []string{}) + pdmlArgs := profiles.ConfStringSlice("main.pdml-args", []string{}) + psmlArgs := profiles.ConfStringSlice("main.psml-args", []string{}) if opts.TimestampFormat != "" { psmlArgs = append(psmlArgs, "-t", opts.TimestampFormat) } - tsharkArgs := termshark.ConfStringSlice("main.tshark-args", []string{}) + tsharkArgs := profiles.ConfStringSlice("main.tshark-args", []string{}) if ui.PacketColors && !ui.PacketColorsSupported { log.Warnf("Packet coloring is enabled, but %s does not support --color", tsharkBin) ui.PacketColors = false } - cacheSize := termshark.ConfInt("main.pcap-cache-size", 64) - bundleSize := termshark.ConfInt("main.pcap-bundle-size", 1000) + cacheSize := profiles.ConfInt("main.pcap-cache-size", 64) + bundleSize := profiles.ConfInt("main.pcap-bundle-size", 1000) if bundleSize <= 0 { maxBundleSize := 100000 log.Infof("Config specifies pcap-bundle-size as %d - setting to max (%d)", bundleSize, maxBundleSize) @@ -795,8 +787,8 @@ func cmain() int { // 0-21 are set up normally, and not remapped. If the closest match is one of those // colors, then the theme won't look as expected. A workaround is to tell // gowid not to use colors 0-21 when finding the closest match. - if termshark.ConfKeyExists("main.ignore-base16-colors") { - gowid.IgnoreBase16 = termshark.ConfBool("main.ignore-base16-colors", false) + if profiles.ConfKeyExists("main.ignore-base16-colors") { + gowid.IgnoreBase16 = profiles.ConfBool("main.ignore-base16-colors", false) } else { // Try to auto-detect whether or not base16-shell is installed and in-use gowid.IgnoreBase16 = (os.Getenv("BASE16_SHELL") != "") @@ -810,7 +802,7 @@ func cmain() int { // just an implementation snafu, or if something else is going on... In any case, // termshark will fall back to 256-colors if base16 is detected because I can // programmatically avoid choosing colors 0-21 for anything termshark needs. - if os.Getenv("COLORTERM") != "" && !termshark.ConfBool("main.respect-colorterm", false) { + if os.Getenv("COLORTERM") != "" && !profiles.ConfBool("main.respect-colorterm", false) { log.Infof("Pessimistically disabling 24-bit color to avoid conflicts with base16") os.Unsetenv("COLORTERM") } @@ -1129,7 +1121,7 @@ Loop: case <-checkPcapCacheChan: // Only check the cache dir if we own it; don't want to delete pcap files // that might be shared with wireshark - if termshark.ConfBool("main.use-tshark-temp-for-pcap-cache", false) { + if profiles.ConfBool("main.use-tshark-temp-for-pcap-cache", false) { log.Infof("Termshark does not own the pcap temp dir %s; skipping size check", termshark.PcapDir()) } else { termshark.PrunePcapCache() @@ -1160,7 +1152,7 @@ Loop: // activated. mode := app.GetColorMode() modeStr := theme.Mode(mode) // more concise - themeName := termshark.ConfString(fmt.Sprintf("main.theme-%s", modeStr), "default") + themeName := profiles.ConfString(fmt.Sprintf("main.theme-%s", modeStr), "default") loaded := false if themeName != "" { err = theme.Load(themeName, app) @@ -1198,7 +1190,7 @@ Loop: // If exists is true, it means we already tried and then reverted back, so // just load up termshark normally with no further interruption. if _, exists := os.LookupEnv("TERMSHARK_ORIGINAL_TERM"); !exists { - if !termshark.ConfBool("main.disable-term-helper", false) { + if !profiles.ConfBool("main.disable-term-helper", false) { err = termshark.Does256ColorTermExist() if err != nil { log.Infof("Must use 8-color mode because 256-color version of TERM=%s unavailable - %v.", os.Getenv("TERM"), err) diff --git a/configs/profiles/profiles.go b/configs/profiles/profiles.go new file mode 100644 index 0000000..231e3f9 --- /dev/null +++ b/configs/profiles/profiles.go @@ -0,0 +1,169 @@ +// Copyright 2019-2022 Graham Clark. All rights reserved. Use of this source +// code is governed by the MIT license that can be found in the LICENSE +// file. + +package profiles + +import ( + "fmt" + "os" + "path/filepath" + "sync" + + "github.com/spf13/viper" +) + +//====================================================================== + +// The config is accessed by the main goroutine and pcap loading goroutines. So this +// is an attempt to prevent warnings with the -race flag (though they are very likely +// harmless) +var confMutex sync.Mutex + +// If this is non-nil, then the user has a profile loaded +var vProfile *viper.Viper +var vDefault *viper.Viper + +//====================================================================== + +func init() { + vDefault = viper.New() + vProfile = viper.New() +} + +//====================================================================== + +// First is error, second is warning +func ReadDefaultConfig(dir string) error { + return readConfig(vDefault, dir, "termshark") +} + +func readConfig(v *viper.Viper, dir string, base string) error { + confMutex.Lock() + defer confMutex.Unlock() + + var err error + + v.SetConfigName(base) // no need to include file extension - looks for file called termshark.ini for example + v.AddConfigPath(dir) + + fp := filepath.Join(dir, fmt.Sprintf("%s.toml", base)) + if f, err2 := os.OpenFile(fp, os.O_RDONLY|os.O_CREATE, 0666); err2 != nil { + err = fmt.Errorf("Warning: could not create initial config file: %w", err2) + } else { + f.Close() + } + + err = v.ReadInConfig() + if err != nil { + err = fmt.Errorf("Warning: config file %s not found...", fp) + } + + return err +} + +func ConfKeyExists(name string) bool { + return confKeyExists(vDefault, name) +} + +func confKeyExists(v *viper.Viper, name string) bool { + return v.Get(name) != nil +} + +func ConfString(name string, def string) string { + return confString(vDefault, name, def) +} + +func confString(v *viper.Viper, name string, def string) string { + confMutex.Lock() + defer confMutex.Unlock() + if v.Get(name) != nil { + return v.GetString(name) + } else { + return def + } +} + +func SetConf(name string, val interface{}) { + setConf(vDefault, name, val) +} + +func setConf(v *viper.Viper, name string, val interface{}) { + confMutex.Lock() + defer confMutex.Unlock() + v.Set(name, val) + v.WriteConfig() +} + +func ConfStrings(name string) []string { + return confStrings(vDefault, name) +} + +func confStrings(v *viper.Viper, name string) []string { + confMutex.Lock() + defer confMutex.Unlock() + return v.GetStringSlice(name) +} + +func DeleteConf(name string) { + deleteConf(vDefault, name) +} + +func deleteConf(v *viper.Viper, name string) { + confMutex.Lock() + defer confMutex.Unlock() + v.Set(name, "") + v.WriteConfig() +} + +func ConfInt(name string, def int) int { + return confInt(vDefault, name, def) +} + +func confInt(v *viper.Viper, name string, def int) int { + confMutex.Lock() + defer confMutex.Unlock() + if v.Get(name) != nil { + return v.GetInt(name) + } else { + return def + } +} + +func ConfBool(name string, def ...bool) bool { + return confBool(vDefault, name, def...) +} + +func confBool(v *viper.Viper, name string, def ...bool) bool { + confMutex.Lock() + defer confMutex.Unlock() + if v.Get(name) != nil { + return v.GetBool(name) + } else { + if len(def) > 0 { + return def[0] + } else { + return false + } + } +} + +func ConfStringSlice(name string, def []string) []string { + return confStringSlice(vDefault, name, def) +} + +func confStringSlice(v *viper.Viper, name string, def []string) []string { + confMutex.Lock() + defer confMutex.Unlock() + res := v.GetStringSlice(name) + if res == nil { + res = def + } + return res +} + +//====================================================================== +// Local Variables: +// mode: Go +// fill-column: 78 +// End: diff --git a/shark/columnformat.go b/shark/columnformat.go index 5fc772a..0ea68a1 100644 --- a/shark/columnformat.go +++ b/shark/columnformat.go @@ -15,6 +15,7 @@ import ( "github.com/gcla/gowid/widgets/table" "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus" ) @@ -295,7 +296,7 @@ func GetPsmlColumnFormatFrom(colKey string) []PsmlColumnSpec { func getPsmlColumnFormatWithoutLock(colKey string) []PsmlColumnSpec { res := make([]PsmlColumnSpec, 0) - widths := termshark.ConfStringSlice(colKey, []string{}) + widths := profiles.ConfStringSlice(colKey, []string{}) if len(widths) == 0 || (len(widths)/3)*3 != len(widths) { logrus.Warnf("Unexpected %s structure - using defaults", colKey) res = DefaultPsmlColumnSpec diff --git a/ui/convsui.go b/ui/convsui.go index 1ea943d..3f7f62e 100644 --- a/ui/convsui.go +++ b/ui/convsui.go @@ -31,6 +31,7 @@ import ( "github.com/gcla/gowid/widgets/text" "github.com/gcla/gowid/widgets/vpadding" "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/convs" "github.com/gcla/termshark/v2/pcap" "github.com/gcla/termshark/v2/psmlmodel" @@ -326,19 +327,19 @@ type ConvsUiWidget struct { } func (w *ConvsUiWidget) AbsoluteTime() bool { - return termshark.ConfBool("main.conv-absolute-time", false) + return profiles.ConfBool("main.conv-absolute-time", false) } func (w *ConvsUiWidget) SetAbsoluteTime(val bool) { - termshark.SetConf("main.conv-absolute-time", val) + profiles.SetConf("main.conv-absolute-time", val) } func (w *ConvsUiWidget) ResolveNames() bool { - return termshark.ConfBool("main.conv-resolve-names", false) + return profiles.ConfBool("main.conv-resolve-names", false) } func (w *ConvsUiWidget) SetResolveNames(val bool) { - termshark.SetConf("main.conv-resolve-names", val) + profiles.SetConf("main.conv-resolve-names", val) } func (w *ConvsUiWidget) Context() context.Context { @@ -350,11 +351,11 @@ func (w *ConvsUiWidget) FilterValue() string { } func (w *ConvsUiWidget) UseFilter() bool { - return termshark.ConfBool("main.conv-use-filter", false) + return profiles.ConfBool("main.conv-use-filter", false) } func (w *ConvsUiWidget) SetUseFilter(val bool) { - termshark.SetConf("main.conv-use-filter", val) + profiles.SetConf("main.conv-use-filter", val) } func (w *ConvsUiWidget) construct() { diff --git a/ui/lastline.go b/ui/lastline.go index 86b8af1..3e584c9 100644 --- a/ui/lastline.go +++ b/ui/lastline.go @@ -16,6 +16,7 @@ import ( "github.com/gcla/gowid/gwutil" "github.com/gcla/gowid/vim" "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/theme" "github.com/gcla/termshark/v2/widgets/mapkeys" "github.com/gcla/termshark/v2/widgets/minibuffer" @@ -184,7 +185,7 @@ func (s recentsArg) OfferCompletion() bool { func (s recentsArg) Completions() []string { matches := make([]string, 0) - cfiles := termshark.ConfStringSlice("main.recent-files", []string{}) + cfiles := profiles.ConfStringSlice("main.recent-files", []string{}) if cfiles != nil { for _, sc := range cfiles { scopy := sc @@ -212,7 +213,7 @@ func (s filterArg) OfferCompletion() bool { func (s filterArg) Completions() []string { matches := make([]string, 0) - cfiles := termshark.ConfStringSlice(s.field, []string{}) + cfiles := profiles.ConfStringSlice(s.field, []string{}) if cfiles != nil { for _, sc := range cfiles { scopy := sc @@ -325,33 +326,33 @@ func (d setCommand) Run(app gowid.IApp, args ...string) error { case "auto-scroll": if b, err = parseOnOff(args[2]); err == nil { AutoScroll = b - termshark.SetConf("main.auto-scroll", AutoScroll) + profiles.SetConf("main.auto-scroll", AutoScroll) OpenMessage(fmt.Sprintf("Packet auto-scroll is now %s", gwutil.If(b, "on", "off").(string)), appView, app) } case "copy-timeout": if i, err = strconv.ParseUint(args[2], 10, 32); err == nil { - termshark.SetConf("main.copy-command-timeout", i) + profiles.SetConf("main.copy-command-timeout", i) OpenMessage(fmt.Sprintf("Copy timeout is now %ds", i), appView, app) } case "dark-mode": if b, err = parseOnOff(args[2]); err == nil { DarkMode = b - termshark.SetConf("main.dark-mode", DarkMode) + profiles.SetConf("main.dark-mode", DarkMode) } case "disable-shark-fin": if b, err = strconv.ParseBool(args[2]); err == nil { - termshark.SetConf("main.disable-shark-fin", DarkMode) + profiles.SetConf("main.disable-shark-fin", DarkMode) OpenMessage(fmt.Sprintf("Shark-saver is now %s", gwutil.If(b, "off", "on").(string)), appView, app) } case "packet-colors": if b, err = parseOnOff(args[2]); err == nil { PacketColors = b - termshark.SetConf("main.packet-colors", PacketColors) + profiles.SetConf("main.packet-colors", PacketColors) OpenMessage(fmt.Sprintf("Packet colors are now %s", gwutil.If(b, "on", "off").(string)), appView, app) } case "suppress-tshark-errors": if b, err = parseOnOff(args[2]); err == nil { - termshark.SetConf("main.suppress-tshark-errors", b) + profiles.SetConf("main.suppress-tshark-errors", b) if b { OpenMessage("tshark errors will be suppressed.", appView, app) } else { @@ -360,11 +361,11 @@ func (d setCommand) Run(app gowid.IApp, args ...string) error { } case "term": if err = termshark.ValidateTerm(args[2]); err == nil { - termshark.SetConf("main.term", args[2]) + profiles.SetConf("main.term", args[2]) OpenMessage(fmt.Sprintf("Terminal type is now %s\n(Requires restart)", args[2]), appView, app) } case "pager": - termshark.SetConf("main.pager", args[2]) + profiles.SetConf("main.pager", args[2]) OpenMessage(fmt.Sprintf("Pager is now %s", args[2]), appView, app) default: err = invalidSetCommandErr @@ -372,10 +373,10 @@ func (d setCommand) Run(app gowid.IApp, args ...string) error { case 2: switch args[1] { case "noterm": - termshark.DeleteConf("main.term") + profiles.DeleteConf("main.term") OpenMessage("Terminal type is now unset\n(Requires restart)", appView, app) case "nopager": - termshark.DeleteConf("main.pager") + profiles.DeleteConf("main.pager") OpenMessage("Pager is now unset", appView, app) default: err = invalidSetCommandErr @@ -546,7 +547,7 @@ func (d themeCommand) Run(app gowid.IApp, args ...string) error { err = invalidThemeCommandErr } else { mode := theme.Mode(app.GetColorMode()).String() // more concise - termshark.SetConf(fmt.Sprintf("main.theme-%s", mode), args[1]) + profiles.SetConf(fmt.Sprintf("main.theme-%s", mode), args[1]) theme.Load(args[1], app) SetupColors() OpenMessage(fmt.Sprintf("Set %s theme for terminal mode %v.", args[1], app.GetColorMode()), appView, app) diff --git a/ui/logsui.go b/ui/logsui.go index 120c876..f2ec5e0 100644 --- a/ui/logsui.go +++ b/ui/logsui.go @@ -16,6 +16,7 @@ import ( "github.com/gcla/gowid/widgets/holder" "github.com/gcla/gowid/widgets/terminal" "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/widgets/fileviewer" log "github.com/sirupsen/logrus" "github.com/spf13/viper" @@ -24,7 +25,7 @@ import ( //====================================================================== func pager() string { - res := termshark.ConfString("main.pager", "") + res := profiles.ConfString("main.pager", "") if res == "" { res = os.Getenv("PAGER") } diff --git a/ui/prochandlers.go b/ui/prochandlers.go index a861b39..4dc53a5 100644 --- a/ui/prochandlers.go +++ b/ui/prochandlers.go @@ -14,6 +14,7 @@ import ( "github.com/gcla/gowid" "github.com/gcla/gowid/widgets/table" "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/pcap" log "github.com/sirupsen/logrus" ) @@ -120,7 +121,7 @@ func (t updatePacketViews) OnError(code pcap.HandlerCode, app gowid.IApp, err er fmt.Fprintf(os.Stderr, "%v\n", err) RequestQuit() } else { - if !termshark.ConfBool("main.suppress-tshark-errors", false) { + if !profiles.ConfBool("main.suppress-tshark-errors", false) { var errstr string if kverr, ok := err.(gowid.KeyValueError); ok { errstr = fmt.Sprintf("%v\n\n", kverr.Cause()) @@ -153,7 +154,7 @@ func (t SimpleErrors) OnError(code pcap.HandlerCode, app gowid.IApp, err error) log.Error(err) // Hack to avoid picking up errors at other parts of the load // cycle. There should be specific handlers for specific errors. - if !termshark.ConfBool("main.suppress-tshark-errors", false) { + if !profiles.ConfBool("main.suppress-tshark-errors", false) { app.Run(gowid.RunFunction(func(app gowid.IApp) { OpenError(fmt.Sprintf("%v", err), app) })) @@ -372,7 +373,7 @@ func (s SetStructWidgets) OnError(code pcap.HandlerCode, app gowid.IApp, err err // Hack to avoid picking up errors at other parts of the load // cycle. There should be specific handlers for specific errors. if s.Ld.PdmlLoader.IsLoading() { - if !termshark.ConfBool("main.suppress-tshark-errors", false) { + if !profiles.ConfBool("main.suppress-tshark-errors", false) { app.Run(gowid.RunFunction(func(app gowid.IApp) { OpenLongError(fmt.Sprintf("%v", err), app) })) diff --git a/ui/psmlcols.go b/ui/psmlcols.go index fce49c6..3b4de19 100644 --- a/ui/psmlcols.go +++ b/ui/psmlcols.go @@ -25,7 +25,7 @@ import ( "github.com/gcla/gowid/widgets/styled" "github.com/gcla/gowid/widgets/table" "github.com/gcla/gowid/widgets/text" - "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/shark" "github.com/gcla/termshark/v2/shark/wiresharkcfg" "github.com/gcla/termshark/v2/ui/menuutil" @@ -224,7 +224,7 @@ func openEditColumns(app gowid.IApp) { } } - bakCols := termshark.ConfStringSlice("main.column-format-bak", []string{}) + bakCols := profiles.ConfStringSlice("main.column-format-bak", []string{}) if len(bakCols) != 0 { btn := button.New(text.New("Restore")) btn.OnClick(gowid.MakeWidgetCallback("cb", func(app gowid.IApp, widget gowid.IWidget) { @@ -299,12 +299,12 @@ func openEditColumns(app gowid.IApp) { } newcols := pcols.ToConfigList() - curcols := termshark.ConfStringSlice("main.column-format", []string{}) + curcols := profiles.ConfStringSlice("main.column-format", []string{}) updated := false if !reflect.DeepEqual(newcols, curcols) { - termshark.SetConf("main.column-format-bak", curcols) - termshark.SetConf("main.column-format", newcols) + profiles.SetConf("main.column-format-bak", curcols) + profiles.SetConf("main.column-format", newcols) updated = true } diff --git a/ui/searchbyfilter.go b/ui/searchbyfilter.go index 0364496..f6a1567 100644 --- a/ui/searchbyfilter.go +++ b/ui/searchbyfilter.go @@ -18,6 +18,7 @@ import ( "github.com/gcla/gowid" "github.com/gcla/gowid/widgets/table" "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/format" "github.com/gcla/termshark/v2/pcap" "github.com/gcla/termshark/v2/widgets/search" @@ -384,8 +385,8 @@ func makePsmlCommand(filename string, displayFilter string) pcap.IPcapCommand { args = append(args, "-Y", displayFilter) } - psmlArgs := termshark.ConfStringSlice("main.psml-args", []string{}) - tsharkArgs := termshark.ConfStringSlice("main.tshark-args", []string{}) + psmlArgs := profiles.ConfStringSlice("main.psml-args", []string{}) + tsharkArgs := profiles.ConfStringSlice("main.tshark-args", []string{}) args = append(args, psmlArgs...) args = append(args, tsharkArgs...) diff --git a/ui/streamui.go b/ui/streamui.go index 5526476..f4516b6 100644 --- a/ui/streamui.go +++ b/ui/streamui.go @@ -19,6 +19,7 @@ import ( "github.com/gcla/gowid/widgets/null" "github.com/gcla/gowid/widgets/table" "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/pcap" "github.com/gcla/termshark/v2/pdmltree" "github.com/gcla/termshark/v2/streams" @@ -339,7 +340,7 @@ func (t *streamParseHandler) OnError(code pcap.HandlerCode, app gowid.IApp, err if !Running { fmt.Fprintf(os.Stderr, "%v\n", err) RequestQuit() - } else if !termshark.ConfBool("main.suppress-tshark-errors", false) { + } else if !profiles.ConfBool("main.suppress-tshark-errors", false) { var errstr string if kverr, ok := err.(gowid.KeyValueError); ok { errstr = fmt.Sprintf("%v\n\n", kverr.Cause()) @@ -359,7 +360,7 @@ func (t *streamParseHandler) OnError(code pcap.HandlerCode, app gowid.IApp, err } func initStreamWidgetCache() { - widgetCacheSize := termshark.ConfInt("main.stream-cache-size", 100) + widgetCacheSize := profiles.ConfInt("main.stream-cache-size", 100) var err error streamWidgets, err = lru.New(widgetCacheSize) @@ -441,7 +442,7 @@ func makeStreamWidget(previousFilter string, filter string, cap string, proto st MenuOpener: &multiMenu1Opener, DefaultDisplay: func() streamwidget.DisplayFormat { view := streamwidget.Hex - choice := termshark.ConfString("main.stream-view", "hex") + choice := profiles.ConfString("main.stream-view", "hex") switch choice { case "raw": view = streamwidget.Raw diff --git a/ui/switchterm.go b/ui/switchterm.go index 5dacd2e..ea5b223 100644 --- a/ui/switchterm.go +++ b/ui/switchterm.go @@ -16,6 +16,7 @@ import ( "github.com/gcla/gowid/widgets/holder" "github.com/gcla/gowid/widgets/paragraph" "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" ) //====================================================================== @@ -39,7 +40,7 @@ func SuggestSwitchingTerm(app gowid.IApp) { NoAsk := dialog.Button{ Msg: "No, don't ask", Action: gowid.MakeWidgetCallback("exec", gowid.WidgetChangedFunction(func(app gowid.IApp, w gowid.IWidget) { - termshark.SetConf("main.disable-term-helper", true) + profiles.SetConf("main.disable-term-helper", true) switchTerm.Close(app) })), } @@ -75,7 +76,7 @@ func IsTerminalLegible(app gowid.IApp) { YesSave := dialog.Button{ Msg: "Yes", Action: gowid.MakeWidgetCallback("exec", gowid.WidgetChangedFunction(func(app gowid.IApp, w gowid.IWidget) { - termshark.SetConf("main.term", os.Getenv("TERM")) + profiles.SetConf("main.term", os.Getenv("TERM")) saveTerm.Close(app) })), } diff --git a/ui/ui.go b/ui/ui.go index 187a01a..0547e33 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -46,6 +46,7 @@ import ( "github.com/gcla/gowid/widgets/tree" "github.com/gcla/gowid/widgets/vpadding" "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/pcap" "github.com/gcla/termshark/v2/pdmltree" "github.com/gcla/termshark/v2/psmlmodel" @@ -328,7 +329,7 @@ func columnNameFromShowname(showname string) string { } func useAsColumn(filter string, name string, app gowid.IApp) { - newCols := termshark.ConfStringSlice("main.column-format", []string{}) + newCols := profiles.ConfStringSlice("main.column-format", []string{}) colsBak := make([]string, len(newCols)) for i, col := range newCols { colsBak[i] = col @@ -340,8 +341,8 @@ func useAsColumn(filter string, name string, app gowid.IApp) { "true", ) - termshark.SetConf("main.column-format-bak", colsBak) - termshark.SetConf("main.column-format", newCols) + profiles.SetConf("main.column-format-bak", colsBak) + profiles.SetConf("main.column-format", newCols) RequestReload(app) } @@ -1222,7 +1223,7 @@ func openResultsAfterCopy(tmplName string, tocopy string, app gowid.IApp) { func processCopyChoices(copyLen int, app gowid.IApp) { var cc *dialog.Widget - copyCmd := termshark.ConfStringSlice( + copyCmd := profiles.ConfStringSlice( "main.copy-command", system.CopyToClipboard, ) @@ -1377,7 +1378,7 @@ func reallyQuit(app gowid.IApp) { // (a) Loader is in interface mode (b) User did not set -w flag // (c) always-keep-pcap setting is unset (def false) or false if Loader.InterfaceFile() != "" && !WriteToSelected && - !termshark.ConfBool("main.always-keep-pcap", false) { + !profiles.ConfBool("main.always-keep-pcap", false) { askToSave(app, func(app gowid.IApp) { RequestQuit() }) @@ -1415,7 +1416,7 @@ func lastLineMode(app gowid.IApp) { MiniBuffer.Register("no-theme", minibufferFn(func(app gowid.IApp, s ...string) error { mode := theme.Mode(app.GetColorMode()).String() // more concise - termshark.DeleteConf(fmt.Sprintf("main.theme-%s", mode)) + profiles.DeleteConf(fmt.Sprintf("main.theme-%s", mode)) theme.Load("default", app) SetupColors() OpenMessage(fmt.Sprintf("Cleared theme for terminal mode %v.", app.GetColorMode()), appView, app) @@ -2076,19 +2077,19 @@ func mainKeyPress(evk *tcell.EventKey, app gowid.IApp) bool { } else if isrune && evk.Rune() == '|' { if mainViewNoKeys.SubWidget() == mainview { mainViewNoKeys.SetSubWidget(altview1, app) - termshark.SetConf("main.layout", "altview1") + profiles.SetConf("main.layout", "altview1") } else if mainViewNoKeys.SubWidget() == altview1 { mainViewNoKeys.SetSubWidget(altview2, app) - termshark.SetConf("main.layout", "altview2") + profiles.SetConf("main.layout", "altview2") } else { mainViewNoKeys.SetSubWidget(mainview, app) - termshark.SetConf("main.layout", "mainview") + profiles.SetConf("main.layout", "mainview") } } else if isrune && evk.Rune() == '\\' { w := mainViewNoKeys.SubWidget() fp := gowid.FocusPath(w) if w == viewOnlyPacketList || w == viewOnlyPacketStructure || w == viewOnlyPacketHex { - switch termshark.ConfString("main.layout", "mainview") { + switch profiles.ConfString("main.layout", "mainview") { case "altview1": mainViewNoKeys.SetSubWidget(altview1, app) case "altview2": @@ -2505,7 +2506,7 @@ func ApplyAutoScroll(ev *tcell.EventKey, app gowid.IApp) bool { doit = true } if doit { - if termshark.ConfBool("main.auto-scroll", true) { + if profiles.ConfBool("main.auto-scroll", true) { AutoScroll = true reenableAutoScroll = true // when packet updates come, helps // understand that AutoScroll should not be disabled again @@ -2960,7 +2961,7 @@ func RequestLoadInterfaces(psrcs []pcap.IPacketSource, captureFilter string, dis // MaybeKeepThenRequestLoadPcap loads a pcap after first checking to see whether // the current load is a live load and the packets need to be kept. func MaybeKeepThenRequestLoadPcap(pcapf string, displayFilter string, jump termshark.GlobalJumpPos, app gowid.IApp) { - if Loader.InterfaceFile() != "" && !WriteToSelected && !termshark.ConfBool("main.always-keep-pcap", false) { + if Loader.InterfaceFile() != "" && !WriteToSelected && !profiles.ConfBool("main.always-keep-pcap", false) { askToSave(app, func(app gowid.IApp) { RequestLoadPcap(pcapf, displayFilter, jump, app) }) @@ -3085,7 +3086,7 @@ func progMax(x, y Prog) Prog { func makeRecentMenuWidget() (gowid.IWidget, int) { savedItems := make([]menuutil.SimpleMenuItem, 0) - cfiles := termshark.ConfStringSlice("main.recent-files", []string{}) + cfiles := profiles.ConfStringSlice("main.recent-files", []string{}) if cfiles != nil { for i, s := range cfiles { scopy := s @@ -3121,7 +3122,7 @@ var _ termshark.IPrefixCompleterCallback = (*savedCompleterCallback)(nil) func (s *savedCompleterCallback) Call(orig []string) { if s.prefix == "" { - comps := termshark.ConfStrings("main.recent-filters") + comps := profiles.ConfStrings("main.recent-filters") if len(comps) == 0 { comps = orig } @@ -3220,7 +3221,7 @@ func Build() (*gowid.App, error) { var err error var app *gowid.App - widgetCacheSize := termshark.ConfInt("main.ui-cache-size", 1000) + widgetCacheSize := profiles.ConfInt("main.ui-cache-size", 1000) if widgetCacheSize < 64 { widgetCacheSize = 64 } @@ -3345,7 +3346,7 @@ func Build() (*gowid.App, error) { CB: func(app gowid.IApp, w gowid.IWidget) { multiMenu1Opener.CloseMenu(generalMenu, app) DarkMode = !DarkMode - termshark.SetConf("main.dark-mode", DarkMode) + profiles.SetConf("main.dark-mode", DarkMode) }, }, menuutil.MakeMenuDivider(), @@ -3480,7 +3481,7 @@ func Build() (*gowid.App, error) { CB: func(app gowid.IApp, w gowid.IWidget) { multiMenu1Opener.CloseMenu(generalMenu, app) PacketColors = !PacketColors - termshark.SetConf("main.packet-colors", PacketColors) + profiles.SetConf("main.packet-colors", PacketColors) }, }, }, @@ -4122,7 +4123,7 @@ func Build() (*gowid.App, error) { altview2 = altview2OuterRows mainViewNoKeys = holder.New(mainview) - defaultLayout := termshark.ConfString("main.layout", "") + defaultLayout := profiles.ConfString("main.layout", "") switch defaultLayout { case "altview1": mainViewNoKeys = holder.New(altview1) @@ -4175,7 +4176,7 @@ func Build() (*gowid.App, error) { // For minibuffer mbView = holder.New(appViewWithKeys) - if !termshark.ConfBool("main.disable-shark-fin", false) { + if !profiles.ConfBool("main.disable-shark-fin", false) { Fin = rossshark.New(mbView) steerableFin := appkeys.NewMouse( diff --git a/ui/wormhole.go b/ui/wormhole.go index ca400f3..16a7012 100644 --- a/ui/wormhole.go +++ b/ui/wormhole.go @@ -11,7 +11,7 @@ import ( "github.com/gcla/gowid" "github.com/gcla/gowid/widgets/dialog" "github.com/gcla/gowid/widgets/framed" - "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/widgets/wormhole" log "github.com/sirupsen/logrus" ) @@ -24,7 +24,7 @@ func openWormhole(app gowid.IApp) { var numWords int if CurrentWormholeWidget == nil { - numWords = termshark.ConfInt("main.wormhole-length", 2) + numWords = profiles.ConfInt("main.wormhole-length", 2) } else { numWords = CurrentWormholeWidget.CodeLength() } @@ -38,8 +38,8 @@ func openWormhole(app gowid.IApp) { OpenError(msg, app) }, CodeLength: numWords, - TransitRelayAddress: termshark.ConfString("main.wormhole-transit-relay", ""), - RendezvousURL: termshark.ConfString("main.wormhole-rendezvous-url", ""), + TransitRelayAddress: profiles.ConfString("main.wormhole-transit-relay", ""), + RendezvousURL: profiles.ConfString("main.wormhole-rendezvous-url", ""), }) if err != nil { msg := fmt.Sprintf("%v", err) diff --git a/utils.go b/utils.go index 76571dd..f07ffe0 100644 --- a/utils.go +++ b/utils.go @@ -37,6 +37,7 @@ import ( "github.com/gcla/gowid/gwutil" "github.com/gcla/gowid/vim" "github.com/gcla/gowid/widgets/table" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/system" "github.com/gcla/termshark/v2/widgets/resizable" "github.com/gdamore/tcell/v2" @@ -46,7 +47,6 @@ import ( "github.com/pkg/errors" "github.com/shibukawa/configdir" log "github.com/sirupsen/logrus" - "github.com/spf13/viper" "github.com/tevino/abool" ) @@ -140,81 +140,6 @@ func ReverseStringSlice(s []string) { //====================================================================== -// The config is accessed by the main goroutine and pcap loading goroutines. So this -// is an attempt to prevent warnings with the -race flag (though they are very likely -// harmless) -var confMutex sync.Mutex - -func ConfKeyExists(name string) bool { - return viper.Get(name) != nil -} - -func ConfString(name string, def string) string { - confMutex.Lock() - defer confMutex.Unlock() - if viper.Get(name) != nil { - return viper.GetString(name) - } else { - return def - } -} - -func SetConf(name string, val interface{}) { - confMutex.Lock() - defer confMutex.Unlock() - viper.Set(name, val) - viper.WriteConfig() -} - -func ConfStrings(name string) []string { - confMutex.Lock() - defer confMutex.Unlock() - return viper.GetStringSlice(name) -} - -func DeleteConf(name string) { - confMutex.Lock() - defer confMutex.Unlock() - viper.Set(name, "") - viper.WriteConfig() -} - -func ConfInt(name string, def int) int { - confMutex.Lock() - defer confMutex.Unlock() - if viper.Get(name) != nil { - return viper.GetInt(name) - } else { - return def - } -} - -func ConfBool(name string, def ...bool) bool { - confMutex.Lock() - defer confMutex.Unlock() - if viper.Get(name) != nil { - return viper.GetBool(name) - } else { - if len(def) > 0 { - return def[0] - } else { - return false - } - } -} - -func ConfStringSlice(name string, def []string) []string { - confMutex.Lock() - defer confMutex.Unlock() - res := viper.GetStringSlice(name) - if res == nil { - res = def - } - return res -} - -//====================================================================== - var TSharkVersionUnknown = fmt.Errorf("Could not determine version of tshark") func TSharkVersionFromOutput(output string) (semver.Version, error) { @@ -254,7 +179,7 @@ func TSharkSupportsColor(tshark string) (bool, error) { // TSharkPath will return the full path of the tshark binary, if it's found in the path, otherwise an error func TSharkPath() (string, *gowid.KeyValueError) { - tsharkBin := ConfString("main.tshark", "") + tsharkBin := profiles.ConfString("main.tshark", "") if tsharkBin != "" { confirmedTshark := false if _, err := os.Stat(tsharkBin); err == nil { @@ -343,7 +268,7 @@ func CacheDir() string { func PcapDir() string { var res string // If use-tshark-temp-for-cache is set, use that - if ConfBool("main.use-tshark-temp-for-pcap-cache", false) { + if profiles.ConfBool("main.use-tshark-temp-for-pcap-cache", false) { tmp, err := TsharkSetting("Temp") if err == nil { res = tmp @@ -351,7 +276,7 @@ func PcapDir() string { } // Otherwise try the user's preference if res == "" { - res = ConfString("main.pcap-cache-dir", "") + res = profiles.ConfString("main.pcap-cache-dir", "") } if res == "" { res = DefaultPcapDir() @@ -366,15 +291,15 @@ func DefaultPcapDir() string { } func TSharkBin() string { - return ConfString("main.tshark", "tshark") + return profiles.ConfString("main.tshark", "tshark") } func DumpcapBin() string { - return ConfString("main.dumpcap", "dumpcap") + return profiles.ConfString("main.dumpcap", "dumpcap") } func CapinfosBin() string { - return ConfString("main.capinfos", "capinfos") + return profiles.ConfString("main.capinfos", "capinfos") } // CaptureBin is the binary the user intends to use to capture @@ -391,9 +316,9 @@ func CapinfosBin() string { // it switches to capture mode. func CaptureBin() string { if runtime.GOOS == "windows" { - return ConfString("main.capture-command", DumpcapBin()) + return profiles.ConfString("main.capture-command", DumpcapBin()) } else { - return ConfString("main.capture-command", os.Args[0]) + return profiles.ConfString("main.capture-command", os.Args[0]) } } @@ -420,7 +345,7 @@ func TailCommand() []string { if runtime.GOOS == "windows" { def = []string{os.Args[0], "--tail"} } - return ConfStringSlice("main.tail-command", def) + return profiles.ConfStringSlice("main.tail-command", def) } func KeyPressIsPrintable(key gowid.IKey) bool { @@ -456,7 +381,7 @@ func RemoveKeyMapping(kp vim.KeyPress) { } func LoadKeyMappings() []KeyMapping { - mappings := ConfStringSlice("main.key-mappings", []string{}) + mappings := profiles.ConfStringSlice("main.key-mappings", []string{}) res := make([]KeyMapping, 0) for _, mapping := range mappings { pair := strings.Split(mapping, " ") @@ -484,7 +409,7 @@ func SaveKeyMappings(mappings []KeyMapping) { for _, mapping := range mappings { ser = append(ser, fmt.Sprintf("%v %v", mapping.From, vim.KeySequence(mapping.To))) } - SetConf("main.key-mappings", ser) + profiles.SetConf("main.key-mappings", ser) } func RemoveFromStringSlice(pcap string, comps []string) []string { @@ -664,12 +589,12 @@ func SafePid(p IProcess) int { } func SetConvTypes(convs []string) { - SetConf("main.conv-types", convs) + profiles.SetConf("main.conv-types", convs) } func ConvTypes() []string { defs := []string{"eth", "ip", "ipv6", "tcp", "udp"} - ctypes := ConfStrings("main.conv-types") + ctypes := profiles.ConfStrings("main.conv-types") if len(ctypes) > 0 { z, ok := arrayOperations.Intersect(defs, ctypes) if ok { @@ -683,13 +608,13 @@ func ConvTypes() []string { } func AddToRecentFiles(pcap string) { - comps := ConfStrings("main.recent-files") + comps := profiles.ConfStrings("main.recent-files") if len(comps) == 0 || comps[0] != pcap { comps = RemoveFromStringSlice(pcap, comps) if len(comps) > 16 { comps = comps[0 : 16-1] } - SetConf("main.recent-files", comps) + profiles.SetConf("main.recent-files", comps) } } @@ -698,18 +623,18 @@ func AddToRecentFilters(val string) { } func addToRecent(field string, val string) { - comps := ConfStrings(field) + comps := profiles.ConfStrings(field) if (len(comps) == 0 || comps[0] != val) && strings.TrimSpace(val) != "" { comps = RemoveFromStringSlice(val, comps) if len(comps) > 64 { comps = comps[0 : 64-1] } - SetConf(field, comps) + profiles.SetConf(field, comps) } } func LoadOffsetFromConfig(name string) ([]resizable.Offset, error) { - offsStr := ConfString("main."+name, "") + offsStr := profiles.ConfString("main."+name, "") if offsStr == "" { return nil, errors.WithStack(gowid.WithKVs(ConfigErr, map[string]interface{}{ "name": name, @@ -735,16 +660,16 @@ func SaveOffsetToConfig(name string, offsets2 []resizable.Offset) { } } if len(offsets) == 0 { - DeleteConf("main." + name) + profiles.DeleteConf("main." + name) } else { offs, err := json.Marshal(offsets) if err != nil { log.Fatal(err) } - SetConf("main."+name, string(offs)) + profiles.SetConf("main."+name, string(offs)) } // Hack to make viper save if I only deleted from the map - SetConf("main.lastupdate", time.Now().String()) + profiles.SetConf("main.lastupdate", time.Now().String()) } //====================================================================== @@ -771,7 +696,7 @@ type globalJumpPosMapping struct { } func LoadGlobalMarks(m map[rune]GlobalJumpPos) error { - marksStr := ConfString("main.marks", "") + marksStr := profiles.ConfString("main.marks", "") if marksStr == "" { return nil } @@ -798,16 +723,16 @@ func SaveGlobalMarks(m map[rune]GlobalJumpPos) { marks = append(marks, globalJumpPosMapping{Key: k, GlobalJumpPos: v}) } if len(marks) == 0 { - DeleteConf("main.marks") + profiles.DeleteConf("main.marks") } else { marksJ, err := json.Marshal(marks) if err != nil { log.Fatal(err) } - SetConf("main.marks", string(marksJ)) + profiles.SetConf("main.marks", string(marksJ)) } // Hack to make viper save if I only deleted from the map - SetConf("main.lastupdate", time.Now().String()) + profiles.SetConf("main.lastupdate", time.Now().String()) } //====================================================================== @@ -922,7 +847,7 @@ func PrunePcapCache() error { // assume the cache can grow indefinitely - in case users are now relying on this // to keep old pcaps around. I don't want to delete any files without the user's // explicit permission. - var diskCacheSize int64 = int64(ConfInt("main.disk-cache-size-mb", -1)) + var diskCacheSize int64 = int64(profiles.ConfInt("main.disk-cache-size-mb", -1)) if diskCacheSize == -1 { log.Infof("No pcap disk cache size set. Skipping cache pruning.") @@ -1245,7 +1170,7 @@ func ApplyArguments(cmd []string, args []string) ([]string, int) { } func BrowseUrl(url string) error { - urlCmd := ConfStringSlice( + urlCmd := profiles.ConfStringSlice( "main.browse-command", system.OpenURL, ) @@ -1304,7 +1229,7 @@ type ICommandWaitTicker interface { func CopyCommand(input io.Reader, cb interface{}) error { var err error - copyCmd := ConfStringSlice( + copyCmd := profiles.ConfStringSlice( "main.copy-command", system.CopyToClipboard, ) @@ -1318,7 +1243,7 @@ func CopyCommand(input io.Reader, cb interface{}) error { outBuf := bytes.Buffer{} cmd.Stdout = &outBuf - cmdTimeout := ConfInt("main.copy-command-timeout", 5) + cmdTimeout := profiles.ConfInt("main.copy-command-timeout", 5) if err := cmd.Start(); err != nil { return errors.WithStack(gowid.WithKVs(BadCommand, map[string]interface{}{"err": err})) } diff --git a/widgets/search/search.go b/widgets/search/search.go index 512eeef..b909613 100644 --- a/widgets/search/search.go +++ b/widgets/search/search.go @@ -27,6 +27,7 @@ import ( "github.com/gcla/gowid/widgets/styled" "github.com/gcla/gowid/widgets/text" "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/ui/menuutil" "github.com/gcla/termshark/v2/widgets/filter" "github.com/gcla/termshark/v2/widgets/ifwidget" @@ -298,7 +299,7 @@ func units(n int) gowid.RenderWithUnits { } func getSearchType() string { - res := termshark.ConfString("main.search-type", "filter") + res := profiles.ConfString("main.search-type", "filter") if _, ok := searchTypeMap[res]; !ok { res = "filter" } @@ -306,7 +307,7 @@ func getSearchType() string { } func getSearchTarget() string { - res := termshark.ConfString("main.search-target", "list") + res := profiles.ConfString("main.search-target", "list") if _, ok := searchTargetMap[res]; !ok { res = "list" } @@ -583,11 +584,11 @@ func (w *Widget) Value() string { } func (w *Widget) CaseSensitive() bool { - return termshark.ConfBool("main.search-case-sensitive", false) + return profiles.ConfBool("main.search-case-sensitive", false) } func (w *Widget) SetCaseSensitive(val bool) { - termshark.SetConf("main.search-case-sensitive", val) + profiles.SetConf("main.search-case-sensitive", val) } func (w *Widget) Open(app gowid.IApp) { @@ -686,7 +687,7 @@ func buildSearchTypeMenu(btn *button.Widget, men menu.IOpener, res *Widget) *men btn.SetSubWidget(text.New(searchTypeMap[stype]), app) // Save the default search type - termshark.SetConf("main.search-type", stype) + profiles.SetConf("main.search-type", stype) res.validator = getValidator() @@ -703,7 +704,7 @@ func buildSearchTypeMenu(btn *button.Widget, men menu.IOpener, res *Widget) *men switch stype { case "hex": - termshark.SetConf("main.search-target", "bytes") + profiles.SetConf("main.search-target", "bytes") } // read main.search-type and adjust which search algorithm to use @@ -729,9 +730,9 @@ func buildSearchTypeMenu(btn *button.Widget, men menu.IOpener, res *Widget) *men func (w *Widget) updateSearchTargetFromConf(app gowid.IApp) { - sAlg := termshark.ConfString("main.search-type", "filter") + sAlg := profiles.ConfString("main.search-type", "filter") if sAlg != "filter" && sAlg != "hex" { - sAlg = termshark.ConfString("main.search-target", "list") + sAlg = profiles.ConfString("main.search-target", "list") } switch sAlg { @@ -780,7 +781,7 @@ func buildSearchTargetMenu(btn *button.Widget, men menu.IOpener, res *Widget) *m Key: gowid.MakeKey('1' + rune(i)), CB: func(app gowid.IApp, _ gowid.IWidget) { - termshark.SetConf("main.search-target", target) + profiles.SetConf("main.search-target", target) btn.SetSubWidget(text.New(searchTargetMap[target]), app) diff --git a/widgets/streamwidget/streamwidget.go b/widgets/streamwidget/streamwidget.go index 8555269..8bead61 100644 --- a/widgets/streamwidget/streamwidget.go +++ b/widgets/streamwidget/streamwidget.go @@ -36,6 +36,7 @@ import ( "github.com/gcla/gowid/widgets/table" "github.com/gcla/gowid/widgets/text" "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/format" "github.com/gcla/termshark/v2/streams" "github.com/gcla/termshark/v2/ui/menuutil" @@ -416,7 +417,7 @@ func (w *Widget) construct() { for i := 0; i < len(w.tblWidgets); i++ { w.updateChunkModel(i, w.displayAs, app) } - termshark.SetConf("main.stream-view", "hex") + profiles.SetConf("main.stream-view", "hex") } }}) rb2.OnClick(gowid.WidgetCallback{"cb", func(app gowid.IApp, w2 gowid.IWidget) { @@ -425,7 +426,7 @@ func (w *Widget) construct() { for i := 0; i < len(w.tblWidgets); i++ { w.updateChunkModel(i, w.displayAs, app) } - termshark.SetConf("main.stream-view", "ascii") + profiles.SetConf("main.stream-view", "ascii") } }}) rb3.OnClick(gowid.WidgetCallback{"cb", func(app gowid.IApp, w2 gowid.IWidget) { @@ -434,7 +435,7 @@ func (w *Widget) construct() { for i := 0; i < len(w.tblWidgets); i++ { w.updateChunkModel(i, w.displayAs, app) } - termshark.SetConf("main.stream-view", "raw") + profiles.SetConf("main.stream-view", "raw") } }}) From 9c159359f3de4c6b417bbac0ba38292211a18660 Mon Sep 17 00:00:00 2001 From: Graham Clark Date: Sun, 5 Jun 2022 19:06:15 -0400 Subject: [PATCH 03/11] Remove a use of the global viper struct --- configs/profiles/profiles.go | 8 ++++++++ ui/logsui.go | 4 +--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/configs/profiles/profiles.go b/configs/profiles/profiles.go index 231e3f9..ead8dd9 100644 --- a/configs/profiles/profiles.go +++ b/configs/profiles/profiles.go @@ -162,6 +162,14 @@ func confStringSlice(v *viper.Viper, name string, def []string) []string { return res } +func WriteConfigAs(name string) error { + return writeConfigAs(vDefault, name) +} + +func writeConfigAs(v *viper.Viper, name string) error { + return v.WriteConfigAs(name) +} + //====================================================================== // Local Variables: // mode: Go diff --git a/ui/logsui.go b/ui/logsui.go index f2ec5e0..2546969 100644 --- a/ui/logsui.go +++ b/ui/logsui.go @@ -19,7 +19,6 @@ import ( "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/widgets/fileviewer" log "github.com/sirupsen/logrus" - "github.com/spf13/viper" ) //====================================================================== @@ -43,7 +42,6 @@ func openLogsUi(app gowid.IApp) { } func openConfigUi(app gowid.IApp) { - viper.SetConfigName("termshark") // no need to include file extension - looks for file called termshark.ini for example tmp, err := ioutil.TempFile("", "termshark-*.toml") if err != nil { OpenError(fmt.Sprintf("Could not create temp file: %v", err), app) @@ -51,7 +49,7 @@ func openConfigUi(app gowid.IApp) { } tmp.Close() - err = viper.WriteConfigAs(tmp.Name()) + err = profiles.WriteConfigAs(tmp.Name()) if err != nil { OpenError(fmt.Sprintf("Could not run config viewer\n\n%v", err), app) } else { From c5bfbef6ede9f5488d4cc92f9db28d5e0874c41c Mon Sep 17 00:00:00 2001 From: Graham Clark Date: Sun, 12 Jun 2022 18:07:47 -0400 Subject: [PATCH 04/11] Initial implementation of a profiles feature for termshark This work is driven by this issue: https://github.com/gcla/termshark/issues/108 Here's a description of how everything currently works. Prior to this change, termshark had one config file (per user), stored in a standard location. I'll use Linux as an example - ~/.config/termshark/termshark.toml. With this change, there's a new set of subdirectories, one per profile, containing toml files e.g. after some profiles have been created, you might have: ~/.config/termshark/profiles/classic/termshark.toml ~/.config/termshark/profiles/extracolumns/termshark.toml ~/.config/termshark/profiles/darker/termshark.toml These toml files are the same structure as the default termshark.toml. Termshark starts with the default profile, represented by the default config file (not in the new profiles/ dir). There are two new console commands: (1) :profile -> switch profile to one that exists already When a non-default profile is chosen, the settings in that profile's config file take precedence. If a setting is needed and not set explicitly, termshark falls back to the setting in the default profile. When a setting is explicitly changed, it is changed in the newly activated profile. (2) :new-profile -> create a new profile The user must choose a name that is not in use (and that can be used as a directory name). When created, termshark automatically switches to the new profile. If the profile in use at the time of creation is not the default, termshark copies the previous profile to the new profile and proceeds from there. If the profile in use is the default, the new profile will be empty. When termshark is using a non-default profile, it is shown on the top line of the UI. Termshark can be started with a non-default profile using the new -C/--profile command-line flag. Note that although I chose this to line up with Wireshark's invocation, termshark does not use Wireshark profiles in any way. --- cli/all.go | 4 +- cmd/termshark/termshark.go | 54 ++- configs/profiles/profiles.go | 197 +++++++++-- go.mod | 23 +- go.sum | 668 ++++++++++++++++++++++++++++++++--- ui/lastline.go | 70 +++- ui/messages.go | 1 + ui/newprofile.go | 172 +++++++++ ui/ui.go | 115 +++++- 9 files changed, 1170 insertions(+), 134 deletions(-) create mode 100644 ui/newprofile.go diff --git a/cli/all.go b/cli/all.go index b8b5fb9..5abd33b 100644 --- a/cli/all.go +++ b/cli/all.go @@ -12,6 +12,7 @@ import "github.com/jessevdk/go-flags" // Used to determine if we should run tshark instead e.g. stdout is not a tty type Tshark struct { PassThru string `long:"pass-thru" default:"auto" optional:"true" optional-value:"true" choice:"yes" choice:"no" choice:"auto" choice:"true" choice:"false" description:"Run tshark instead (auto => if stdout is not a tty)."` + Profile string `long:"profile" short:"C" description:"Start with this configuration profile." value-name:""` PrintIfaces bool `short:"D" optional:"true" optional-value:"true" description:"Print a list of the interfaces on which termshark can capture."` TailSwitch } @@ -27,6 +28,7 @@ type Termshark struct { CaptureFilter string `short:"f" description:"Apply capture filter." value-name:""` TimestampFormat string `short:"t" description:"Set the format of the packet timestamp printed in summary lines." choice:"a" choice:"ad" choice:"adoy" choice:"d" choice:"dd" choice:"e" choice:"r" choice:"u" choice:"ud" choice:"udoy" value-name:""` PlatformSwitches + Profile string `long:"profile" short:"C" description:"Start with this configuration profile." value-name:""` PassThru string `long:"pass-thru" default:"auto" optional:"true" optional-value:"true" choice:"auto" choice:"true" choice:"false" description:"Run tshark instead (auto => if stdout is not a tty)."` LogTty bool `long:"log-tty" optional:"true" optional-value:"true" choice:"true" choice:"false" description:"Log to the terminal."` Debug TriState `long:"debug" default:"unset" hidden:"true" optional:"true" optional-value:"true" description:"Enable termshark debugging. See https://termshark.io/userguide."` @@ -40,7 +42,7 @@ type Termshark struct { // If args are passed through to tshark (e.g. stdout not a tty), then // strip these out so tshark doesn't fail. -var TermsharkOnly = []string{"--pass-thru", "--log-tty", "--debug", "--tail"} +var TermsharkOnly = []string{"--pass-thru", "--profile", "--log-tty", "--debug", "--tail"} func FlagIsTrue(val string) bool { return val == "true" || val == "yes" diff --git a/cmd/termshark/termshark.go b/cmd/termshark/termshark.go index 1fd9ef7..c12a311 100644 --- a/cmd/termshark/termshark.go +++ b/cmd/termshark/termshark.go @@ -27,7 +27,6 @@ import ( "github.com/gcla/termshark/v2/shark" "github.com/gcla/termshark/v2/streams" "github.com/gcla/termshark/v2/system" - "github.com/gcla/termshark/v2/theme" "github.com/gcla/termshark/v2/tty" "github.com/gcla/termshark/v2/ui" "github.com/gcla/termshark/v2/widgets/filter" @@ -149,15 +148,6 @@ func cmain() int { fmt.Fprintf(os.Stderr, fmt.Sprintf("%s\n", err.Error())) } - if os.Getenv("TERMSHARK_CAPTURE_MODE") == "1" { - err = system.DumpcapExt(termshark.DumpcapBin(), termshark.TSharkBin(), os.Args[1:]...) - if err != nil { - return 1 - } else { - return 0 - } - } - // Used to determine if we should run tshark instead e.g. stdout is not a tty var tsopts cli.Tshark @@ -193,6 +183,29 @@ func cmain() int { } } + // From here, the current profile is referenced. So load it up prior to first use. If the user + // provides a non-existent profile name, it should be an error, just as for Wireshark. + if tsopts.Profile != "" { + if err = profiles.Use(tsopts.Profile); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + return 1 + } + } + + // If this variable is set, it's set by termshark internally, and termshark is guaranteed to + // construct a valid command-line invocation. So it doesn't matter if I do this after the CLI + // parsing logic because there's no risk of an error causing a short-circuit and this command + // not being run. The reason to do it after the CLI parsing logic is so that I have the correct + // config profile loaded, needed for the tshark command. + if os.Getenv("TERMSHARK_CAPTURE_MODE") == "1" { + err = system.DumpcapExt(termshark.DumpcapBin(), termshark.TSharkBin(), os.Args[1:]...) + if err != nil { + return 1 + } else { + return 0 + } + } + // Run after accessing the config so I can use the configured tshark binary, if there is one. I need that // binary in the case that termshark is run where stdout is not a tty, in which case I exec tshark - but // it makes sense to use the one in termshark.toml @@ -1150,24 +1163,7 @@ Loop: // Need to do that here because the app won't know how many colors the screen // has (and therefore which variant of the theme to load) until the screen is // activated. - mode := app.GetColorMode() - modeStr := theme.Mode(mode) // more concise - themeName := profiles.ConfString(fmt.Sprintf("main.theme-%s", modeStr), "default") - loaded := false - if themeName != "" { - err = theme.Load(themeName, app) - if err != nil { - log.Warnf("Theme %s could not be loaded: %v", themeName, err) - } else { - loaded = true - } - } - if !loaded && themeName != "default" { - err = theme.Load("default", app) - if err != nil { - log.Warnf("Theme %s could not be loaded: %v", themeName, err) - } - } + ui.ApplyCurrentTheme(app) // This needs to run after the toml config file is loaded. ui.SetupColors() @@ -1186,7 +1182,7 @@ Loop: ui.StartUIChan = nil // make sure it's not triggered again if runtime.GOOS != "windows" { - if mode == gowid.Mode8Colors { + if app.GetColorMode() == gowid.Mode8Colors { // If exists is true, it means we already tried and then reverted back, so // just load up termshark normally with no further interruption. if _, exists := os.LookupEnv("TERMSHARK_ORIGINAL_TERM"); !exists { diff --git a/configs/profiles/profiles.go b/configs/profiles/profiles.go index ead8dd9..ed8d874 100644 --- a/configs/profiles/profiles.go +++ b/configs/profiles/profiles.go @@ -6,10 +6,12 @@ package profiles import ( "fmt" + "io/ioutil" "os" "path/filepath" "sync" + "github.com/shibukawa/configdir" "github.com/spf13/viper" ) @@ -21,6 +23,7 @@ import ( var confMutex sync.Mutex // If this is non-nil, then the user has a profile loaded +var currentName string var vProfile *viper.Viper var vDefault *viper.Viper @@ -28,17 +31,16 @@ var vDefault *viper.Viper func init() { vDefault = viper.New() - vProfile = viper.New() } //====================================================================== // First is error, second is warning func ReadDefaultConfig(dir string) error { - return readConfig(vDefault, dir, "termshark") + return readConfig(vDefault, dir, "termshark", true) } -func readConfig(v *viper.Viper, dir string, base string) error { +func readConfig(v *viper.Viper, dir string, base string, createIfNecessary bool) error { confMutex.Lock() defer confMutex.Unlock() @@ -48,44 +50,66 @@ func readConfig(v *viper.Viper, dir string, base string) error { v.AddConfigPath(dir) fp := filepath.Join(dir, fmt.Sprintf("%s.toml", base)) - if f, err2 := os.OpenFile(fp, os.O_RDONLY|os.O_CREATE, 0666); err2 != nil { - err = fmt.Errorf("Warning: could not create initial config file: %w", err2) - } else { - f.Close() + if createIfNecessary { + var f *os.File + if f, err = os.OpenFile(fp, os.O_RDONLY|os.O_CREATE, 0666); err == nil { + f.Close() + } } - err = v.ReadInConfig() - if err != nil { - err = fmt.Errorf("Warning: config file %s not found...", fp) + // We managed anyway - so don't alarm the user + if v.ReadInConfig() == nil { + err = nil + } else if err != nil { + err = fmt.Errorf("Profile %s not found. (%w)", fp, err) + } else { + err = fmt.Errorf("Profile %s not found.", fp) } return err } +func Default() *viper.Viper { + return vDefault +} + +func Current() *viper.Viper { + if vProfile != nil { + return vProfile + } + return Default() +} + func ConfKeyExists(name string) bool { - return confKeyExists(vDefault, name) + return ConfKeyExistsIn(Current(), name) || ConfKeyExistsIn(Default(), name) } -func confKeyExists(v *viper.Viper, name string) bool { +func ConfKeyExistsIn(v *viper.Viper, name string) bool { return v.Get(name) != nil } func ConfString(name string, def string) string { - return confString(vDefault, name, def) + return confString(Current(), Default(), name, def) } -func confString(v *viper.Viper, name string, def string) string { +func confString(v *viper.Viper, vd *viper.Viper, name string, def string) string { confMutex.Lock() defer confMutex.Unlock() - if v.Get(name) != nil { + // Use GetString because viper will not allow deletion of keys; so I always + // use the assumption that "" is the same as unset for a string key; then + // I can fallback to the default map if the requested key's value is either "" + // or missing + if v != nil && v.GetString(name) != "" { return v.GetString(name) + } else if vd.GetString(name) != "" { + return vd.GetString(name) } else { return def } } func SetConf(name string, val interface{}) { - setConf(vDefault, name, val) + setConf(Current(), name, val) } func setConf(v *viper.Viper, name string, val interface{}) { @@ -96,17 +120,21 @@ func setConf(v *viper.Viper, name string, val interface{}) { } func ConfStrings(name string) []string { - return confStrings(vDefault, name) + return confStrings(Current(), Default(), name) } -func confStrings(v *viper.Viper, name string) []string { +func confStrings(v *viper.Viper, vd *viper.Viper, name string) []string { confMutex.Lock() defer confMutex.Unlock() - return v.GetStringSlice(name) + if v != nil && ConfKeyExistsIn(v, name) { + return v.GetStringSlice(name) + } else { + return vd.GetStringSlice(name) + } } func DeleteConf(name string) { - deleteConf(vDefault, name) + deleteConf(Current(), name) } func deleteConf(v *viper.Viper, name string) { @@ -117,28 +145,32 @@ func deleteConf(v *viper.Viper, name string) { } func ConfInt(name string, def int) int { - return confInt(vDefault, name, def) + return confInt(Current(), Default(), name, def) } -func confInt(v *viper.Viper, name string, def int) int { +func confInt(v *viper.Viper, vd *viper.Viper, name string, def int) int { confMutex.Lock() defer confMutex.Unlock() - if v.Get(name) != nil { + if v != nil && v.Get(name) != nil { return v.GetInt(name) + } else if vd != nil && vd.Get(name) != nil { + return vd.GetInt(name) } else { return def } } func ConfBool(name string, def ...bool) bool { - return confBool(vDefault, name, def...) + return confBool(vProfile, vDefault, name, def...) } -func confBool(v *viper.Viper, name string, def ...bool) bool { +func confBool(v *viper.Viper, vd *viper.Viper, name string, def ...bool) bool { confMutex.Lock() defer confMutex.Unlock() - if v.Get(name) != nil { + if v != nil && v.Get(name) != nil { return v.GetBool(name) + } else if vd != nil && vd.Get(name) != nil { + return vd.GetBool(name) } else { if len(def) > 0 { return def[0] @@ -149,13 +181,19 @@ func confBool(v *viper.Viper, name string, def ...bool) bool { } func ConfStringSlice(name string, def []string) []string { - return confStringSlice(vDefault, name, def) + return ConfStringSliceFrom(vProfile, vDefault, name, def) } -func confStringSlice(v *viper.Viper, name string, def []string) []string { +func ConfStringSliceFrom(v *viper.Viper, vd *viper.Viper, name string, def []string) []string { confMutex.Lock() defer confMutex.Unlock() - res := v.GetStringSlice(name) + var res []string + if v != nil { + res = v.GetStringSlice(name) + } + if res == nil && vd != nil { + res = vd.GetStringSlice(name) + } if res == nil { res = def } @@ -163,13 +201,112 @@ func confStringSlice(v *viper.Viper, name string, def []string) []string { } func WriteConfigAs(name string) error { - return writeConfigAs(vDefault, name) + return writeConfigAs(Current(), name) } func writeConfigAs(v *viper.Viper, name string) error { return v.WriteConfigAs(name) } +func profilesDir() (string, error) { + stdConf := configdir.New("", "termshark") + conf := stdConf.QueryFolderContainsFile("profiles") + if conf == nil { + return "", fmt.Errorf("Could not find profiles dir.") + } + dirs := stdConf.QueryFolders(configdir.Global) + return filepath.Join(dirs[0].Path, "profiles"), nil +} + +func CopyToAndUse(name string) error { + if Default() == Current() { + vProfile = viper.New() + } + + dir, err := profilesDir() + if err != nil { + return err + } + dir = filepath.Join(dir, name) + + if _, err := os.Stat(dir); os.IsNotExist(err) { + err = os.Mkdir(dir, 0777) + if err != nil { + return fmt.Errorf("Unexpected error making dir %s: %v", dir, err) + } + } + + vProfile.SetConfigFile(filepath.Join(dir, "termshark.toml")) + vProfile.WriteConfig() + + return Use(name) +} + +func CurrentName() string { + if currentName == "" { + return "default" + } + return currentName +} + +func AllNames() []string { + matches := make([]string, 0) + + profPath, err := profilesDir() + if err != nil { + return matches + } + + files, err := ioutil.ReadDir(profPath) + if err == nil { + for _, file := range files { + if file.Name() != "default" { + if _, err := os.Stat(filepath.Join(profPath, file.Name(), "termshark.toml")); err == nil { + matches = append(matches, file.Name()) + } + } + } + } + + matches = append(matches, "default") + + return matches +} + +func Use(name string) error { + // Go back to default - so no overriding profile + if name == "" || name == "default" { + confMutex.Lock() + defer confMutex.Unlock() + vProfile = nil + currentName = "default" + return nil + } + + vNew := viper.New() + + dir, err := profilesDir() + if err != nil { + return err + } + dir = filepath.Join(dir, name) + + if _, err := os.Stat(dir); os.IsNotExist(err) { + err = os.Mkdir(dir, 0777) + if err != nil { + return fmt.Errorf("Unexpected error making dir %s: %v", dir, err) + } + } + + if err := readConfig(vNew, dir, "termshark", false); err != nil { + return err + } + + vProfile = vNew + currentName = name + return nil +} + //====================================================================== // Local Variables: // mode: Go diff --git a/go.mod b/go.mod index 776dfde..d7218db 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/antchfx/xmlquery v1.3.3 github.com/antchfx/xpath v1.1.11 // indirect github.com/blang/semver v3.5.1+incompatible - github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/flytam/filenamify v1.1.0 github.com/gcla/deep v1.0.2 github.com/gcla/gowid v1.3.1-0.20220603022106-4d04cba8013a github.com/gcla/tail v1.0.1-0.20190505190527-650e90873359 @@ -18,30 +18,19 @@ require ( github.com/hashicorp/golang-lru v0.5.4 github.com/jessevdk/go-flags v1.4.0 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 - github.com/magiconair/properties v1.8.4 // indirect - github.com/mattn/go-isatty v0.0.12 + github.com/mattn/go-isatty v0.0.14 github.com/mitchellh/go-homedir v1.1.0 - github.com/mitchellh/mapstructure v1.4.0 // indirect github.com/mreiferson/go-snappystream v0.2.3 - github.com/pelletier/go-toml v1.8.1 // indirect github.com/pkg/errors v0.9.1 github.com/psanford/wormhole-william v1.0.6-0.20210402190004-049df45b8d5a github.com/rakyll/statik v0.1.7 github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 github.com/sirupsen/logrus v1.7.0 - github.com/spf13/afero v1.5.1 // indirect - github.com/spf13/cast v1.3.1 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/viper v1.7.1 - github.com/stretchr/testify v1.7.0 + github.com/spf13/viper v1.12.0 + github.com/stretchr/testify v1.7.1 github.com/tevino/abool v1.2.0 - gitlab.com/jonas.jasas/condchan v0.0.0-20190210165812-36637ad2b5bc // indirect - golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect - golang.org/x/sys v0.0.0-20220318055525-2edf467146b5 + gitlab.com/jonas.jasas/condchan v0.0.0-20190210165812-36637ad2b5bc + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a gopkg.in/fsnotify/fsnotify.v1 v1.4.7 - gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - modernc.org/interval v1.0.0 // indirect - modernc.org/mathutil v1.4.1 // indirect ) diff --git a/go.sum b/go.sum index 7d55759..4030df7 100644 --- a/go.sum +++ b/go.sum @@ -3,47 +3,117 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT 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.44.3/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 v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= 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/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= github.com/adam-hanna/arrayOperations v0.2.6 h1:QZC99xC8MgUawXnav7bFMejs/dm7YySnDpMx3oZzz2Y= github.com/adam-hanna/arrayOperations v0.2.6/go.mod h1:iIzkSjP91FnE66cUFNAjjUJVmjyAwCH0SXnWsx2nbdk= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antchfx/xmlquery v1.3.3 h1:HYmadPG0uz8CySdL68rB4DCLKXz2PurCjS3mnkVF4CQ= github.com/antchfx/xmlquery v1.3.3/go.mod h1:64w0Xesg2sTaawIdNqMB+7qaW/bSqkQm+ssPaCMWNnc= github.com/antchfx/xpath v1.1.10/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= github.com/antchfx/xpath v1.1.11 h1:WOFtK8TVAjLm3lbgqeP0arlHpvCEeTANeWZ/csPpJkQ= github.com/antchfx/xpath v1.1.11/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/araddon/dateparse v0.0.0-20210207001429-0eec95c9db7e h1:OjdSMCht0ZVX7IH0nTdf00xEustvbtUGRgMh3gbdmOg= github.com/araddon/dateparse v0.0.0-20210207001429-0eec95c9db7e/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 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/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 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/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheggaaa/pb/v3 v3.0.1/go.mod h1:SqqeMF/pMOIu3xgGoxtPYhMNQP258xE4x/XRTYua+KU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 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/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.15 h1:cKRCLMj3Ddm54bKSpemfQ8AtYFBhAI2MPmdys22fBdc= github.com/creack/pty v1.1.15/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -51,14 +121,29 @@ 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/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/flytam/filenamify v1.1.0 h1:iEOcC/1UgxJf4lp2E2CWtYO7TMyYmgb2RPSTou89FLs= +github.com/flytam/filenamify v1.1.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= 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/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/gcla/deep v1.0.2 h1:qBOx6eepcOSRYnHJ+f2ih4hP4Vca1YnLtXxp73n5KWI= github.com/gcla/deep v1.0.2/go.mod h1:evE9pbpSGhItmFoBIk8hPOIC/keKTGYhFl6Le1Av+GE= -github.com/gcla/gowid v1.3.1-0.20220530181752-072f0882aae0 h1:myaHMntGEyzp1nWI8QL6596lwKKxclaPOS9D1XlvOGI= -github.com/gcla/gowid v1.3.1-0.20220530181752-072f0882aae0/go.mod h1:7T4Xzfznq31XvQyAOX+SZzQjvF7RX16mjXDXGB7R/44= github.com/gcla/gowid v1.3.1-0.20220603022106-4d04cba8013a h1:8kh1ORv/P5ruPPoZBMrXAxw406+o9Uvg4fPblsMfcUo= github.com/gcla/gowid v1.3.1-0.20220603022106-4d04cba8013a/go.mod h1:7T4Xzfznq31XvQyAOX+SZzQjvF7RX16mjXDXGB7R/44= github.com/gcla/tail v1.0.1-0.20190505190527-650e90873359 h1:3xEhacR7pIJV8daurdBygptxhzTJeYFqJp1V6SDl+pE= @@ -76,9 +161,14 @@ github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwv github.com/gin-gonic/gin v1.7.0 h1:jGB9xAJQ12AIGNB4HguylppmDK1Am9ppF7XnGXXJuoU= github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= @@ -98,35 +188,92 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 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/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 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/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/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/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 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.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +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.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 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.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +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/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= 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/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= @@ -134,15 +281,26 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad 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/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/guptarohit/asciigraph v0.4.1/go.mod h1:9fYEfE5IGJGxlP1B+w8wHFy7sNZMhPtn59f0RLtpRFM= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/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-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= 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= @@ -156,55 +314,81 @@ 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/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 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/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13 h1:eSvu8Tmq6j2psUJqJrLcWH6K3w5Dwc+qipbaA6eVEN4= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/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/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 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/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.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= -github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 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/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -213,52 +397,76 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 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.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks= -github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mreiferson/go-snappystream v0.2.3 h1:ETSjz9NhUz13J3Aq0NisB/8h0nb2QG8DAcQNEw1T8cw= github.com/mreiferson/go-snappystream v0.2.3/go.mod h1:hPB+SkMcb49n7i7BErAtgT4jFQcaCVp6Vyu7aZ46qQo= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/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/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= 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/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= 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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= 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_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= 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/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/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/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= 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/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/psanford/wormhole-william v1.0.6-0.20210402190004-049df45b8d5a h1:IfxVpoAvmF0UXdBEQsa+5KZ7YlrjetPCT9biVvkYfKo= github.com/psanford/wormhole-william v1.0.6-0.20210402190004-049df45b8d5a/go.mod h1:Cz4DnYGGu/7Y8DZxmL0HsZ78EkyTYeKFwZJzF7FKCxw= github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 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/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 h1:Xuk8ma/ibJ1fOy4Ee11vHhUFHQNpHhrBneOCNHVXS5w= @@ -266,20 +474,19 @@ github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0/go.mod h1:7Awj 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/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -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.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg= -github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= 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/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= @@ -288,46 +495,78 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn 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.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -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/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= +github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= 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/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= +github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA= github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= gitlab.com/jonas.jasas/condchan v0.0.0-20190210165812-36637ad2b5bc h1:zCsu+odZEHb2f8U8WWhDgY5N5w3JCLHxuCIqVqCsLcQ= gitlab.com/jonas.jasas/condchan v0.0.0-20190210165812-36637ad2b5bc/go.mod h1:4JS8TdA7HSdK+x43waOdTGodqY/VKsj4w+8pWDL0E88= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= +go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= +go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= 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 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 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/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 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= @@ -337,10 +576,22 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl 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/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 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/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -354,18 +605,77 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn 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-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 h1:NWy5+hlRbC7HK+PmcXVUmW1IMyFce7to56IUvhUFm7Y= +golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 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/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= 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/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/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= @@ -381,21 +691,86 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w 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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220318055525-2edf467146b5 h1:saXMvIOKvRFwbOMicHXr0B1uwoxq9dGmLe5ExMES6c4= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -411,25 +786,106 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3 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-20190524140312-2c0ae7006135/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-20190907020128-2ca718005c18/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/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= 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/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko= 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/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 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= @@ -439,41 +895,161 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98 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/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= 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.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +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.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify/fsnotify.v1 v1.4.7 h1:XNNYLJHt73EyYiCZi6+xjupS9CpvmiDgjPTAjrBlQbo= gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= +gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 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.3/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.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -modernc.org/interval v1.0.0 h1:Qn2Wuajm4C459vIf4woVviD0ITEJ1ulMKb2dLm/7qE8= -modernc.org/interval v1.0.0/go.mod h1:/AfW0uaVPVb1/afoQD3MW9Foc/vVUp0YghT6Wm6IM/A= -modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= salsa.debian.org/vasudev/gospake2 v0.0.0-20180813171123-adcc69dd31d5 h1:j+F9fFxAFNdrO85XnERJSYS5QGfPUWUy9IP4s9BkV6A= salsa.debian.org/vasudev/gospake2 v0.0.0-20180813171123-adcc69dd31d5/go.mod h1:soKzqXBAtqHTODjyA0VzH2iERtpzN1w65eZUfetn2cQ= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/ui/lastline.go b/ui/lastline.go index 3e584c9..274860a 100644 --- a/ui/lastline.go +++ b/ui/lastline.go @@ -35,6 +35,7 @@ var invalidRecentsCommandErr = fmt.Errorf("Invalid recents command") var invalidMapCommandErr = fmt.Errorf("Invalid map command") var invalidFilterCommandErr = fmt.Errorf("Invalid filter command") var invalidThemeCommandErr = fmt.Errorf("Invalid theme command") +var invalidProfileCommandErr = fmt.Errorf("Invalid profile command") type minibufferFn func(gowid.IApp, ...string) error @@ -293,6 +294,30 @@ func (s themeArg) Completions() []string { //====================================================================== +type profileArg struct { + substr string +} + +var _ minibuffer.IArg = profileArg{} + +func (s profileArg) OfferCompletion() bool { + return true +} + +func (s profileArg) Completions() []string { + matches := make([]string, 0) + profs := profiles.AllNames() + for _, prof := range profs { + if strings.Contains(prof, s.substr) { + matches = append(matches, prof) + } + } + + return matches +} + +//====================================================================== + func stringIn(s string, a []string) bool { for _, s2 := range a { if s == s2 { @@ -336,8 +361,7 @@ func (d setCommand) Run(app gowid.IApp, args ...string) error { } case "dark-mode": if b, err = parseOnOff(args[2]); err == nil { - DarkMode = b - profiles.SetConf("main.dark-mode", DarkMode) + SetDarkMode(b) } case "disable-shark-fin": if b, err = strconv.ParseBool(args[2]); err == nil { @@ -585,6 +609,48 @@ func (d themeCommand) Arguments(toks []string, app gowid.IApp) []minibuffer.IArg //====================================================================== +type profileCommand struct{} + +var _ minibuffer.IAction = profileCommand{} + +func (d profileCommand) Run(app gowid.IApp, args ...string) error { + var err error + + if len(args) != 2 { + err = invalidProfileCommandErr + } else { + cur := profiles.Current() + err = profiles.Use(args[1]) + if err == nil { + err = ApplyCurrentProfile(app, cur, profiles.Current()) + } + } + + if err != nil { + OpenMessage(fmt.Sprintf("Error: %s", err), appView, app) + } else { + OpenMessage(fmt.Sprintf("Now using profile %s.", args[1]), appView, app) + } + + return err +} + +func (d profileCommand) OfferCompletion() bool { + return true +} + +func (d profileCommand) Arguments(toks []string, app gowid.IApp) []minibuffer.IArg { + res := make([]minibuffer.IArg, 0) + pref := "" + if len(toks) > 0 { + pref = toks[0] + } + res = append(res, profileArg{substr: pref}) + return res +} + +//====================================================================== + type mapCommand struct { w *mapkeys.Widget } diff --git a/ui/messages.go b/ui/messages.go index 1883be9..9e40fc3 100644 --- a/ui/messages.go +++ b/ui/messages.go @@ -122,6 +122,7 @@ logs____ - Show termshark's log file (Unix-only) map_____ - Map a keypress to a key sequence (see help map) marks___ - Show file-local and global packet marks no-theme - Clear theme for the current terminal color mode +profile_ - Choose a termshark profile quit____ - Quit termshark recents_ - Load a pcap from those recently-used set_____ - Set various config properties (see help set) diff --git a/ui/newprofile.go b/ui/newprofile.go new file mode 100644 index 0000000..96886ae --- /dev/null +++ b/ui/newprofile.go @@ -0,0 +1,172 @@ +// Copyright 2019-2022 Graham Clark. All rights reserved. Use of this source +// code is governed by the MIT license that can be found in the LICENSE +// file. + +package ui + +import ( + "fmt" + + "github.com/flytam/filenamify" + "github.com/gcla/gowid" + "github.com/gcla/gowid/widgets/dialog" + "github.com/gcla/gowid/widgets/divider" + "github.com/gcla/gowid/widgets/edit" + "github.com/gcla/gowid/widgets/framed" + "github.com/gcla/gowid/widgets/pile" + "github.com/gcla/gowid/widgets/text" + "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" + "github.com/gcla/termshark/v2/widgets/appkeys" + "github.com/gdamore/tcell/v2" +) + +//====================================================================== + +var invalidNameErr = fmt.Errorf("Please ensure profile name can be used as a filename.") + +// validProfileName makes sure the profile name is not in use AND can be embedded +// in a directory path. It's easier that way and not much of a limitation. +func validProfileName(name string) error { + if termshark.StringInSlice(name, profiles.AllNames()) { + return fmt.Errorf("Profile %s already exists.", name) + } + + fname, err := filenamify.Filenamify(name, filenamify.Options{}) + if err != nil { + return invalidNameErr + } + + if name != fname { + return invalidNameErr + } + + return nil +} + +func openNewProfile(app gowid.IApp) { + var copyProfileDialog *dialog.Widget + var redoDialog *dialog.Widget + var basedOff string + var invalidWidget *text.Widget + var invalidText string + var okFunc func(gowid.IApp, gowid.IWidget) + + openCopy := func() { + copyProfileDialog.Open(appView, units(len(basedOff)+20), app) + } + + openRedo := func() { + invalidWidget.SetText(invalidText, app) + redoDialog.Open(appView, units(len(invalidText)+10), app) + } + + nameWidget := edit.New() + nameWidgetExt := appkeys.New( + nameWidget, + func(ev *tcell.EventKey, app gowid.IApp) bool { + res := false + switch ev.Key() { + case tcell.KeyEnter: + okFunc(app, nameWidget) + res = true + } + return res + }, + appkeys.Options{ + ApplyBefore: true, + }, + ) + + invalidText = "Placeholder" + invalidWidget = text.New(invalidText) + + openAgainBtn := dialog.Button{ + Msg: "Ok", + Action: gowid.MakeWidgetCallback("exec", gowid.WidgetChangedFunction(func(app gowid.IApp, _ gowid.IWidget) { + redoDialog.Close(app) + openCopy() + })), + } + + redoView := framed.NewSpace(invalidWidget) + + redoDialog = dialog.New( + redoView, + dialog.Options{ + Buttons: []dialog.Button{openAgainBtn}, + NoShadow: true, + BackgroundStyle: gowid.MakePaletteRef("dialog"), + BorderStyle: gowid.MakePaletteRef("dialog"), + ButtonStyle: gowid.MakePaletteRef("dialog-button"), + Modal: true, + FocusOnWidget: true, + }, + ) + + okFunc = func(app gowid.IApp, _ gowid.IWidget) { + copyProfileDialog.Close(app) + + name := nameWidget.Text() + err := validProfileName(name) + if err != nil { + invalidText = err.Error() + openRedo() + return + } + + cur := profiles.Current() + + err = profiles.CopyToAndUse(name) + if err != nil { + OpenError(err.Error(), app) + return + } + + err = ApplyCurrentProfile(app, cur, profiles.Current()) + if err != nil { + OpenError(err.Error(), app) + return + } + + OpenMessage(fmt.Sprintf("Now using new profile %s.", name), appView, app) + } + + okBtn := dialog.Button{ + Msg: "Ok", + Action: gowid.MakeWidgetCallback("exec", gowid.WidgetChangedFunction(okFunc)), + } + + basedOff = fmt.Sprintf("This profile will be based off of %s.", profiles.CurrentName()) + + newProfileView := framed.NewSpace( + pile.NewFlow( + text.New(basedOff), + divider.NewBlank(), + text.New("Please enter a name for this profile:"), + divider.NewBlank(), + framed.NewUnicode(nameWidgetExt), + ), + ) + + copyProfileDialog = dialog.New( + newProfileView, + dialog.Options{ + Buttons: []dialog.Button{okBtn, dialog.Cancel}, + NoShadow: true, + BackgroundStyle: gowid.MakePaletteRef("dialog"), + BorderStyle: gowid.MakePaletteRef("dialog"), + ButtonStyle: gowid.MakePaletteRef("dialog-button"), + Modal: true, + FocusOnWidget: true, + }, + ) + + openCopy() +} + +//====================================================================== +// Local Variables: +// mode: Go +// fill-column: 78 +// End: diff --git a/ui/ui.go b/ui/ui.go index 0547e33..c39f3d2 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -73,6 +73,7 @@ import ( lru "github.com/hashicorp/golang-lru" "github.com/pkg/errors" log "github.com/sirupsen/logrus" + "github.com/spf13/viper" ) //====================================================================== @@ -132,6 +133,7 @@ var view2idx int var generalMenu *menu.Widget var analysisMenu *menu.Widget var savedMenu *menu.Widget +var profileMenu *menu.Widget var FilterWidget *filter.Widget var Fin *rossshark.Widget var CopyModeWidget gowid.IWidget @@ -168,6 +170,11 @@ var multiMenu2Opener MultiMenuOpener var tabViewsForward map[gowid.IWidget]gowid.IWidget var tabViewsBackward map[gowid.IWidget]gowid.IWidget +var currentProfile *text.Widget +var currentProfileWidget *columns.Widget +var currentProfileWidgetHolder *holder.Widget +var openProfileSite *menu.SiteWidget + var currentCapture *text.Widget var currentCaptureWidget *columns.Widget var currentCaptureWidgetHolder *holder.Widget @@ -1417,9 +1424,13 @@ func lastLineMode(app gowid.IApp) { MiniBuffer.Register("no-theme", minibufferFn(func(app gowid.IApp, s ...string) error { mode := theme.Mode(app.GetColorMode()).String() // more concise profiles.DeleteConf(fmt.Sprintf("main.theme-%s", mode)) - theme.Load("default", app) + ApplyCurrentTheme(app) SetupColors() - OpenMessage(fmt.Sprintf("Cleared theme for terminal mode %v.", app.GetColorMode()), appView, app) + var prof string + if profiles.Current() != profiles.Default() { + prof = fmt.Sprintf("in profile %s ", profiles.CurrentName()) + } + OpenMessage(fmt.Sprintf("Cleared theme %sfor terminal mode %v.", prof, app.GetColorMode()), appView, app) return nil })) @@ -1480,6 +1491,11 @@ func lastLineMode(app gowid.IApp) { })) } + MiniBuffer.Register("new-profile", minibufferFn(func(app gowid.IApp, s ...string) error { + openNewProfile(app) + return nil + })) + MiniBuffer.Register("set", setCommand{}) // read new pcap @@ -1489,6 +1505,7 @@ func lastLineMode(app gowid.IApp) { MiniBuffer.Register("recents", recentsCommand{}) MiniBuffer.Register("filter", filterCommand{}) MiniBuffer.Register("theme", themeCommand{}) + MiniBuffer.Register("profile", profileCommand{}) MiniBuffer.Register("map", mapCommand{w: keyMapper}) MiniBuffer.Register("unmap", unmapCommand{w: keyMapper}) MiniBuffer.Register("help", helpCommand{}) @@ -3216,6 +3233,62 @@ func (w *prefixKeyWidget) UserInput(ev interface{}, size gowid.IRenderSize, focu //====================================================================== +func SetDarkMode(mode bool) { + DarkMode = mode + profiles.SetConf("main.dark-mode", DarkMode) +} + +func UpdateProfileWidget(name string, app gowid.IApp) { + currentProfile.SetText(name, app) + if name != "" && name != "default" { + currentProfileWidgetHolder.SetSubWidget(currentProfileWidget, app) + } else { + currentProfileWidgetHolder.SetSubWidget(nullw, app) + } +} + +// vp and vc guaranteed to be non-nil +func ApplyCurrentProfile(app gowid.IApp, vp *viper.Viper, vc *viper.Viper) error { + UpdateProfileWidget(profiles.CurrentName(), app) + + SetDarkMode(profiles.ConfBool("main.dark-mode", true)) + + curcols := profiles.ConfStringSliceFrom(vp, profiles.Default(), "main.column-format", []string{}) + newcols := profiles.ConfStringSliceFrom(vc, profiles.Default(), "main.column-format", []string{}) + if !reflect.DeepEqual(newcols, curcols) { + RequestReload(app) + } + + ApplyCurrentTheme(app) + SetupColors() + + return nil +} + +func ApplyCurrentTheme(app gowid.IApp) { + var err error + mode := app.GetColorMode() + modeStr := theme.Mode(mode) // more concise + themeName := profiles.ConfString(fmt.Sprintf("main.theme-%s", modeStr), "default") + loaded := false + if themeName != "" { + err = theme.Load(themeName, app) + if err != nil { + log.Warnf("Theme %s could not be loaded: %v", themeName, err) + } else { + loaded = true + } + } + if !loaded && themeName != "default" { + err = theme.Load("default", app) + if err != nil { + log.Warnf("Theme %s could not be loaded: %v", themeName, err) + } + } +} + +//====================================================================== + func Build() (*gowid.App, error) { var err error @@ -3345,8 +3418,7 @@ func Build() (*gowid.App, error) { Key: gowid.MakeKey('d'), CB: func(app gowid.IApp, w gowid.IWidget) { multiMenu1Opener.CloseMenu(generalMenu, app) - DarkMode = !DarkMode - profiles.SetConf("main.dark-mode", DarkMode) + SetDarkMode(!DarkMode) }, }, menuutil.MakeMenuDivider(), @@ -3607,6 +3679,24 @@ func Build() (*gowid.App, error) { }, }) + //====================================================================== + + currentProfile = text.New("default") + currentProfileWidget = columns.NewFixed( + text.New("Profile: "), + currentProfile, + sp, + &gowid.ContainerWidget{ + IWidget: fill.New('|'), + D: gowid.MakeRenderBox(1, 1), + }, + sp, + ) + currentProfileWidgetHolder = holder.New(currentProfileWidget) + + // Update display to show the profile if it isn't the default + UpdateProfileWidget(profiles.CurrentName(), app) + var titleCols *columns.Widget // If anything gets added or removed here, see [[generalmenu1]] @@ -3623,6 +3713,10 @@ func Build() (*gowid.App, error) { IWidget: fill.New(' '), D: weight(1), }, + &gowid.ContainerWidget{ + IWidget: currentProfileWidgetHolder, + D: fixed, // give it priority when the window isn't wide enough + }, openAnalysisSite, openAnalysis2, openMenuSite, @@ -3646,7 +3740,7 @@ func Build() (*gowid.App, error) { generalNext.Site = openAnalysisSite generalNext.Container = titleCols generalNext.MenuOpener = &multiMenu1Opener - generalNext.Focus = 4 // should really find by ID + generalNext.Focus = 5 // should really find by ID // <> analysisNext.Cur = analysisMenu @@ -3654,7 +3748,7 @@ func Build() (*gowid.App, error) { analysisNext.Site = openMenuSite analysisNext.Container = titleCols analysisNext.MenuOpener = &multiMenu1Opener - analysisNext.Focus = 6 // should really find by ID + analysisNext.Focus = 7 // should really find by ID packetListViewHolder = holder.New(nullw) packetStructureViewHolder = holder.New(nullw) @@ -3714,6 +3808,9 @@ func Build() (*gowid.App, error) { savedBtnSite := menu.NewSite(menu.SiteOptions{YOffset: 1}) savedw.OnClick(gowid.MakeWidgetCallback("cb", func(app gowid.IApp, w gowid.IWidget) { multiMenu1Opener.OpenMenu(savedMenu, savedBtnSite, app) + // if !multiMenu1Opener.OpenMenu(savedMenu, savedBtnSite, app) { + // multiMenu1Opener.CloseMenu(savedMenu, app) + // } })) progWidgetIdx = 7 // adjust this if nullw moves position in filterCols @@ -4132,9 +4229,9 @@ func Build() (*gowid.App, error) { } // <> - menuPathMain = []interface{}{0, 6} - menuPathAlt = []interface{}{0, 6} - menuPathMax = []interface{}{0, 6} + menuPathMain = []interface{}{0, 7} + menuPathAlt = []interface{}{0, 7} + menuPathMax = []interface{}{0, 7} buildStreamUi() buildFilterConvsMenu() From 4cc4668971ccf5fd53aecc42f6954f673616ad1f Mon Sep 17 00:00:00 2001 From: Graham Clark Date: Sun, 12 Jun 2022 22:34:38 -0400 Subject: [PATCH 05/11] Try to ensure the profiles dir exists when termshark starts Otherwise the new-profile command will fail. --- cmd/termshark/termshark.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/termshark/termshark.go b/cmd/termshark/termshark.go index c12a311..7a98ff1 100644 --- a/cmd/termshark/termshark.go +++ b/cmd/termshark/termshark.go @@ -141,6 +141,10 @@ func cmain() int { dirs = stdConf.QueryFolders(configdir.Global) if err := dirs[0].CreateParentDir("dummy"); err != nil { fmt.Fprintf(os.Stderr, "Warning: could not create config dir: %v\n", err) + } else { + if err = os.MkdirAll(filepath.Join(dirs[0].Path, "profiles"), 0755); err != nil { + fmt.Fprintf(os.Stderr, "Warning: could not create profiles dir: %v\n", err) + } } err := profiles.ReadDefaultConfig(dirs[0].Path) From 7601e01fc136d44396646795374c86eec2c04e42 Mon Sep 17 00:00:00 2001 From: Graham Clark Date: Sat, 2 Jul 2022 17:53:41 -0400 Subject: [PATCH 06/11] Add an extra token to each line of stderr from termshark processes For example: time="2022-07-02T12:46:22-04:00" level=error msg="tshark: Configuration Profile \"test1\" does not exist" cmd=/home/gcla/bin/tshark This might make it a little easier to understand when a tshark process fails to run correctly. I may go further and capture stderr for display in a UI error dialog. --- pcap/cmds.go | 2 +- utils.go | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pcap/cmds.go b/pcap/cmds.go index c82c33f..f1116f9 100644 --- a/pcap/cmds.go +++ b/pcap/cmds.go @@ -46,7 +46,7 @@ func (c *Command) String() string { func (c *Command) Start() error { c.Lock() defer c.Unlock() - c.Cmd.Stderr = log.StandardLogger().Writer() + c.Cmd.Stderr = termshark.ErrLogger("cmd", c.Path) c.PutInNewGroupOnUnix() res := c.Cmd.Start() return res diff --git a/utils.go b/utils.go index f07ffe0..58bbe37 100644 --- a/utils.go +++ b/utils.go @@ -674,6 +674,13 @@ func SaveOffsetToConfig(name string, offsets2 []resizable.Offset) { //====================================================================== +func ErrLogger(key string, val string) *io.PipeWriter { + l := log.StandardLogger() + return log.NewEntry(l).WithField(key, val).WriterLevel(log.ErrorLevel) +} + +//====================================================================== + // Need to publish fields for template use type JumpPos struct { Summary string `json:"summary"` From 51e74574771b1c6d08428ad8a2a2c80a6caa59ac Mon Sep 17 00:00:00 2001 From: Graham Clark Date: Sat, 2 Jul 2022 17:58:43 -0400 Subject: [PATCH 07/11] A function to provide a list of Wireshark profiles The command tshark -G folders is used to determine the locations - both global and personal. I will use this to allow the user to connect a tshark profile to a Wireshark profile, so that when tshark is invoked, it can be influenced by a specific Wireshark profile (e.g. for packet colors) --- utils.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/utils.go b/utils.go index 58bbe37..73f53f4 100644 --- a/utils.go +++ b/utils.go @@ -1082,6 +1082,27 @@ func TsharkSetting(field string) (string, error) { } return "", fmt.Errorf("Field %s not found in output of tshark -G folders", field) +//====================================================================== + +func WiresharkProfileNames() []string { + res := make([]string, 0, 8) + folders, _ := TsharkSettings("Personal configuration", "Global configuration") + for _, folder := range folders { + profFolder := filepath.Join(folder, "profiles") + + files, err := ioutil.ReadDir(profFolder) + if err != nil { + log.Warnf("Could not read wireshark config folder %s: %v", profFolder, err) + continue + } + + for _, file := range files { + if file.IsDir() { + res = append(res, file.Name()) + } + } + } + return res } //====================================================================== From 1b73b61e5431602af709b5300d785306c962e164 Mon Sep 17 00:00:00 2001 From: Graham Clark Date: Sat, 2 Jul 2022 19:03:53 -0400 Subject: [PATCH 08/11] Abstract this simple confirmation function I'd like to use it in another setting where I require a confirmation from the user before proceeding. --- ui/ui.go | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/ui/ui.go b/ui/ui.go index 824d442..45f7df7 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -1547,7 +1547,28 @@ func getCurrentStructModelWith(row int, lock sync.Locker) *pdmltree.Model { //====================================================================== func reallyClear(app gowid.IApp) { - msgt := "Do you want to clear current capture?" + confirmAction( + "Do you want to clear current capture?", + func(app gowid.IApp) { + Loader.ClearPcap( + pcap.HandlerList{ + SimpleErrors{}, + MakePacketViewUpdater(), + MakeUpdateCurrentCaptureInTitle(), + ManageStreamCache{}, + ManageCapinfoCache{}, + SetStructWidgets{Loader}, // for OnClear + ClearMarksHandler{}, + ManageSearchData{}, + CancelledMessage{}, + }, + ) + }, + app, + ) +} + +func confirmAction(msgt string, ok func(gowid.IApp), app gowid.IApp) { msg := text.New(msgt) YesNo = dialog.New( framed.NewSpace(hpadding.New(msg, hmiddle, fixed)), @@ -1558,19 +1579,7 @@ func reallyClear(app gowid.IApp) { Action: gowid.MakeWidgetCallback("cb", func(app gowid.IApp, w gowid.IWidget) { YesNo.Close(app) - Loader.ClearPcap( - pcap.HandlerList{ - SimpleErrors{}, - MakePacketViewUpdater(), - MakeUpdateCurrentCaptureInTitle(), - ManageStreamCache{}, - ManageCapinfoCache{}, - SetStructWidgets{Loader}, // for OnClear - ClearMarksHandler{}, - ManageSearchData{}, - CancelledMessage{}, - }, - ) + ok(app) }, ), }, From 9ccca577eee8c2db7ca531fda0ecdc07024ff16f Mon Sep 17 00:00:00 2001 From: Graham Clark Date: Sat, 2 Jul 2022 19:05:05 -0400 Subject: [PATCH 09/11] Generalize the TsharkSettings function This allows me to return more than one setting from the invocation of a single tshark command. I'll use this to determine the Wireshark global and personal folders. --- utils.go | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/utils.go b/utils.go index 73f53f4..b8fad7e 100644 --- a/utils.go +++ b/utils.go @@ -1067,21 +1067,41 @@ var foldersRE = regexp.MustCompile(`:\s*`) // Global configuration: /usr/share/wireshark // func TsharkSetting(field string) (string, error) { - out, err := exec.Command(TSharkBin(), []string{"-G", "folders"}...).Output() + res, err := TsharkSettings(field) if err != nil { return "", err } + val, ok := res[field] + if !ok { + return "", fmt.Errorf("Field %s not found in output of tshark -G folders", field) + } + + return val, nil +} + +func TsharkSettings(fields ...string) (map[string]string, error) { + out, err := exec.Command(TSharkBin(), []string{"-G", "folders"}...).Output() + if err != nil { + return nil, err + } + + res := make(map[string]string) + scanner := bufio.NewScanner(strings.NewReader(string(out))) for scanner.Scan() { line := scanner.Text() pieces := foldersRE.Split(line, 2) - if len(pieces) == 2 && pieces[0] == field { - return pieces[1], nil + for _, field := range fields { + if len(pieces) == 2 && pieces[0] == field { + res[field] = pieces[1] + } } } - return "", fmt.Errorf("Field %s not found in output of tshark -G folders", field) + return res, nil +} + //====================================================================== func WiresharkProfileNames() []string { From b8476af2401449f66c26d9857e3b4c7506e15770 Mon Sep 17 00:00:00 2001 From: Graham Clark Date: Sat, 2 Jul 2022 19:23:05 -0400 Subject: [PATCH 10/11] Rework profile minibuffer commands and add a connection to Wireshark This change reworks profile support. First, when the create-profile UI is opened, a new section at the bottom of the dialog allows making a connection to a Wireshark profile. If the checkbox is ticked, then the drop down button can be used to choose a Wireshark profile. This is saved in termshark.toml (for the current termshark profile) as main.wireshark-profile (string). The effect is that when tshark is invoked e.g. to load the PSML or PDML for a pcap, the -C flag is provided. One practical effect of this is that the Wireshark packet colors the user may have set up under a specific profile are able to be used in termshark. So, this mechanism allows configuration of termshark profiles via a connection to a Wireshark profile. Note that most Wireshark settings are not adopted in this way; for example, column sets can be configured in Wireshark, but termshark does this independently and stores them in the user's current termshark profile. You can change column sets by changing termshark profile, but they are stored by termshark in its config and not consumed from Wireshark's config. The second change reworks the profile minibuffer commands. Instead of profile and new-profile, there is a multi-level profile command: - profile - create - use - delete - link - unlink --- configs/profiles/profiles.go | 30 ++++++-- pcap/cmds.go | 17 ++++- ui/lastline.go | 139 +++++++++++++++++++++++++++++++---- ui/newprofile.go | 125 ++++++++++++++++++++++++++++--- ui/ui.go | 19 +++-- 5 files changed, 294 insertions(+), 36 deletions(-) diff --git a/configs/profiles/profiles.go b/configs/profiles/profiles.go index ed8d874..6902b75 100644 --- a/configs/profiles/profiles.go +++ b/configs/profiles/profiles.go @@ -89,10 +89,10 @@ func ConfKeyExistsIn(v *viper.Viper, name string) bool { } func ConfString(name string, def string) string { - return confString(Current(), Default(), name, def) + return ConfStringFrom(Current(), Default(), name, def) } -func confString(v *viper.Viper, vd *viper.Viper, name string, def string) string { +func ConfStringFrom(v *viper.Viper, vd *viper.Viper, name string, def string) string { confMutex.Lock() defer confMutex.Unlock() // Use GetString because viper will not allow deletion of keys; so I always @@ -109,10 +109,10 @@ func confString(v *viper.Viper, vd *viper.Viper, name string, def string) string } func SetConf(name string, val interface{}) { - setConf(Current(), name, val) + SetConfIn(Current(), name, val) } -func setConf(v *viper.Viper, name string, val interface{}) { +func SetConfIn(v *viper.Viper, name string, val interface{}) { confMutex.Lock() defer confMutex.Unlock() v.Set(name, val) @@ -250,6 +250,11 @@ func CurrentName() string { } func AllNames() []string { + res := AllNonDefaultNames() + return append(res, "default") +} + +func AllNonDefaultNames() []string { matches := make([]string, 0) profPath, err := profilesDir() @@ -268,11 +273,24 @@ func AllNames() []string { } } - matches = append(matches, "default") - return matches } +func Delete(name string) error { + dir, err := profilesDir() + if err != nil { + return err + } + dir = filepath.Join(dir, name) + + err = os.RemoveAll(dir) + if err != nil { + return fmt.Errorf("Unexpected error deleting profile dir %s: %v", dir, err) + } + + return nil +} + func Use(name string) error { // Go back to default - so no overriding profile if name == "" || name == "default" { diff --git a/pcap/cmds.go b/pcap/cmds.go index f1116f9..cdec87f 100644 --- a/pcap/cmds.go +++ b/pcap/cmds.go @@ -13,9 +13,9 @@ import ( "sync" "github.com/gcla/termshark/v2" + "github.com/gcla/termshark/v2/configs/profiles" "github.com/gcla/termshark/v2/shark" "github.com/kballard/go-shellquote" - log "github.com/sirupsen/logrus" ) //====================================================================== @@ -119,6 +119,10 @@ func (c Commands) Iface(ifaces []string, captureFilter string, tmpfile string) I if captureFilter != "" { args = append(args, "-f", captureFilter) } + prof := profiles.ConfString("main.wireshark-profile", "") + if prof != "" { + args = append(args, "-C", prof) + } res := &Command{ Cmd: exec.Command(termshark.CaptureBin(), args...), } @@ -194,6 +198,11 @@ func (c Commands) Psml(pcap interface{}, displayFilter string) IPcapCommand { args = append(args, c.PsmlArgs...) args = append(args, c.Args...) + prof := profiles.ConfString("main.wireshark-profile", "") + if prof != "" { + args = append(args, "-C", prof) + } + //cmd := exec.Command("strace", args...) cmd := exec.Command(termshark.TSharkBin(), args...) //cmd := exec.Command("stdbuf", args...) @@ -226,6 +235,12 @@ func (c Commands) Pdml(pcap string, displayFilter string) IPcapCommand { } args = append(args, c.PdmlArgs...) args = append(args, c.Args...) + + prof := profiles.ConfString("main.wireshark-profile", "") + if prof != "" { + args = append(args, "-C", prof) + } + return &Command{Cmd: exec.Command(termshark.TSharkBin(), args...)} } diff --git a/ui/lastline.go b/ui/lastline.go index 274860a..ed8ed07 100644 --- a/ui/lastline.go +++ b/ui/lastline.go @@ -91,6 +91,13 @@ func (s substrArg) Completions() []string { //====================================================================== +func newCachedArg(sub string, comps []string) substrArg { + return substrArg{ + sub: sub, + candidates: comps, + } +} + func newBoolArg(sub string) substrArg { return substrArg{ sub: sub, @@ -135,6 +142,19 @@ func newHelpArg(sub string) substrArg { } } +func newProfileArg(sub string) substrArg { + return substrArg{ + sub: sub, + candidates: []string{ + "create", + "use", + "delete", + "link", + "unlink", + }, + } +} + //====================================================================== type unhelpfulArg struct { @@ -609,27 +629,105 @@ func (d themeCommand) Arguments(toks []string, app gowid.IApp) []minibuffer.IArg //====================================================================== -type profileCommand struct{} +type profileCommand struct { + termsharkProfiles []string + wiresharkProfiles []string +} var _ minibuffer.IAction = profileCommand{} +func newProfileCommand() *profileCommand { + return &profileCommand{ + termsharkProfiles: profiles.AllNonDefaultNames(), + wiresharkProfiles: termshark.WiresharkProfileNames(), + } +} + func (d profileCommand) Run(app gowid.IApp, args ...string) error { var err error - if len(args) != 2 { - err = invalidProfileCommandErr - } else { - cur := profiles.Current() - err = profiles.Use(args[1]) - if err == nil { - err = ApplyCurrentProfile(app, cur, profiles.Current()) + switch len(args) { + case 3: + switch args[1] { + case "use": + if !termshark.StringInSlice(args[2], append(d.termsharkProfiles, "default")) { + err = fmt.Errorf("%s is not a valid termshark profile", args[2]) + break + } + cur := profiles.Current() + // gcla later todo - validate arg2 is in list + err = profiles.Use(args[2]) + if err == nil { + err = ApplyCurrentProfile(app, cur, profiles.Current()) + } + if err == nil { + OpenMessage(fmt.Sprintf("Now using profile %s.", args[2]), appView, app) + } + case "link": + // gcla later todo - need to validate it is in list! + if !termshark.StringInSlice(args[2], d.wiresharkProfiles) { + err = fmt.Errorf("%s is not a valid Wireshark profile", args[2]) + break + } + curLink := profiles.ConfString("main.wireshark-profile", "") + profiles.SetConf("main.wireshark-profile", args[2]) + if curLink != args[2] { + RequestReload(app) + } + case "delete": + if !termshark.StringInSlice(args[2], d.termsharkProfiles) { + err = fmt.Errorf("%s is not a valid termshark profile", args[2]) + break + } + + confirmAction( + fmt.Sprintf("Really delete profile %s?", args[2]), + func(app gowid.IApp) { + cur := profiles.Current() + curName := profiles.CurrentName() + if curName == args[2] { + err = profiles.Use("default") + if err == nil { + err = ApplyCurrentProfile(app, cur, profiles.Current()) + } + } + if err == nil { + err = profiles.Delete(args[2]) + } + if err == nil { + msg := fmt.Sprintf("Profile %s deleted.", args[2]) + if curName == args[2] { + OpenMessage(fmt.Sprintf("%s Switched back to default profile.", msg), appView, app) + } else { + OpenMessage(msg, appView, app) + } + } else if err != nil { + OpenMessage(fmt.Sprintf("Error: %s", err), appView, app) + } + }, + app, + ) + + default: + err = invalidSetCommandErr + } + case 2: + switch args[1] { + case "create": + openNewProfile(app) + case "unlink": + curLink := profiles.ConfString("main.wireshark-profile", "") + profiles.SetConf("main.wireshark-profile", "") + if curLink != "" { + RequestReload(app) + } + default: + err = invalidProfileCommandErr } } if err != nil { OpenMessage(fmt.Sprintf("Error: %s", err), appView, app) - } else { - OpenMessage(fmt.Sprintf("Now using profile %s.", args[1]), appView, app) } return err @@ -641,11 +739,26 @@ func (d profileCommand) OfferCompletion() bool { func (d profileCommand) Arguments(toks []string, app gowid.IApp) []minibuffer.IArg { res := make([]minibuffer.IArg, 0) - pref := "" + res = append(res, newProfileArg(toks[0])) + if len(toks) > 0 { - pref = toks[0] + pref := "" + if len(toks) > 1 { + pref = toks[1] + } + + switch toks[0] { + case "create": + case "unlink": + case "use": + res = append(res, newCachedArg(pref, append(d.termsharkProfiles, "default"))) + case "delete": + res = append(res, newCachedArg(pref, d.termsharkProfiles)) + case "link": + res = append(res, newCachedArg(pref, d.wiresharkProfiles)) + } } - res = append(res, profileArg{substr: pref}) + return res } diff --git a/ui/newprofile.go b/ui/newprofile.go index 96886ae..c291cde 100644 --- a/ui/newprofile.go +++ b/ui/newprofile.go @@ -9,14 +9,21 @@ import ( "github.com/flytam/filenamify" "github.com/gcla/gowid" + "github.com/gcla/gowid/widgets/button" + "github.com/gcla/gowid/widgets/checkbox" + "github.com/gcla/gowid/widgets/columns" "github.com/gcla/gowid/widgets/dialog" + "github.com/gcla/gowid/widgets/disable" "github.com/gcla/gowid/widgets/divider" "github.com/gcla/gowid/widgets/edit" "github.com/gcla/gowid/widgets/framed" + "github.com/gcla/gowid/widgets/menu" "github.com/gcla/gowid/widgets/pile" + "github.com/gcla/gowid/widgets/styled" "github.com/gcla/gowid/widgets/text" "github.com/gcla/termshark/v2" "github.com/gcla/termshark/v2/configs/profiles" + "github.com/gcla/termshark/v2/ui/menuutil" "github.com/gcla/termshark/v2/widgets/appkeys" "github.com/gdamore/tcell/v2" ) @@ -28,6 +35,10 @@ var invalidNameErr = fmt.Errorf("Please ensure profile name can be used as a fil // validProfileName makes sure the profile name is not in use AND can be embedded // in a directory path. It's easier that way and not much of a limitation. func validProfileName(name string) error { + if name == "" { + return fmt.Errorf("No profile name provided.") + } + if termshark.StringInSlice(name, profiles.AllNames()) { return fmt.Errorf("Profile %s already exists.", name) } @@ -104,6 +115,11 @@ func openNewProfile(app gowid.IApp) { }, ) + var profileString string // what's displayed in the drop down button + var profileDropDown *button.Widget + var linkCheckBox *checkbox.Widget + var profileMenu *menu.Widget + okFunc = func(app gowid.IApp, _ gowid.IWidget) { copyProfileDialog.Close(app) @@ -115,7 +131,7 @@ func openNewProfile(app gowid.IApp) { return } - cur := profiles.Current() + prev := profiles.Current() err = profiles.CopyToAndUse(name) if err != nil { @@ -123,7 +139,16 @@ func openNewProfile(app gowid.IApp) { return } - err = ApplyCurrentProfile(app, cur, profiles.Current()) + cur := profiles.Current() + + // Set this after CopyAndUse so I can distinguish the prior Wireshark + // profile link (if any) from the current. If there's a change, the current + // source is reloaded. + if linkCheckBox.IsChecked() && profileString != "" { + profiles.SetConfIn(cur, "main.wireshark-profile", profileString) + } + + err = ApplyCurrentProfile(app, prev, cur) if err != nil { OpenError(err.Error(), app) return @@ -139,16 +164,96 @@ func openNewProfile(app gowid.IApp) { basedOff = fmt.Sprintf("This profile will be based off of %s.", profiles.CurrentName()) - newProfileView := framed.NewSpace( - pile.NewFlow( - text.New(basedOff), - divider.NewBlank(), - text.New("Please enter a name for this profile:"), - divider.NewBlank(), - framed.NewUnicode(nameWidgetExt), - ), + linkCheckBox = checkbox.New(false) + + linkWidget := columns.NewFixed(text.New("Link to Wireshark: "), linkCheckBox) + + folderStrings := termshark.WiresharkProfileNames() + + enableWireshark := len(folderStrings) > 0 + + if enableWireshark { + profileString = folderStrings[0] + profileDropDown = button.New(text.New(profileString)) + } + + menuItems := make([]menuutil.SimpleMenuItem, 0) + + for i, folder := range folderStrings { + folderCopy := folder + menuItems = append(menuItems, + menuutil.SimpleMenuItem{ + Txt: folder, + Key: gowid.MakeKey('1' + rune(i)), + CB: func(app gowid.IApp, w2 gowid.IWidget) { + profileString = folderCopy + profileDropDown.SetSubWidget(text.New(profileString), app) + }, + }, + ) + } + + lb, _ := menuutil.MakeMenuWithHotKeys(menuItems, nil) + + profileMenu = menu.New("profilemenu", lb, fixed, menu.Options{ + Modal: true, + OpenCloser: &multiMenu1Opener, + CloseKeysProvided: true, + CloseKeys: []gowid.IKey{ + gowid.MakeKey('q'), + gowid.MakeKeyExt(tcell.KeyLeft), + gowid.MakeKeyExt(tcell.KeyEscape), + gowid.MakeKeyExt(tcell.KeyCtrlC), + }, + }) + + profileMenuSite := menu.NewSite(menu.SiteOptions{YOffset: 1}) + + if enableWireshark { + profileDropDown.OnClick(gowid.MakeWidgetCallback("cb", func(app gowid.IApp, w2 gowid.IWidget) { + multiMenu1Opener.OpenMenu(profileMenu, profileMenuSite, app) + })) + } + + s2Btn := disable.NewDisabled(profileDropDown) + + styledProfileBtn := styled.NewExt( + s2Btn, + gowid.MakePaletteRef("button"), + gowid.MakePaletteRef("button-focus"), + ) + + linkCheckBox.OnClick(gowid.MakeWidgetCallback("cb", func(app gowid.IApp, w2 gowid.IWidget) { + s2Btn.Set(!linkCheckBox.IsChecked()) + })) + + dialogWidgets := make([]interface{}, 0, 8) + dialogWidgets = append(dialogWidgets, + text.New(basedOff), + divider.NewBlank(), + text.New("Please enter a name for this profile:"), + divider.NewBlank(), + framed.NewUnicode(nameWidgetExt), ) + // Add the option to link to a wireshark profile + if enableWireshark { + dialogWidgets = append(dialogWidgets, + divider.NewBlank(), + columns.NewWithDim( + gowid.RenderWithWeight{1}, + &gowid.ContainerWidget{ + IWidget: linkWidget, + D: gowid.RenderFixed{}, + }, + text.New(" "), + columns.NewFixed(profileMenuSite, styledProfileBtn), + ), + ) + } + + newProfileView := framed.NewSpace(pile.NewFlow(dialogWidgets...)) + copyProfileDialog = dialog.New( newProfileView, dialog.Options{ diff --git a/ui/ui.go b/ui/ui.go index 45f7df7..9dd4f5f 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -1491,11 +1491,6 @@ func lastLineMode(app gowid.IApp) { })) } - MiniBuffer.Register("new-profile", minibufferFn(func(app gowid.IApp, s ...string) error { - openNewProfile(app) - return nil - })) - MiniBuffer.Register("set", setCommand{}) // read new pcap @@ -1505,7 +1500,7 @@ func lastLineMode(app gowid.IApp) { MiniBuffer.Register("recents", recentsCommand{}) MiniBuffer.Register("filter", filterCommand{}) MiniBuffer.Register("theme", themeCommand{}) - MiniBuffer.Register("profile", profileCommand{}) + MiniBuffer.Register("profile", newProfileCommand()) MiniBuffer.Register("map", mapCommand{w: keyMapper}) MiniBuffer.Register("unmap", unmapCommand{w: keyMapper}) MiniBuffer.Register("help", helpCommand{}) @@ -3260,11 +3255,23 @@ func UpdateProfileWidget(name string, app gowid.IApp) { func ApplyCurrentProfile(app gowid.IApp, vp *viper.Viper, vc *viper.Viper) error { UpdateProfileWidget(profiles.CurrentName(), app) + reload := false + SetDarkMode(profiles.ConfBool("main.dark-mode", true)) + curWireshark := profiles.ConfStringFrom(vp, profiles.Default(), "main.wireshark-profile", "") + newWireshark := profiles.ConfStringFrom(vc, profiles.Default(), "main.wireshark-profile", "") + if curWireshark != newWireshark { + reload = true + } + curcols := profiles.ConfStringSliceFrom(vp, profiles.Default(), "main.column-format", []string{}) newcols := profiles.ConfStringSliceFrom(vc, profiles.Default(), "main.column-format", []string{}) if !reflect.DeepEqual(newcols, curcols) { + reload = true + } + + if reload { RequestReload(app) } From ef07dd1651f4936c20a6720e5aef439503d44056 Mon Sep 17 00:00:00 2001 From: Graham Clark Date: Sun, 3 Jul 2022 14:50:20 -0400 Subject: [PATCH 11/11] Update the info shown via "help cmdline" I had neglected this - it should show all available minibuffer commands. --- ui/messages.go | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/ui/messages.go b/ui/messages.go index 9e40fc3..89ede16 100644 --- a/ui/messages.go +++ b/ui/messages.go @@ -111,24 +111,28 @@ Activate cmdline mode with the : key. Hit tab to see and choose possible completions. -capinfo_ - Capture file properties -clear___ - Clear current pcap -config__ - Show termshark's config file (Unix-only) -convs___ - Open conversations view -filter__ - Choose a display filter from recently-used -help____ - Various help dialogs -load____ - Load a pcap from the filesystem -logs____ - Show termshark's log file (Unix-only) -map_____ - Map a keypress to a key sequence (see help map) -marks___ - Show file-local and global packet marks -no-theme - Clear theme for the current terminal color mode -profile_ - Choose a termshark profile -quit____ - Quit termshark -recents_ - Load a pcap from those recently-used -set_____ - Set various config properties (see help set) -streams_ - Open stream reassembly view -theme___ - Choose a theme for the current terminal color mode -unmap___ - Remove a keypress mapping{{end}} +capinfo______ - Capture file properties +clear-filter_ - Clear the display filter and apply +clear-packets - Clear the current pcap +columns______ - Choose the columns to display +config_______ - Show termshark's config file (Unix-only) +convs________ - Open conversations view +filter_______ - Choose a display filter from recently-used +help_________ - Various help dialogs +load_________ - Load a pcap from the filesystem +logs_________ - Show termshark's log file (Unix-only) +map__________ - Map a keypress to a key sequence (see help map) +marks________ - Show file-local and global packet marks +menu_________ - Open the UI Misc menu +no-theme_____ - Clear theme for the current terminal color mode +profile______ - Profile actions - create, use, delete, etc +quit_________ - Quit termshark +recents______ - Load a pcap from those recently-used +set__________ - Set various config properties (see help set) +streams______ - Open stream reassembly view +theme________ - Choose a theme for the current terminal color mode +unmap________ - Remove a keypress mapping +wormhole_____ - Prepare to transfer the current pcap{{end}} {{define "SetHelp"}}{{template "NameVer" .}}