summaryrefslogtreecommitdiffstats
path: root/cmd/gotop/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/gotop/main.go')
-rw-r--r--cmd/gotop/main.go250
1 files changed, 107 insertions, 143 deletions
diff --git a/cmd/gotop/main.go b/cmd/gotop/main.go
index 0b08846..d8e0493 100644
--- a/cmd/gotop/main.go
+++ b/cmd/gotop/main.go
@@ -9,15 +9,16 @@ import (
"os/signal"
"path/filepath"
"sort"
- "strconv"
"strings"
"syscall"
"time"
- docopt "github.com/docopt/docopt.go"
+ //_ "net/http/pprof"
+
ui "github.com/gizak/termui/v3"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/shibukawa/configdir"
+ flag "github.com/xxxserxxx/pflag"
"github.com/xxxserxxx/gotop/v4"
"github.com/xxxserxxx/gotop/v4/colorschemes"
@@ -48,127 +49,66 @@ var (
stderrLogger = log.New(os.Stderr, "", 0)
)
-// TODO: Add tab completion for Linux https://gist.github.com/icholy/5314423
-// TODO: state:merge #135 linux console font (cmatsuoka/console-font)
-// TODO: Abstract out the UI toolkit. mum4k/termdash, VladimirMarkelov/clui, gcla/gowid, rivo/tview, marcusolsson/tui-go might work better for some OS/Archs. Performance/memory use comparison would be interesting.
func parseArgs(conf *gotop.Config) error {
cds := conf.ConfigDir.QueryFolders(configdir.All)
cpaths := make([]string, len(cds))
for i, p := range cds {
cpaths[i] = p.Path
}
- usage := fmt.Sprintln(`
-Usage: gotop [options]
-
-Options:
- -c, --color=NAME Set a colorscheme.
- -h, --help Show this screen.
- -S, --graphscale=INT Graph scale factor, from 1+ [default: 7]
- -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, --bandwidth=bits Specify the number of bits per seconds.
- -l, --layout=NAME Name of layout spec file for the UI. Use "-" to pipe.
- -i, --interface=NAME Select network interface [default: all]. Several interfaces can be defined using comma separated values. Interfaces can also be ignored using !
- -x, --export=PORT Enable metrics for export on the specified port.
- --mbps Show mbps for network IO.
- --test Runs tests and exits with success/failure code.
- --list <devices|layouts|colorschemes|paths|keys>
- devices: Prints out device names for widgets supporting filters.
- layouts: Lists build-in layouts
- colorschemes: Lists built-in colorschemes
- paths: List out configuration file search paths
- keys: Show the keyboard bindings.
- --write-config Write out a default config file.`)
-
- args, err := docopt.ParseArgs(usage, os.Args[1:], Version)
- if err != nil {
- return err
- }
-
- if val, _ := args["--layout"]; val != nil {
- conf.Layout = val.(string)
- }
- if val, _ := args["--color"]; val != nil {
- cs, err := colorschemes.FromName(conf.ConfigDir, val.(string))
- if err != nil {
- return err
- }
- conf.Colorscheme = cs
- }
-
- 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 val, _ := args["--export"]; val != nil {
- conf.ExportPort = val.(string)
- }
- if val, _ := args["--rate"]; val != nil {
- rateStr, _ := val.(string)
- rate, err := strconv.ParseFloat(rateStr, 64)
- if err != nil {
- 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)
- }
- }
- 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)
+ help := flag.BoolP("help", "h", false, "Show this screen.")
+ color := flag.StringP("color", "c", conf.Colorscheme.Name, "Set a colorscheme.")
+ flag.IntVarP(&conf.GraphHorizontalScale, "graphscale", "S", conf.GraphHorizontalScale, "Graph scale factor, >0")
+ version := flag.BoolP("version", "v", false, "Print version and exit.")
+ versioN := flag.BoolP("", "V", false, "Print version and exit.")
+ flag.BoolVarP(&conf.PercpuLoad, "percpu", "p", conf.PercpuLoad, "Show each CPU in the CPU widget.")
+ flag.BoolVarP(&conf.AverageLoad, "averagecpu", "a", conf.AverageLoad, "Show average CPU in the CPU widget.")
+ fahrenheit := flag.BoolP("fahrenheit", "f", conf.TempScale == 'F', "Show temperatures in fahrenheit.Show temperatures in fahrenheit.")
+ flag.BoolVarP(&conf.Statusbar, "statusbar", "s", conf.Statusbar, "Show a statusbar with the time.")
+ flag.DurationVarP(&conf.UpdateInterval, "rate", "r", conf.UpdateInterval, "Number of times per second to update CPU and Mem widgets.")
+ flag.StringVarP(&conf.ExportPort, "layout", "l", conf.Layout, `Name of layout spec file for the UI. Use "-" to pipe.`)
+ flag.StringVarP(&conf.NetInterface, "interface", "i", "all", "Select network interface. Several interfaces can be defined using comma separated values. Interfaces can also be ignored using `!`")
+ flag.StringVarP(&conf.ExportPort, "export", "x", conf.ExportPort, "Enable metrics for export on the specified port.")
+ flag.BoolVarP(&conf.Mbps, "mbps", "", conf.Mbps, "Show network rate as mbps.")
+ // FIXME Where did this go??
+ //conf.Band = flag.IntP("bandwidth", "B", 100, "Specify the number of bits per seconds.")
+ flag.BoolVar(&conf.Test, "test", conf.Test, "Runs tests and exits with success/failure code.")
+ list := flag.String("list", "", `List <devices|layouts|colorschemes|paths|keys>
+devices: Prints out device names for filterable widgets
+layouts: Lists build-in layouts
+colorschemes: Lists built-in colorschemes
+paths: List out configuration file search paths
+keys: Show the keyboard bindings.`)
+ wc := flag.Bool("write-config", false, "Write out a default config file.")
+ flag.CommandLine.SortFlags = false
+ flag.Usage = func() {
+ fmt.Fprintf(os.Stderr, "Usage: %s [options]\n\nOptions:\n", os.Args[0])
+ flag.PrintDefaults()
+ }
+ flag.Parse()
+ if *version || *versioN {
+ fmt.Printf("gotop %s (%s)\n", Version, BuildDate)
+ os.Exit(0)
}
- if val, _ := args["--test"]; val != nil {
- conf.Test = val.(bool)
+ if *help {
+ flag.Usage()
+ os.Exit(0)
}
- if val, _ := args["--graphscale"]; val != nil {
- str, _ := args["--graphscale"].(string)
- scl, err := strconv.Atoi(str)
- if err != nil {
- fmt.Printf("invalid value \"%s\" for graphscale; must be an integer\n", args["--graphscale"])
- os.Exit(1)
- }
- if scl < 1 {
- fmt.Printf("graphscale must be greater than 0 [1, ∞); you provided %d. Values > 30 are probably not useful.\n", scl)
- os.Exit(1)
- }
- conf.GraphHorizontalScale = scl
+ cs, err := colorschemes.FromName(conf.ConfigDir, *color)
+ if err != nil {
+ return err
}
- if args["--mbps"].(bool) {
- conf.Mbps = true
+ conf.Colorscheme = cs
+ if *fahrenheit {
+ conf.TempScale = 'F'
+ } else {
+ conf.TempScale = 'C'
}
- if val, _ := args["--list"]; val != nil {
- switch val {
+ if *list != "" {
+ switch *list {
case "layouts":
- fmt.Println("Built-in layouts:")
- fmt.Println("\tdefault")
- fmt.Println("\tminimal")
- fmt.Println("\tbattery")
- fmt.Println("\tkitchensink")
+ fmt.Println(LAYOUTS)
case "colorschemes":
- fmt.Println("Built-in colorschemes:")
- fmt.Println("\tdefault")
- fmt.Println("\tdefault-dark (for white background)")
- fmt.Println("\tsolarized")
- fmt.Println("\tsolarized16-dark")
- fmt.Println("\tsolarized16-light")
- fmt.Println("\tmonokai")
- fmt.Println("\tvice")
+ fmt.Println(COLORSCHEMES)
case "paths":
fmt.Println("Loadable colorschemes & layouts, and the config file, are searched for, in order:")
paths := make([]string, 0)
@@ -180,42 +120,14 @@ Options:
case "devices":
listDevices()
case "keys":
- fmt.Println(`
-Quit: q or <C-c>
-Process navigation:
- k and <Up>: up
- j and <Down>: down
- <C-u>: half page up
- <C-d>: half page down
- <C-b>: full page up
- <C-f>: full page down
- gg and <Home>: jump to top
- G and <End>: jump to bottom
-Process actions:
- <Tab>: toggle process grouping
- dd: kill selected process or group of processes with SIGTERM
- d3: kill selected process or group of processes with SIGQUIT
- d9: kill selected process or group of processes with SIGKILL
-Process sorting
- c: CPU
- m: Mem
- p: PID
-Process filtering:
- /: start editing filter
- (while editing):
- <Enter> accept filter
- <C-c> and <Escape>: clear filter
-CPU and Mem graph scaling:
- h: scale in
- l: scale out
-?: toggles keybind help menu`)
+ fmt.Println(KEYS)
default:
- fmt.Printf("Unknown option \"%s\"; try layouts, colorschemes, or devices\n", val)
+ fmt.Printf("Unknown option \"%s\"; try layouts, colorschemes, or devices\n", *list)
os.Exit(1)
}
os.Exit(0)
}
- if args["--write-config"].(bool) {
+ if *wc {
path, err := conf.Write()
if err != nil {
fmt.Printf("Failed to write configuration file: %s\n", err)
@@ -224,7 +136,6 @@ CPU and Mem graph scaling:
fmt.Printf("Config written to %s\n", path)
os.Exit(0)
}
-
return nil
}
@@ -438,7 +349,17 @@ func makeConfig() gotop.Config {
// TODO: Add fans
// TODO: mpd visualizer widget
+// TODO: Add tab completion for Linux https://gist.github.com/icholy/5314423
+// TODO: state:merge #135 linux console font (cmatsuoka/console-font)
+// TODO: Abstract out the UI toolkit. mum4k/termdash, VladimirMarkelov/clui, gcla/gowid, rivo/tview, marcusolsson/tui-go might work better for some OS/Archs. Performance/memory use comparison would be interesting.
+// TODO: all of the go vet stuff, more unit tests, benchmarks, finish remote.
+// TODO: color bars for memory, a-la bashtop
func main() {
+ // For performance testing
+ //go func() {
+ // log.Fatal(http.ListenAndServe(":7777", nil))
+ //}()
+
// This is just to make sure gotop returns a useful exit code, but also
// executes all defer statements and so cleans up before exit. Sort of
// annoying work-around for a lack of a clean way to exit Go programs
@@ -486,6 +407,7 @@ func run() int {
return runTests(conf)
}
+ //devices.Startup(conf)
if err := ui.Init(); err != nil {
stderrLogger.Print(err)
return 1
@@ -575,3 +497,45 @@ func listDevices() {
}
}
}
+
+const KEYS = `Quit: q or <C-c>
+Process navigation:
+ k and <Up>: up
+ j and <Down>: down
+ <C-u>: half page up
+ <C-d>: half page down
+ <C-b>: full page up
+ <C-f>: full page down
+ gg and <Home>: jump to top
+ G and <End>: jump to bottom
+Process actions:
+ <Tab>: toggle process grouping
+ dd: kill selected process or group of processes with SIGTERM
+ d3: kill selected process or group of processes with SIGQUIT
+ d9: kill selected process or group of processes with SIGKILL
+Process sorting
+ c: CPU
+ m: Mem
+ p: PID
+Process filtering:
+ /: start editing filter
+ (while editing):
+ <Enter> accept filter
+ <C-c> and <Escape>: clear filter
+CPU and Mem graph scaling:
+ h: scale in
+ l: scale out
+?: toggles keybind help menu`
+const LAYOUTS = `Built-in layouts:
+\tdefault
+\tminimal
+\tbattery
+\tkitchensink`
+const COLORSCHEMES = `Built-in colorschemes:
+\tdefault
+\tdefault-dark (for white background)
+\tsolarized
+\tsolarized16-dark
+\tsolarized16-light
+\tmonokai
+\tvice`