From d743472b16af0c32dd63ddeab9007db7bee98bc9 Mon Sep 17 00:00:00 2001 From: Bradley Cicenas Date: Thu, 11 Jan 2018 16:15:18 +0000 Subject: [PATCH] add support for config file, keybinding for exporting active config --- README.md | 1 + config/file.go | 119 +++++++++++++++++++++++++++++++++++++++++++++++ config/switch.go | 8 ++++ grid.go | 3 ++ main.go | 2 +- menus.go | 1 + 6 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 config/file.go diff --git a/README.md b/README.md index 2bd922f..a8b7124 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ s | Select container sort field r | Reverse container sort order o | Open single view l | View container logs (`t` to toggle timestamp when open) +S | Save current configuration to file q | Quit ctop [build]: _docs/build.md diff --git a/config/file.go b/config/file.go new file mode 100644 index 0000000..513054a --- /dev/null +++ b/config/file.go @@ -0,0 +1,119 @@ +package config + +import ( + "fmt" + "os" + "regexp" + "strings" + + "github.com/BurntSushi/toml" +) + +var ( + xdgRe = regexp.MustCompile("^XDG_*") +) + +type ConfigFile struct { + Options map[string]string `toml:"options"` + Toggles map[string]bool `toml:"toggles"` +} + +func exportConfig() ConfigFile { + c := ConfigFile{ + Options: make(map[string]string), + Toggles: make(map[string]bool), + } + for _, p := range GlobalParams { + c.Options[p.Key] = p.Val + } + for _, sw := range GlobalSwitches { + c.Toggles[sw.Key] = sw.Val + } + return c +} + +func Read() error { + var config ConfigFile + + path, err := getConfigPath() + if err != nil { + return err + } + + if _, err := toml.DecodeFile(path, &config); err != nil { + return err + } + + for k, v := range config.Options { + Update(k, v) + } + for k, v := range config.Toggles { + UpdateSwitch(k, v) + } + return nil +} + +func Write() error { + path, err := getConfigPath() + if err != nil { + return err + } + + cfgdir := basedir(path) + // create config dir if not exist + if _, err := os.Stat(cfgdir); err != nil { + err = os.MkdirAll(cfgdir, 0755) + if err != nil { + return fmt.Errorf("failed to create config dir [%s]: %s", cfgdir, err) + } + } + + file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644) + if err != nil { + return fmt.Errorf("failed to open config for writing: %s", err) + } + + writer := toml.NewEncoder(file) + err = writer.Encode(exportConfig()) + if err != nil { + return fmt.Errorf("failed to write config: %s", err) + } + + return nil +} + +// determine config path from environment +func getConfigPath() (path string, err error) { + homeDir, ok := os.LookupEnv("HOME") + if !ok { + return path, fmt.Errorf("$HOME not set") + } + + // use xdg config home if possible + if xdgSupport() { + xdgHome, ok := os.LookupEnv("XDG_CONFIG_HOME") + if !ok { + xdgHome = fmt.Sprintf("%s/.config", homeDir) + } + path = fmt.Sprintf("%s/ctop/config", xdgHome) + } else { + path = fmt.Sprintf("%s/.ctop", homeDir) + } + + return path, nil +} + +// test for environemnt supporting XDG spec +func xdgSupport() bool { + for _, e := range os.Environ() { + if xdgRe.FindAllString(e, 1) != nil { + return true + } + } + return false +} + +func basedir(path string) string { + parts := strings.Split(path, "/") + return strings.Join((parts[0 : len(parts)-1]), "/") +} diff --git a/config/switch.go b/config/switch.go index 3eb343a..1658669 100644 --- a/config/switch.go +++ b/config/switch.go @@ -45,6 +45,14 @@ func GetSwitchVal(k string) bool { return GetSwitch(k).Val } +func UpdateSwitch(k string, val bool) { + sw := GetSwitch(k) + if sw.Val != val { + log.Noticef("config change: %s: %t -> %t", k, sw.Val, val) + sw.Val = val + } +} + // Toggle a boolean switch func Toggle(k string) { sw := GetSwitch(k) diff --git a/grid.go b/grid.go index af88c62..bb15263 100644 --- a/grid.go +++ b/grid.go @@ -131,6 +131,9 @@ func Display() bool { menu = SortMenu ui.StopLoop() }) + ui.Handle("/sys/kbd/S", func(ui.Event) { + config.Write() + }) ui.Handle("/timer/1s", func(e ui.Event) { RefreshDisplay() diff --git a/main.go b/main.go index 63deda6..b6ee215 100644 --- a/main.go +++ b/main.go @@ -41,7 +41,7 @@ func main() { sortFieldFlag = flag.String("s", "", "select container sort field") reverseSortFlag = flag.Bool("r", false, "reverse container sort order") invertFlag = flag.Bool("i", false, "invert default colors") - scaleCpu = flag.Bool("scale-cpu", false, "show cpu as %% of system total") + scaleCpu = flag.Bool("scale-cpu", false, "show cpu as % of system total") connectorFlag = flag.String("connector", "docker", "container connector to use") ) flag.Parse() diff --git a/menus.go b/menus.go index cb1cbcd..feceea2 100644 --- a/menus.go +++ b/menus.go @@ -25,6 +25,7 @@ var helpDialog = []menu.Item{ {"[r] - reverse container sort order", ""}, {"[o] - open single view", ""}, {"[l] - view container logs ([t] to toggle timestamp when open)", ""}, + {"[S] - save current configuration to file", ""}, {"[q] - exit ctop", ""}, }