Mostly adds the -C option. KNOWN: it must be the first argument.

Doc
This commit is contained in:
Sean E. Russell 2020-04-29 10:25:21 -05:00
parent 3487bbfaed
commit 3f26ebef76
6 changed files with 91 additions and 49 deletions

View File

@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Adds ability to filter reported temperatures (#92)
- Command line option to list layouts, paths, colorschemes, hotkeys, and filterable devices
- Adds ability to write out a configuration file
- Adds a command for specifying the configuration file to use
### Changed

View File

@ -1,6 +1,8 @@
package main
import (
"bufio"
"flag"
"fmt"
"io"
"log"
@ -18,7 +20,7 @@ import (
ui "github.com/gizak/termui/v3"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/shibukawa/configdir"
flag "github.com/xxxserxxx/opflag"
"github.com/xxxserxxx/opflag"
"github.com/xxxserxxx/gotop/v4"
"github.com/xxxserxxx/gotop/v4/colorschemes"
@ -50,49 +52,50 @@ var (
stderrLogger = log.New(os.Stderr, "", 0)
)
func parseArgs(conf *gotop.Config) error {
func parseArgs() error {
cds := conf.ConfigDir.QueryFolders(configdir.All)
cpaths := make([]string, len(cds))
for i, p := range cds {
cpaths[i] = p.Path
}
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.Layout, "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.")
help := opflag.BoolP("help", "h", false, "Show this screen.")
color := opflag.StringP("color", "c", conf.Colorscheme.Name, "Set a colorscheme.")
opflag.IntVarP(&conf.GraphHorizontalScale, "graphscale", "S", conf.GraphHorizontalScale, "Graph scale factor, >0")
version := opflag.BoolP("version", "v", false, "Print version and exit.")
versioN := opflag.BoolP("", "V", false, "Print version and exit.")
opflag.BoolVarP(&conf.PercpuLoad, "percpu", "p", conf.PercpuLoad, "Show each CPU in the CPU widget.")
opflag.BoolVarP(&conf.AverageLoad, "averagecpu", "a", conf.AverageLoad, "Show average CPU in the CPU widget.")
fahrenheit := opflag.BoolP("fahrenheit", "f", conf.TempScale == 'F', "Show temperatures in fahrenheit.Show temperatures in fahrenheit.")
opflag.BoolVarP(&conf.Statusbar, "statusbar", "s", conf.Statusbar, "Show a statusbar with the time.")
opflag.DurationVarP(&conf.UpdateInterval, "rate", "r", conf.UpdateInterval, "Number of times per second to update CPU and Mem widgets.")
opflag.StringVarP(&conf.Layout, "layout", "l", conf.Layout, `Name of layout spec file for the UI. Use "-" to pipe.`)
opflag.StringVarP(&conf.NetInterface, "interface", "i", "all", "Select network interface. Several interfaces can be defined using comma separated values. Interfaces can also be ignored using `!`")
opflag.StringVarP(&conf.ExportPort, "export", "x", conf.ExportPort, "Enable metrics for export on the specified port.")
opflag.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>
//conf.Band = opflag.IntP("bandwidth", "B", 100, "Specify the number of bits per seconds.")
opflag.BoolVar(&conf.Test, "test", conf.Test, "Runs tests and exits with success/failure code.")
opflag.StringP("", "C", "", "Config file to use instead of default (MUST BE FIRST ARGUMENT)")
list := opflag.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
widgets: Widgets that can be used in a layout
widgets: Widgets that can be used in a layout
keys: Show the keyboard bindings.`)
wc := flag.Bool("write-config", false, "Write out a default config file.")
flag.SortFlags = false
flag.Usage = func() {
wc := opflag.Bool("write-config", false, "Write out a default config file.")
opflag.SortFlags = false
opflag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: %s [options]\n\nOptions:\n", os.Args[0])
flag.PrintDefaults()
opflag.PrintDefaults()
}
flag.Parse()
opflag.Parse()
if *version || *versioN {
fmt.Printf("gotop %s (%s)\n", Version, BuildDate)
os.Exit(0)
}
if *help {
flag.Usage()
opflag.Usage()
os.Exit(0)
}
cs, err := colorschemes.FromName(conf.ConfigDir, *color)
@ -331,14 +334,17 @@ func eventLoop(c gotop.Config, grid *layout.MyGrid) {
}
}
// TODO: Add fans
// TODO: mpd visualizer widget
// TODO: @devices fans
// TODO: @devices mpd visualizer
// TODO: @devices color bars for memory, a-la bashtop
// 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
// TODO: more unit tests, benchmarks
// TODO: README is getting long. Move to wiki.
// TODO: add verbose debugging option
// TODO: find VMs for FreeBSD, etc for testing gotop
// TODO: add README about extensions, and wiki page for writing extensions
func main() {
// For performance testing
//go func() {
@ -359,15 +365,23 @@ func main() {
}
func run() int {
conf := gotop.NewConfig()
conf = gotop.NewConfig()
// Find the config file; look in (1) local, (2) user, (3) global
// Check the last argument first
fs := flag.NewFlagSet("config", flag.ContinueOnError)
cfg := fs.String("C", "", "Config file")
fs.SetOutput(bufio.NewWriter(nil))
fs.Parse(os.Args[1:])
if *cfg != "" {
conf.ConfigFile = *cfg
}
err := conf.Load()
if err != nil {
fmt.Printf("failed to parse config file: %s\n", err)
return 2
}
// Override with command line arguments
err = parseArgs(&conf)
err = parseArgs()
if err != nil {
fmt.Printf("parsing CLI args: %s\n", err)
return 2

View File

@ -5,7 +5,9 @@ import (
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"strconv"
"strings"
@ -16,6 +18,9 @@ import (
"github.com/xxxserxxx/gotop/v4/widgets"
)
// CONFFILE is the name of the default config file
const CONFFILE = "gotop.conf"
type Config struct {
ConfigDir configdir.ConfigDir
GraphHorizontalScale int
@ -34,6 +39,7 @@ type Config struct {
Temps []string
Test bool
ExtensionVars map[string]string
ConfigFile string
}
func NewConfig() Config {
@ -54,21 +60,25 @@ func NewConfig() Config {
ExtensionVars: make(map[string]string),
}
conf.Colorscheme, _ = colorschemes.FromName(conf.ConfigDir, "default")
folder := conf.ConfigDir.QueryFolderContainsFile(CONFFILE)
if folder != nil {
conf.ConfigFile = filepath.Join(folder.Path, CONFFILE)
}
return conf
}
func (conf *Config) Load() error {
var in []byte
var err error
cfn := "gotop.conf"
folder := conf.ConfigDir.QueryFolderContainsFile(cfn)
if folder != nil {
if in, err = folder.ReadFile(cfn); err != nil {
return err
}
} else {
if conf.ConfigFile == "" {
return nil
}
var err error
if _, err = os.Stat(conf.ConfigFile); os.IsNotExist(err) {
return nil
}
if in, err = ioutil.ReadFile(conf.ConfigFile); err != nil {
return err
}
return load(bytes.NewReader(in), conf)
}
@ -169,21 +179,35 @@ func load(in io.Reader, conf *Config) error {
return nil
}
// Write serializes the configuration to a file.
// The configuration written is based on the loaded configuration, plus any
// command-line changes, so it can be used to update an existing configuration
// file. The file will be written to the specificed `--config` argument file,
// if one is set; otherwise, it'll create one in the user's config directory.
func (conf *Config) Write() (string, error) {
cfn := "gotop.conf"
ds := conf.ConfigDir.QueryFolders(configdir.Global)
if len(ds) == 0 {
ds = conf.ConfigDir.QueryFolders(configdir.Local)
var dir *configdir.Config
var file string = CONFFILE
if conf.ConfigFile == "" {
ds := conf.ConfigDir.QueryFolders(configdir.Global)
if len(ds) == 0 {
return "", fmt.Errorf("error locating config folders")
ds = conf.ConfigDir.QueryFolders(configdir.Local)
if len(ds) == 0 {
return "", fmt.Errorf("error locating config folders")
}
}
ds[0].CreateParentDir(CONFFILE)
dir = ds[0]
} else {
dir = &configdir.Config{}
dir.Path = filepath.Dir(conf.ConfigFile)
file = filepath.Base(conf.ConfigFile)
}
marshalled := marshal(conf)
err := ds[0].WriteFile(cfn, marshalled)
err := dir.WriteFile(file, marshalled)
if err != nil {
return "", err
}
return filepath.Join(ds[0].Path, cfn), nil
return filepath.Join(dir.Path, file), nil
}
func marshal(c *Config) []byte {

2
go.mod
View File

@ -14,7 +14,7 @@ require (
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect
github.com/stretchr/testify v1.4.0
github.com/xxxserxxx/iSMC v1.0.1
github.com/xxxserxxx/opflag v1.0.3
github.com/xxxserxxx/opflag v1.0.5
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a // indirect
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c // indirect
golang.org/x/tools/gopls v0.4.0 // indirect

4
go.sum
View File

@ -119,6 +119,10 @@ github.com/xxxserxxx/opflag v1.0.2 h1:TanW4Ck/RNal4fP2VVAvhEu7eBq4z+9hhGq9Q8OTq6
github.com/xxxserxxx/opflag v1.0.2/go.mod h1:GWZtb3/tGGj5W1GE/JTyJAuqgxDxl1+jqDGAGM+P/p4=
github.com/xxxserxxx/opflag v1.0.3 h1:ugsBWZtSXUaMLEjPLW0WKGjq/gsrc0GpZYbCJY6ZHVY=
github.com/xxxserxxx/opflag v1.0.3/go.mod h1:GWZtb3/tGGj5W1GE/JTyJAuqgxDxl1+jqDGAGM+P/p4=
github.com/xxxserxxx/opflag v1.0.4 h1:g979b8oReAERfDKFTTwdvAYIarFxpVYOzYrHa/hMvNs=
github.com/xxxserxxx/opflag v1.0.4/go.mod h1:GWZtb3/tGGj5W1GE/JTyJAuqgxDxl1+jqDGAGM+P/p4=
github.com/xxxserxxx/opflag v1.0.5 h1:2H4Qtl1qe+dSkEcGt+fBe2mQ8z14MgkWPqcLaoa6k90=
github.com/xxxserxxx/opflag v1.0.5/go.mod h1:GWZtb3/tGGj5W1GE/JTyJAuqgxDxl1+jqDGAGM+P/p4=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/arch v0.0.0-20181203225421-5a4828bb7045/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=

View File

@ -31,7 +31,6 @@ type TempWidget struct {
tempsMetric map[string]prometheus.Gauge
}
// TODO: state:deferred 156 Added temperatures for NVidia GPUs (azak-azkaran/master). Crashes on non-nvidia machines.
func NewTempWidget(tempScale TempScale, filter []string) *TempWidget {
self := &TempWidget{
Block: ui.NewBlock(),