summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean E. Russell <ser@ser1.net>2020-02-17 11:40:16 -0600
committerSean E. Russell <ser@ser1.net>2020-02-17 11:40:16 -0600
commit2a533986815836ac65c2b03d1f9c4c508e5b98a9 (patch)
tree03d18ab237434820066eb82025f539ce1bfdbc56
parent3fc3d1e18ed1f80444d037f34769841f4a7e37d9 (diff)
parent10e3b7afbc53fe68b3c9ec0dd8ddff4e15fba9e4 (diff)
Adds log rotation, config file support, and refactoring. Colorschemes are self-registered. Merge remote-tracking branch 'jrswab/configFile111' into config_file; drastically refactored, and am not sure how much original code from the patch was used.
-rw-r--r--CHANGELOG.md11
-rw-r--r--README.md4
-rw-r--r--cmd/gotop/main.go206
-rw-r--r--colorschemes/default.go30
-rw-r--r--colorschemes/default_dark.go30
-rw-r--r--colorschemes/monokai.go30
-rw-r--r--colorschemes/nord.go34
-rw-r--r--colorschemes/registry.go43
-rw-r--r--colorschemes/solarized.go30
-rw-r--r--colorschemes/solarized16-dark.go30
-rw-r--r--colorschemes/solarized16-light.go30
-rw-r--r--colorschemes/vice.go30
-rw-r--r--config.go91
-rw-r--r--config.json11
-rw-r--r--config_test.go87
-rw-r--r--go.mod1
-rw-r--r--go.sum2
17 files changed, 472 insertions, 228 deletions
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["--battery"].(bool) {
- log.Printf("BATTERY %s", batteryUI)
- conf.Layout = strings.NewReader(batteryUI)
+ if args["--averagecpu"].(bool) {
+ conf.AverageLoad, _ = args["--averagecpu"].(bool)
}
- if args["--minimal"].(bool) {
- conf.Layout = strings.NewReader(minimalUI)
+ if args["--percpu"].(bool) {
+ conf.PercpuLoad, _ = args["--percpu"].(bool)
}
- rateStr, _ := args["--rate"].(string)
- rate, err := strconv.ParseFloat(rateStr, 64)
- if err != nil {
- return conf, fmt.Errorf("invalid rate parameter")
+ if args["--statusbar"].(bool) {
+ statusbar, _ = args["--statusbar"].(bool)
}
- if rate < 1 {
- conf.UpdateInterval = time.Second * time.Duration(1/rate)
- } else {
- conf.UpdateInterval = time.Second / time.Duration(rate)
+ if args["--battery"].(bool) {
+ conf.Layout = "battery"
}
- fahrenheit, _ := args["--fahrenheit"].(bool)
- if fahrenheit {
- conf.TempScale = w.Fahrenheit
+ if args["--minimal"].(bool) {
+ conf.Layout = "minimal"
}
- 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
-}
-
-// getCustomColorscheme tries to read a custom json colorscheme from <configDir>/<name>.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)
+ if val, _ := args["--fahrenheit"]; val != nil {
+ fahrenheit, _ := val.(bool)
+ if fahrenheit {
+ conf.TempScale = w.Fahrenheit
+ }
}
- err = json.Unmarshal(dat, &cs)
- if err != nil {
- return cs, fmt.Errorf("failed to parse colorscheme file: %v", err)
+ if val, _ := args["--interface"]; val != nil {
+ conf.NetInterface, _ = args["--interface"].(string)
}
- 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 <configDir>/<name>.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=