diff --git a/CHANGELOG.md b/CHANGELOG.md index f8328b4..32bd5e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,10 +15,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [3.3.0] - -- Changed: Logs are now rotated. Settings are currently hard-coded at 4 files of 5MB +- Added: Logs are now rotated. Settings are currently hard-coded at 4 files of 5MB each, so logs shouldn't take up more than 20MB. I'm going to see how many complain about wanting to configure these settings before I add code to do that. +- Added: Config file support. \$XDG_CONFIG_HOME/gotop/gotop.conf can now + contain any field in Config. Syntax is simply KEY=VALUE. Values in config + file are overridden by command-line arguments (although, there's a weakness + in that there's no way to disable boolean fields enabled in the config). +- Changed: Colorscheme registration is changed to be less hard-coded. + Colorschemes can now be created and added to the repo, without having to also + add hard-coded references elsewhere. +- Changed: Minor code refactoring to support Config file changes has resulted + in better isolation. ## [3.2.0] - 2020-02-14 diff --git a/README.md b/README.md index 0903624..a3ff80c 100644 --- a/README.md +++ b/README.md @@ -149,14 +149,14 @@ build massive edifices, you're in for disappointment. ### CLI Options `-c`, `--color=NAME` Set a colorscheme. -`-m`, `--minimal` Only show CPU, Mem and Process widgets. +`-m`, `--minimal` Only show CPU, Mem and Process widgets. (DEPRECATED for `-l minimal`) `-r`, `--rate=RATE` Number of times per second to update CPU and Mem widgets [default: 1]. `-V`, `--version` Print version and exit. `-p`, `--percpu` Show each CPU in the CPU widget. `-a`, `--averagecpu` Show average CPU in the CPU widget. `-f`, `--fahrenheit` Show temperatures in fahrenheit. `-s`, `--statusbar` Show a statusbar with the time. -`-b`, `--battery` Show battery level widget (`minimal` turns off). [preview](./assets/screenshots/battery.png) +`-b`, `--battery` Show battery level widget (`minimal` turns off). [preview](./assets/screenshots/battery.png) (DEPRECATED for `-l battery`) `-i`, `--interface=NAME` Select network interface [default: all]. `-l`, `--layout=NAME` Choose a layout. gotop searches for a file by NAME in \$XDG_CONFIG_HOME/gotop, then relative to the current path. "-" reads a layout from stdin, allowing for simple, one-off layouts such as `echo net | gotop -l -` diff --git a/cmd/gotop/main.go b/cmd/gotop/main.go index 3249cf2..1e9f4f4 100644 --- a/cmd/gotop/main.go +++ b/cmd/gotop/main.go @@ -1,9 +1,8 @@ package main import ( - "encoding/json" "fmt" - "io/ioutil" + "io" "log" "os" "os/signal" @@ -42,7 +41,7 @@ var ( stderrLogger = log.New(os.Stderr, "", 0) ) -func parseArgs() (gotop.Config, error) { +func parseArgs(conf *gotop.Config) error { usage := ` Usage: gotop [options] @@ -75,133 +74,65 @@ Colorschemes: vice ` - ld := utils.GetLogDir(appName) - cd := utils.GetConfigDir(appName) - conf = gotop.Config{ - ConfigDir: cd, - LogDir: ld, - LogFile: "errors.log", - GraphHorizontalScale: 7, - HelpVisible: false, - Colorscheme: colorschemes.Default, - UpdateInterval: time.Second, - AverageLoad: false, - PercpuLoad: false, - TempScale: w.Celsius, - Statusbar: false, - NetInterface: w.NET_INTERFACE_ALL, - MaxLogSize: 5000000, + var err error + conf.Colorscheme, err = colorschemes.FromName(conf.ConfigDir, "default") + if err != nil { + return err } args, err := docopt.ParseArgs(usage, os.Args[1:], version) if err != nil { - return conf, err + return err } if val, _ := args["--layout"]; val != nil { - s := val.(string) - switch s { - case "-": - conf.Layout = os.Stdin - case "default": - conf.Layout = strings.NewReader(defaultUI) - case "minimal": - conf.Layout = strings.NewReader(minimalUI) - case "battery": - conf.Layout = strings.NewReader(batteryUI) - default: - fp := filepath.Join(cd, s) - conf.Layout, err = os.Open(fp) - if err != nil { - conf.Layout, err = os.Open(s) - if err != nil { - stderrLogger.Fatalf("Unable to open layout file %s or ./%s", fp, s) - } - } - } - } else { - conf.Layout = strings.NewReader(defaultUI) + conf.Layout = val.(string) } - if val, _ := args["--color"]; val != nil { - cs, err := handleColorscheme(val.(string)) + cs, err := colorschemes.FromName(conf.ConfigDir, val.(string)) if err != nil { - return conf, err + return err } conf.Colorscheme = cs } - conf.AverageLoad, _ = args["--averagecpu"].(bool) - conf.PercpuLoad, _ = args["--percpu"].(bool) - statusbar, _ = args["--statusbar"].(bool) - + if args["--averagecpu"].(bool) { + conf.AverageLoad, _ = args["--averagecpu"].(bool) + } + if args["--percpu"].(bool) { + conf.PercpuLoad, _ = args["--percpu"].(bool) + } + if args["--statusbar"].(bool) { + statusbar, _ = args["--statusbar"].(bool) + } if args["--battery"].(bool) { - log.Printf("BATTERY %s", batteryUI) - conf.Layout = strings.NewReader(batteryUI) + conf.Layout = "battery" } if args["--minimal"].(bool) { - conf.Layout = strings.NewReader(minimalUI) + conf.Layout = "minimal" } - rateStr, _ := args["--rate"].(string) - rate, err := strconv.ParseFloat(rateStr, 64) - if err != nil { - return conf, fmt.Errorf("invalid rate parameter") - } - if rate < 1 { - conf.UpdateInterval = time.Second * time.Duration(1/rate) - } else { - conf.UpdateInterval = time.Second / time.Duration(rate) - } - fahrenheit, _ := args["--fahrenheit"].(bool) - if fahrenheit { - conf.TempScale = w.Fahrenheit - } - conf.NetInterface, _ = args["--interface"].(string) - - return conf, nil -} - -func handleColorscheme(c string) (colorschemes.Colorscheme, error) { - var cs colorschemes.Colorscheme - switch c { - case "default": - cs = colorschemes.Default - case "solarized": - cs = colorschemes.Solarized - case "solarized16-light": - cs = colorschemes.Solarized16Light - case "solarized16-dark": - cs = colorschemes.Solarized16Dark - case "monokai": - cs = colorschemes.Monokai - case "vice": - cs = colorschemes.Vice - case "default-dark": - cs = colorschemes.DefaultDark - case "nord": - cs = colorschemes.Nord - default: - custom, err := getCustomColorscheme(conf, c) + if val, _ := args["--statusbar"]; val != nil { + rateStr, _ := args["--rate"].(string) + rate, err := strconv.ParseFloat(rateStr, 64) if err != nil { - return cs, err + return fmt.Errorf("invalid rate parameter") + } + if rate < 1 { + conf.UpdateInterval = time.Second * time.Duration(1/rate) + } else { + conf.UpdateInterval = time.Second / time.Duration(rate) } - cs = custom } - return cs, nil -} + if val, _ := args["--fahrenheit"]; val != nil { + fahrenheit, _ := val.(bool) + if fahrenheit { + conf.TempScale = w.Fahrenheit + } + } + if val, _ := args["--interface"]; val != nil { + conf.NetInterface, _ = args["--interface"].(string) + } -// getCustomColorscheme tries to read a custom json colorscheme from /.json -func getCustomColorscheme(c gotop.Config, name string) (colorschemes.Colorscheme, error) { - var cs colorschemes.Colorscheme - filePath := filepath.Join(c.ConfigDir, name+".json") - dat, err := ioutil.ReadFile(filePath) - if err != nil { - return cs, fmt.Errorf("failed to read colorscheme file: %v", err) - } - err = json.Unmarshal(dat, &cs) - if err != nil { - return cs, fmt.Errorf("failed to parse colorscheme file: %v", err) - } - return cs, nil + return nil } func setDefaultTermuiColors(c gotop.Config) { @@ -388,8 +319,40 @@ func eventLoop(c gotop.Config, grid *layout.MyGrid) { } } +func makeConfig() gotop.Config { + ld := utils.GetLogDir(appName) + cd := utils.GetConfigDir(appName) + conf = gotop.Config{ + ConfigDir: cd, + LogDir: ld, + LogFile: "errors.log", + GraphHorizontalScale: 7, + HelpVisible: false, + UpdateInterval: time.Second, + AverageLoad: false, + PercpuLoad: false, + TempScale: w.Celsius, + Statusbar: false, + NetInterface: w.NET_INTERFACE_ALL, + MaxLogSize: 5000000, + Layout: "default", + } + return conf +} + func main() { - conf, err := parseArgs() + // Set up default config + conf := makeConfig() + // Parse the config file + cfn := filepath.Join(conf.ConfigDir, "gotop.conf") + if cf, err := os.Open(cfn); err == nil { + err := gotop.Parse(cf, &conf) + if err != nil { + stderrLogger.Fatalf("error parsing config file %v", err) + } + } + // Override with command line arguments + err := parseArgs(&conf) if err != nil { stderrLogger.Fatalf("failed to parse cli args: %v", err) } @@ -411,7 +374,8 @@ func main() { bar = w.NewStatusBar() } - ly := layout.ParseLayout(conf.Layout) + lstream := getLayout(conf) + ly := layout.ParseLayout(lstream) grid, err := layout.Layout(ly, conf) if err != nil { stderrLogger.Fatalf("failed to initialize termui: %v", err) @@ -433,3 +397,27 @@ func main() { eventLoop(conf, grid) } + +func getLayout(conf gotop.Config) io.Reader { + switch conf.Layout { + case "-": + return os.Stdin + case "default": + return strings.NewReader(defaultUI) + case "minimal": + return strings.NewReader(minimalUI) + case "battery": + return strings.NewReader(batteryUI) + default: + log.Printf("layout = %s", conf.Layout) + fp := filepath.Join(conf.ConfigDir, conf.Layout) + fin, err := os.Open(fp) + if err != nil { + fin, err = os.Open(conf.Layout) + if err != nil { + log.Fatalf("Unable to open layout file %s or ./%s", fp, conf.Layout) + } + } + return fin + } +} diff --git a/colorschemes/default.go b/colorschemes/default.go index de65c22..dc6c6b2 100644 --- a/colorschemes/default.go +++ b/colorschemes/default.go @@ -1,25 +1,27 @@ package colorschemes -var Default = Colorscheme{ - Fg: 7, - Bg: -1, +func init() { + register("default", Colorscheme{ + Fg: 7, + Bg: -1, - BorderLabel: 7, - BorderLine: 6, + BorderLabel: 7, + BorderLine: 6, - CPULines: []int{4, 3, 2, 1, 5, 6, 7, 8}, + CPULines: []int{4, 3, 2, 1, 5, 6, 7, 8}, - BattLines: []int{4, 3, 2, 1, 5, 6, 7, 8}, + BattLines: []int{4, 3, 2, 1, 5, 6, 7, 8}, - MainMem: 5, - SwapMem: 11, + MainMem: 5, + SwapMem: 11, - ProcCursor: 4, + ProcCursor: 4, - Sparkline: 4, + Sparkline: 4, - DiskBar: 7, + DiskBar: 7, - TempLow: 2, - TempHigh: 1, + TempLow: 2, + TempHigh: 1, + }) } diff --git a/colorschemes/default_dark.go b/colorschemes/default_dark.go index 6070985..7ddb5f7 100644 --- a/colorschemes/default_dark.go +++ b/colorschemes/default_dark.go @@ -1,25 +1,27 @@ package colorschemes -var DefaultDark = Colorscheme{ - Fg: 235, - Bg: -1, +func init() { + register("defaultdark", Colorscheme{ + Fg: 235, + Bg: -1, - BorderLabel: 235, - BorderLine: 6, + BorderLabel: 235, + BorderLine: 6, - CPULines: []int{4, 3, 2, 1, 5, 6, 7, 8}, + CPULines: []int{4, 3, 2, 1, 5, 6, 7, 8}, - BattLines: []int{4, 3, 2, 1, 5, 6, 7, 8}, + BattLines: []int{4, 3, 2, 1, 5, 6, 7, 8}, - MainMem: 5, - SwapMem: 3, + MainMem: 5, + SwapMem: 3, - ProcCursor: 33, + ProcCursor: 33, - Sparkline: 4, + Sparkline: 4, - DiskBar: 252, + DiskBar: 252, - TempLow: 2, - TempHigh: 1, + TempLow: 2, + TempHigh: 1, + }) } diff --git a/colorschemes/monokai.go b/colorschemes/monokai.go index 445f054..cd0471c 100644 --- a/colorschemes/monokai.go +++ b/colorschemes/monokai.go @@ -1,25 +1,27 @@ package colorschemes -var Monokai = Colorscheme{ - Fg: 249, - Bg: -1, +func init() { + register("monokai", Colorscheme{ + Fg: 249, + Bg: -1, - BorderLabel: 249, - BorderLine: 239, + BorderLabel: 249, + BorderLine: 239, - CPULines: []int{81, 70, 208, 197, 249, 141, 221, 186}, + CPULines: []int{81, 70, 208, 197, 249, 141, 221, 186}, - BattLines: []int{81, 70, 208, 197, 249, 141, 221, 186}, + BattLines: []int{81, 70, 208, 197, 249, 141, 221, 186}, - MainMem: 208, - SwapMem: 186, + MainMem: 208, + SwapMem: 186, - ProcCursor: 197, + ProcCursor: 197, - Sparkline: 81, + Sparkline: 81, - DiskBar: 102, + DiskBar: 102, - TempLow: 70, - TempHigh: 208, + TempLow: 70, + TempHigh: 208, + }) } diff --git a/colorschemes/nord.go b/colorschemes/nord.go index f493e40..b6d4b50 100644 --- a/colorschemes/nord.go +++ b/colorschemes/nord.go @@ -11,28 +11,30 @@ package colorschemes -var Nord = Colorscheme{ - Name: "A Nord Approximation", - Author: "@jrswab", - Fg: 254, // lightest - Bg: -1, +func init() { + register("nord", Colorscheme{ + Name: "A Nord Approximation", + Author: "@jrswab", + Fg: 254, // lightest + Bg: -1, - BorderLabel: 254, - BorderLine: 96, // Purple + BorderLabel: 254, + BorderLine: 96, // Purple - CPULines: []int{4, 3, 2, 1, 5, 6, 7, 8}, + CPULines: []int{4, 3, 2, 1, 5, 6, 7, 8}, - BattLines: []int{4, 3, 2, 1, 5, 6, 7, 8}, + BattLines: []int{4, 3, 2, 1, 5, 6, 7, 8}, - MainMem: 172, // Orange - SwapMem: 221, // yellow + MainMem: 172, // Orange + SwapMem: 221, // yellow - ProcCursor: 31, // blue (nord9) + ProcCursor: 31, // blue (nord9) - Sparkline: 31, + Sparkline: 31, - DiskBar: 254, + DiskBar: 254, - TempLow: 64, // green - TempHigh: 167, // red + TempLow: 64, // green + TempHigh: 167, // red + }) } diff --git a/colorschemes/registry.go b/colorschemes/registry.go new file mode 100644 index 0000000..97e2bb0 --- /dev/null +++ b/colorschemes/registry.go @@ -0,0 +1,43 @@ +package colorschemes + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "path/filepath" +) + +var registry map[string]Colorscheme + +func FromName(confDir string, c string) (Colorscheme, error) { + cs, ok := registry[c] + if !ok { + cs, err := getCustomColorscheme(confDir, c) + if err != nil { + return cs, err + } + } + return cs, nil +} + +func register(name string, c Colorscheme) { + if registry == nil { + registry = make(map[string]Colorscheme) + } + registry[name] = c +} + +// getCustomColorscheme tries to read a custom json colorscheme from /.json +func getCustomColorscheme(confDir string, name string) (Colorscheme, error) { + var cs Colorscheme + filePath := filepath.Join(confDir, name+".json") + dat, err := ioutil.ReadFile(filePath) + if err != nil { + return cs, fmt.Errorf("failed to read colorscheme file: %v", err) + } + err = json.Unmarshal(dat, &cs) + if err != nil { + return cs, fmt.Errorf("failed to parse colorscheme file: %v", err) + } + return cs, nil +} diff --git a/colorschemes/solarized.go b/colorschemes/solarized.go index 5968310..48d67b0 100644 --- a/colorschemes/solarized.go +++ b/colorschemes/solarized.go @@ -3,26 +3,28 @@ package colorschemes // This is a neutral version of the Solarized 256-color palette. The exception // is that the one grey color uses the average of base0 and base00, which are // already middle of the road. -var Solarized = Colorscheme{ - Fg: -1, - Bg: -1, +func init() { + register("solarized", Colorscheme{ + Fg: -1, + Bg: -1, - BorderLabel: -1, - BorderLine: 37, + BorderLabel: -1, + BorderLine: 37, - CPULines: []int{61, 33, 37, 64, 125, 160, 166, 136}, + CPULines: []int{61, 33, 37, 64, 125, 160, 166, 136}, - BattLines: []int{61, 33, 37, 64, 125, 160, 166, 136}, + BattLines: []int{61, 33, 37, 64, 125, 160, 166, 136}, - MainMem: 125, - SwapMem: 166, + MainMem: 125, + SwapMem: 166, - ProcCursor: 136, + ProcCursor: 136, - Sparkline: 33, + Sparkline: 33, - DiskBar: 243, + DiskBar: 243, - TempLow: 64, - TempHigh: 160, + TempLow: 64, + TempHigh: 160, + }) } diff --git a/colorschemes/solarized16-dark.go b/colorschemes/solarized16-dark.go index f8cdab7..202dbab 100644 --- a/colorschemes/solarized16-dark.go +++ b/colorschemes/solarized16-dark.go @@ -2,26 +2,28 @@ package colorschemes // This scheme assumes the terminal already uses Solarized. Only DiskBar is // different between dark/light. -var Solarized16Dark = Colorscheme{ - Fg: -1, - Bg: -1, +func init() { + register("solarized16dark", Colorscheme{ + Fg: -1, + Bg: -1, - BorderLabel: -1, - BorderLine: 6, + BorderLabel: -1, + BorderLine: 6, - CPULines: []int{13, 4, 6, 2, 5, 1, 9, 3}, + CPULines: []int{13, 4, 6, 2, 5, 1, 9, 3}, - BattLines: []int{13, 4, 6, 2, 5, 1, 9, 3}, + BattLines: []int{13, 4, 6, 2, 5, 1, 9, 3}, - MainMem: 5, - SwapMem: 9, + MainMem: 5, + SwapMem: 9, - ProcCursor: 4, + ProcCursor: 4, - Sparkline: 4, + Sparkline: 4, - DiskBar: 12, // base0 + DiskBar: 12, // base0 - TempLow: 2, - TempHigh: 1, + TempLow: 2, + TempHigh: 1, + }) } diff --git a/colorschemes/solarized16-light.go b/colorschemes/solarized16-light.go index 8426a95..351fe4e 100644 --- a/colorschemes/solarized16-light.go +++ b/colorschemes/solarized16-light.go @@ -2,26 +2,28 @@ package colorschemes // This scheme assumes the terminal already uses Solarized. Only DiskBar is // different between dark/light. -var Solarized16Light = Colorscheme{ - Fg: -1, - Bg: -1, +func init() { + register("solarized16light", Colorscheme{ + Fg: -1, + Bg: -1, - BorderLabel: -1, - BorderLine: 6, + BorderLabel: -1, + BorderLine: 6, - CPULines: []int{13, 4, 6, 2, 5, 1, 9, 3}, + CPULines: []int{13, 4, 6, 2, 5, 1, 9, 3}, - BattLines: []int{13, 4, 6, 2, 5, 1, 9, 3}, + BattLines: []int{13, 4, 6, 2, 5, 1, 9, 3}, - MainMem: 5, - SwapMem: 9, + MainMem: 5, + SwapMem: 9, - ProcCursor: 4, + ProcCursor: 4, - Sparkline: 4, + Sparkline: 4, - DiskBar: 11, // base00 + DiskBar: 11, // base00 - TempLow: 2, - TempHigh: 1, + TempLow: 2, + TempHigh: 1, + }) } diff --git a/colorschemes/vice.go b/colorschemes/vice.go index 23fa02a..8bd2545 100644 --- a/colorschemes/vice.go +++ b/colorschemes/vice.go @@ -1,25 +1,27 @@ package colorschemes -var Vice = Colorscheme{ - Fg: 231, - Bg: -1, +func init() { + register("vice", Colorscheme{ + Fg: 231, + Bg: -1, - BorderLabel: 123, - BorderLine: 102, + BorderLabel: 123, + BorderLine: 102, - CPULines: []int{212, 218, 123, 159, 229, 158, 183, 146}, + CPULines: []int{212, 218, 123, 159, 229, 158, 183, 146}, - BattLines: []int{212, 218, 123, 159, 229, 158, 183, 146}, + BattLines: []int{212, 218, 123, 159, 229, 158, 183, 146}, - MainMem: 201, - SwapMem: 97, + MainMem: 201, + SwapMem: 97, - ProcCursor: 159, + ProcCursor: 159, - Sparkline: 183, + Sparkline: 183, - DiskBar: 158, + DiskBar: 158, - TempLow: 49, - TempHigh: 197, + TempLow: 49, + TempHigh: 197, + }) } diff --git a/config.go b/config.go index c215fac..0cd9e58 100644 --- a/config.go +++ b/config.go @@ -1,7 +1,11 @@ package gotop import ( + "bufio" + "fmt" "io" + "strconv" + "strings" "time" "github.com/xxxserxxx/gotop/colorschemes" @@ -29,9 +33,92 @@ type Config struct { UpdateInterval time.Duration AverageLoad bool PercpuLoad bool - TempScale widgets.TempScale Statusbar bool + TempScale widgets.TempScale NetInterface string - Layout io.Reader + Layout string MaxLogSize int64 } + +func Parse(in io.Reader, conf *Config) error { + r := bufio.NewScanner(in) + var lineNo int + for r.Scan() { + l := strings.TrimSpace(r.Text()) + kv := strings.Split(l, "=") + if len(kv) != 2 { + return fmt.Errorf("bad config file syntax; should be KEY=VALUE, was %s", l) + } + key := strings.ToLower(kv[0]) + switch key { + default: + return fmt.Errorf("invalid config option %s", key) + case "configdir": + conf.ConfigDir = kv[1] + case "logdir": + conf.LogDir = kv[1] + case "logfile": + conf.LogFile = kv[1] + case "graphhorizontalscale": + iv, err := strconv.Atoi(kv[1]) + if err != nil { + return err + } + conf.GraphHorizontalScale = iv + case "helpvisible": + bv, err := strconv.ParseBool(kv[1]) + if err != nil { + return fmt.Errorf("line %d: %v", lineNo, err) + } + conf.HelpVisible = bv + case "colorscheme": + cs, err := colorschemes.FromName(conf.ConfigDir, kv[1]) + if err != nil { + return fmt.Errorf("line %d: %v", lineNo, err) + } + conf.Colorscheme = cs + case "updateinterval": + iv, err := strconv.Atoi(kv[1]) + if err != nil { + return err + } + conf.UpdateInterval = time.Duration(iv) + case "averagecpu": + bv, err := strconv.ParseBool(kv[1]) + if err != nil { + return fmt.Errorf("line %d: %v", lineNo, err) + } + conf.AverageLoad = bv + case "percpuload": + bv, err := strconv.ParseBool(kv[1]) + if err != nil { + return fmt.Errorf("line %d: %v", lineNo, err) + } + conf.PercpuLoad = bv + case "tempscale": + iv, err := strconv.Atoi(kv[1]) + if err != nil { + return err + } + conf.TempScale = widgets.TempScale(iv) + case "statusbar": + bv, err := strconv.ParseBool(kv[1]) + if err != nil { + return fmt.Errorf("line %d: %v", lineNo, err) + } + conf.Statusbar = bv + case "netinterface": + conf.NetInterface = kv[1] + case "layout": + conf.Layout = kv[1] + case "maxlogsize": + iv, err := strconv.Atoi(kv[1]) + if err != nil { + return err + } + conf.MaxLogSize = int64(iv) + } + } + + return nil +} diff --git a/config.json b/config.json new file mode 100644 index 0000000..832e015 --- /dev/null +++ b/config.json @@ -0,0 +1,11 @@ +{ + "colorscheme": "default", + "updateInterval": 1, + "minimalMode": false, + "averageLoad": false, + "percpuLoad": false, + "isFahrenheit": false, + "battery": false, + "statusbar": false, + "netInterface": "NET_INTERFACE_ALL" +} diff --git a/config_test.go b/config_test.go new file mode 100644 index 0000000..329ef75 --- /dev/null +++ b/config_test.go @@ -0,0 +1,87 @@ +package gotop + +import ( + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/xxxserxxx/gotop/widgets" +) + +func TestParse(t *testing.T) { + tests := []struct { + i string + f func(c Config, e error) + }{ + { + i: "logdir", + f: func(c Config, e error) { + assert.Error(t, e, "invalid config syntax") + }, + }, + { + i: "logdir=foo=bar", + f: func(c Config, e error) { + assert.NotNil(t, e) + }, + }, + { + i: "foo=bar", + f: func(c Config, e error) { + assert.NotNil(t, e) + }, + }, + { + i: "configdir=abc\nlogdir=bar\nlogfile=errors", + f: func(c Config, e error) { + assert.Nil(t, e, "unexpected error") + assert.Equal(t, "abc", c.ConfigDir) + assert.Equal(t, "bar", c.LogDir) + assert.Equal(t, "errors", c.LogFile) + }, + }, + { + i: "CONFIGDIR=abc\nloGdir=bar\nlogFILe=errors", + f: func(c Config, e error) { + assert.Nil(t, e, "unexpected error") + assert.Equal(t, "abc", c.ConfigDir) + assert.Equal(t, "bar", c.LogDir) + assert.Equal(t, "errors", c.LogFile) + }, + }, + { + i: "graphhorizontalscale=a", + f: func(c Config, e error) { + assert.Error(t, e, "expected invalid value for graphhorizontalscale") + }, + }, + { + i: "helpvisible=a", + f: func(c Config, e error) { + assert.Error(t, e, "expected invalid value for helpvisible") + }, + }, + { + i: "helpvisible=true\nupdateinterval=30\naveragecpu=true\nPerCPULoad=true\ntempscale=100\nstatusbar=true\nnetinterface=eth0\nlayout=minimal\nmaxlogsize=200", + f: func(c Config, e error) { + assert.Nil(t, e, "unexpected error") + assert.Equal(t, true, c.HelpVisible) + assert.Equal(t, time.Duration(30), c.UpdateInterval) + assert.Equal(t, true, c.AverageLoad) + assert.Equal(t, true, c.PercpuLoad) + assert.Equal(t, widgets.TempScale(100), c.TempScale) + assert.Equal(t, true, c.Statusbar) + assert.Equal(t, "eth0", c.NetInterface) + assert.Equal(t, "minimal", c.Layout) + assert.Equal(t, int64(200), c.MaxLogSize) + }, + }, + } + for _, tc := range tests { + in := strings.NewReader(tc.i) + c := Config{} + e := Parse(in, &c) + tc.f(c, e) + } +} diff --git a/go.mod b/go.mod index e96c9b4..56c0e5d 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/gizak/termui/v3 v3.0.0 github.com/go-ole/go-ole v1.2.4 // indirect github.com/mattn/go-runewidth v0.0.4 + github.com/mitchellh/go-wordwrap v1.0.0 // indirect github.com/shirou/gopsutil v2.18.11+incompatible github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect github.com/stretchr/testify v1.4.0 diff --git a/go.sum b/go.sum index f2046de..6106028 100644 --- a/go.sum +++ b/go.sum @@ -26,6 +26,8 @@ github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840= github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=