mirror of https://github.com/bcicen/ctop.git
refactor column config
This commit is contained in:
parent
c7a8bfa26f
commit
fc9bd9e5ca
|
@ -0,0 +1,138 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// defaults
|
||||||
|
var defaultColumns = []Column{
|
||||||
|
Column{
|
||||||
|
Name: "status",
|
||||||
|
Label: "Status Indicator",
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
Column{
|
||||||
|
Name: "name",
|
||||||
|
Label: "Container Name",
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
Column{
|
||||||
|
Name: "id",
|
||||||
|
Label: "Container ID",
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
Column{
|
||||||
|
Name: "cpu",
|
||||||
|
Label: "CPU Usage",
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
Column{
|
||||||
|
Name: "mem",
|
||||||
|
Label: "Memory Usage",
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
Column{
|
||||||
|
Name: "net",
|
||||||
|
Label: "Network RX/TX",
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
Column{
|
||||||
|
Name: "io",
|
||||||
|
Label: "Disk IO Read/Write",
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
Column{
|
||||||
|
Name: "pids",
|
||||||
|
Label: "Container PID Count",
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type Column struct {
|
||||||
|
Name string
|
||||||
|
Label string
|
||||||
|
Enabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// ColumnsString returns an ordered and comma-delimited string of currently enabled Columns
|
||||||
|
func ColumnsString() string { return strings.Join(EnabledColumns(), ",") }
|
||||||
|
|
||||||
|
// EnabledColumns returns an ordered array of enabled column names
|
||||||
|
func EnabledColumns() (a []string) {
|
||||||
|
lock.RLock()
|
||||||
|
defer lock.RUnlock()
|
||||||
|
for _, col := range GlobalColumns {
|
||||||
|
if col.Enabled {
|
||||||
|
a = append(a, col.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// ColumnLeft moves the column with given name up one position, if possible
|
||||||
|
func ColumnLeft(name string) {
|
||||||
|
idx := colIndex(name)
|
||||||
|
if idx > 0 {
|
||||||
|
swapCols(idx, idx-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ColumnRight moves the column with given name up one position, if possible
|
||||||
|
func ColumnRight(name string) {
|
||||||
|
idx := colIndex(name)
|
||||||
|
if idx < len(GlobalColumns)-1 {
|
||||||
|
swapCols(idx, idx+1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Column order and enabled status from one or more provided Column names
|
||||||
|
func SetColumns(names []string) {
|
||||||
|
var (
|
||||||
|
n int
|
||||||
|
curColStr = ColumnsString()
|
||||||
|
newColumns = make([]*Column, len(GlobalColumns))
|
||||||
|
)
|
||||||
|
|
||||||
|
lock.Lock()
|
||||||
|
|
||||||
|
// add enabled columns by name
|
||||||
|
for _, name := range names {
|
||||||
|
newColumns[n] = popColumn(name)
|
||||||
|
newColumns[n].Enabled = true
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
|
||||||
|
// extend with omitted columns as disabled
|
||||||
|
for _, col := range GlobalColumns {
|
||||||
|
newColumns[n] = col
|
||||||
|
newColumns[n].Enabled = false
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalColumns = newColumns
|
||||||
|
lock.Unlock()
|
||||||
|
|
||||||
|
log.Noticef("config change [columns]: %s -> %s", curColStr, ColumnsString())
|
||||||
|
}
|
||||||
|
|
||||||
|
func swapCols(i, j int) { GlobalColumns[i], GlobalColumns[j] = GlobalColumns[j], GlobalColumns[i] }
|
||||||
|
|
||||||
|
func popColumn(name string) *Column {
|
||||||
|
idx := colIndex(name)
|
||||||
|
if idx < 0 {
|
||||||
|
panic("no such column name: " + name)
|
||||||
|
}
|
||||||
|
col := GlobalColumns[idx]
|
||||||
|
GlobalColumns = append(GlobalColumns[:idx], GlobalColumns[idx+1:]...)
|
||||||
|
return col
|
||||||
|
}
|
||||||
|
|
||||||
|
// return index of column with given name, if any
|
||||||
|
func colIndex(name string) int {
|
||||||
|
for n, c := range GlobalColumns {
|
||||||
|
if c.Name == name {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
|
@ -16,17 +16,18 @@ var (
|
||||||
type File struct {
|
type File struct {
|
||||||
Options map[string]string `toml:"options"`
|
Options map[string]string `toml:"options"`
|
||||||
Toggles map[string]bool `toml:"toggles"`
|
Toggles map[string]bool `toml:"toggles"`
|
||||||
Widgets []Widget `toml:"widget"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportConfig() File {
|
func exportConfig() File {
|
||||||
|
// update columns param from working config
|
||||||
|
Update("columns", ColumnsString())
|
||||||
|
|
||||||
lock.RLock()
|
lock.RLock()
|
||||||
defer lock.RUnlock()
|
defer lock.RUnlock()
|
||||||
|
|
||||||
c := File{
|
c := File{
|
||||||
Options: make(map[string]string),
|
Options: make(map[string]string),
|
||||||
Toggles: make(map[string]bool),
|
Toggles: make(map[string]bool),
|
||||||
Widgets: make([]Widget, len(GlobalWidgets)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range GlobalParams {
|
for _, p := range GlobalParams {
|
||||||
|
@ -35,9 +36,6 @@ func exportConfig() File {
|
||||||
for _, sw := range GlobalSwitches {
|
for _, sw := range GlobalSwitches {
|
||||||
c.Toggles[sw.Key] = sw.Val
|
c.Toggles[sw.Key] = sw.Val
|
||||||
}
|
}
|
||||||
for n, w := range GlobalWidgets {
|
|
||||||
c.Widgets[n] = *w
|
|
||||||
}
|
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@ -54,15 +52,21 @@ func Read() error {
|
||||||
if _, err := toml.DecodeFile(path, &config); err != nil {
|
if _, err := toml.DecodeFile(path, &config); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range config.Options {
|
for k, v := range config.Options {
|
||||||
Update(k, v)
|
Update(k, v)
|
||||||
}
|
}
|
||||||
for k, v := range config.Toggles {
|
for k, v := range config.Toggles {
|
||||||
UpdateSwitch(k, v)
|
UpdateSwitch(k, v)
|
||||||
}
|
}
|
||||||
for _, w := range config.Widgets {
|
|
||||||
UpdateWidget(strings.ToLower(w.Name), w.Enabled)
|
// set working column config, if provided
|
||||||
|
colStr := GetVal("columns")
|
||||||
|
if len(colStr) > 0 {
|
||||||
|
var colNames []string
|
||||||
|
for _, s := range strings.Split(colStr, ",") {
|
||||||
|
colNames = append(colNames, strings.TrimSpace(s))
|
||||||
|
}
|
||||||
|
SetColumns(colNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
var (
|
var (
|
||||||
GlobalParams []*Param
|
GlobalParams []*Param
|
||||||
GlobalSwitches []*Switch
|
GlobalSwitches []*Switch
|
||||||
GlobalWidgets []*Widget
|
GlobalColumns []*Column
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
log = logging.Init()
|
log = logging.Init()
|
||||||
)
|
)
|
||||||
|
@ -19,15 +19,16 @@ var (
|
||||||
func Init() {
|
func Init() {
|
||||||
for _, p := range defaultParams {
|
for _, p := range defaultParams {
|
||||||
GlobalParams = append(GlobalParams, p)
|
GlobalParams = append(GlobalParams, p)
|
||||||
log.Infof("loaded default config param: %s: %s", quote(p.Key), quote(p.Val))
|
log.Infof("loaded default config param [%s]: %s", quote(p.Key), quote(p.Val))
|
||||||
}
|
}
|
||||||
for _, s := range defaultSwitches {
|
for _, s := range defaultSwitches {
|
||||||
GlobalSwitches = append(GlobalSwitches, s)
|
GlobalSwitches = append(GlobalSwitches, s)
|
||||||
log.Infof("loaded default config switch: %s: %t", quote(s.Key), s.Val)
|
log.Infof("loaded default config switch [%s]: %t", quote(s.Key), s.Val)
|
||||||
}
|
}
|
||||||
for _, w := range defaultWidgets {
|
for _, c := range defaultColumns {
|
||||||
GlobalWidgets = append(GlobalWidgets, w)
|
x := c
|
||||||
log.Infof("loaded default widget: %s: %t", quote(w.Name), w.Enabled)
|
GlobalColumns = append(GlobalColumns, &x)
|
||||||
|
log.Infof("loaded default widget config [%s]: %t", quote(x.Name), x.Enabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,11 @@ var defaultParams = []*Param{
|
||||||
Val: "sh",
|
Val: "sh",
|
||||||
Label: "Shell",
|
Label: "Shell",
|
||||||
},
|
},
|
||||||
|
&Param{
|
||||||
|
Key: "columns",
|
||||||
|
Val: "status,name,id,cpu,mem,net,io,pids",
|
||||||
|
Label: "Enabled Columns",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type Param struct {
|
type Param struct {
|
||||||
|
|
122
config/widget.go
122
config/widget.go
|
@ -1,122 +0,0 @@
|
||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// defaults
|
|
||||||
var defaultWidgets = []*Widget{
|
|
||||||
&Widget{
|
|
||||||
Name: "status",
|
|
||||||
Enabled: true,
|
|
||||||
},
|
|
||||||
&Widget{
|
|
||||||
Name: "name",
|
|
||||||
Enabled: true,
|
|
||||||
},
|
|
||||||
&Widget{
|
|
||||||
Name: "id",
|
|
||||||
Enabled: true,
|
|
||||||
},
|
|
||||||
&Widget{
|
|
||||||
Name: "cpu",
|
|
||||||
Enabled: true,
|
|
||||||
},
|
|
||||||
&Widget{
|
|
||||||
Name: "mem",
|
|
||||||
Enabled: true,
|
|
||||||
},
|
|
||||||
&Widget{
|
|
||||||
Name: "net",
|
|
||||||
Enabled: true,
|
|
||||||
},
|
|
||||||
&Widget{
|
|
||||||
Name: "io",
|
|
||||||
Enabled: true,
|
|
||||||
},
|
|
||||||
&Widget{
|
|
||||||
Name: "pids",
|
|
||||||
Enabled: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
type Widget struct {
|
|
||||||
Name string
|
|
||||||
Enabled bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWidget returns a Widget by name
|
|
||||||
func GetWidget(name string) *Widget {
|
|
||||||
lock.RLock()
|
|
||||||
defer lock.RUnlock()
|
|
||||||
|
|
||||||
for _, w := range GlobalWidgets {
|
|
||||||
if w.Name == name {
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Errorf("widget name not found: %s", name)
|
|
||||||
return &Widget{} // default
|
|
||||||
}
|
|
||||||
|
|
||||||
// Widgets returns a copy of all configurable Widgets, in order
|
|
||||||
func Widgets() []Widget {
|
|
||||||
a := make([]Widget, len(GlobalWidgets))
|
|
||||||
|
|
||||||
lock.RLock()
|
|
||||||
defer lock.RUnlock()
|
|
||||||
|
|
||||||
for n, w := range GlobalWidgets {
|
|
||||||
a[n] = *w
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnabledWidgets returns an ordered array of enabled widget names
|
|
||||||
func EnabledWidgets() (a []string) {
|
|
||||||
for _, w := range Widgets() {
|
|
||||||
if w.Enabled {
|
|
||||||
a = append(a, w.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdateWidget(name string, enabled bool) {
|
|
||||||
w := GetWidget(name)
|
|
||||||
oldVal := w.Enabled
|
|
||||||
log.Noticef("config change [%s-enabled]: %t -> %t", name, oldVal, enabled)
|
|
||||||
|
|
||||||
lock.Lock()
|
|
||||||
defer lock.Unlock()
|
|
||||||
w.Enabled = enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToggleWidgetEnabled(name string) {
|
|
||||||
w := GetWidget(name)
|
|
||||||
newVal := !w.Enabled
|
|
||||||
log.Noticef("config change [%s-enabled]: %t -> %t", name, w.Enabled, newVal)
|
|
||||||
|
|
||||||
lock.Lock()
|
|
||||||
defer lock.Unlock()
|
|
||||||
w.Enabled = newVal
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateWidgets replaces existing ordered widgets with those provided
|
|
||||||
func UpdateWidgets(newWidgets []Widget) {
|
|
||||||
oldOrder := widgetNames()
|
|
||||||
lock.Lock()
|
|
||||||
for n, w := range newWidgets {
|
|
||||||
GlobalWidgets[n] = &w
|
|
||||||
}
|
|
||||||
lock.Unlock()
|
|
||||||
log.Noticef("config change [widget-order]: %s -> %s", oldOrder, widgetNames())
|
|
||||||
}
|
|
||||||
|
|
||||||
func widgetNames() string {
|
|
||||||
a := make([]string, len(GlobalWidgets))
|
|
||||||
for n, w := range Widgets() {
|
|
||||||
a[n] = w.Name
|
|
||||||
}
|
|
||||||
return strings.Join(a, ", ")
|
|
||||||
}
|
|
Loading…
Reference in New Issue