From 26166489fd3c2c51f9b9b33902e8f1bb1eb7c590 Mon Sep 17 00:00:00 2001 From: yo Date: Sat, 18 Dec 2021 15:22:55 +0100 Subject: [PATCH] Add pretty display for struct array --- cmd/list.go | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 1 deletion(-) diff --git a/cmd/list.go b/cmd/list.go index 116d9b3..23a4578 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -4,6 +4,7 @@ import ( "os" "fmt" "log" + "reflect" "io/ioutil" "gocage/jail" "encoding/json" @@ -13,19 +14,147 @@ import ( var gJails []Jail +/* Pretty display of jails field + Fields to show are given in a string array parameter + Ex. : displayJails(["Name", "JID", "RootPath"]) +*/ +func displayStructFields(jails []Jail, valsToDisplay []string) { + /* A line is defined by : + Nr of fields + For each field : + Its name + Its max length + Its value + */ + type Field struct { + Name string + MaxLen int + Value string + } + + type Line []Field + + type Output []Line + var out Output + + //fmt.Printf("%d fields in a %d items structure\n", len(valsToDisplay), len(jails)) + + // Browse structure to get max length and values + for _, j := range jails { + // Have to use a pointer, else reflect.Value.Elem() will panic : https://pkg.go.dev/reflect#Value.Elem + tj := &j + + line := make([]Field, len(valsToDisplay)) + for i, f := range valsToDisplay { + a := reflect.ValueOf(&tj).Elem() + //fmt.Printf("Struct : %s, Champ : %s\n", a.String(), f) + //fmt.Printf("%v", a.Elem().FieldByName(f).Interface()) + field := Field { + Name: f, + // For now this just contains this item length, will adjust later + MaxLen: len(fmt.Sprintf("%v", a.Elem().FieldByName(f).Interface())), + Value: fmt.Sprintf("%v", a.Elem().FieldByName(f).Interface()), + } + line[i] = field + + } + out = append(out, line) + } + + // Get real maximum length + maxlen := make([]int, len(valsToDisplay)) + for i := 0; i< len(valsToDisplay); i++ { + maxlen[i] = 0 + } + for _, l := range out { + for i, f := range l { + if f.MaxLen > maxlen[i] { + maxlen[i] = f.MaxLen + } + } + } + + // Align maxlen to the real maximum length + for io, l := range out { + for ii, _ := range l { + // We need to access slice by index if we want to modify content + out[io][ii].MaxLen = maxlen[ii] + } + } + + totalLen := 0 + // Add separator and 2 blank spaces + for _, f := range out[0] { + totalLen += f.MaxLen + 3 + } + // Then add starting delimiter + totalLen += 1 + + Debug := false + if Debug == true { + for _, f := range out[0] { + fmt.Printf("%s max length : %d\n", f.Name, f.MaxLen) + } + } + + // Lets draw things on the screen! + // First, headers + for i := 0; i < totalLen ; i++ { + fmt.Printf("-") + } + fmt.Printf("\n") + + for i, f := range out[0] { + if i == 0 { + fmt.Printf("|") + } + fmt.Printf(" %s", f.Name) + for i := len(f.Name)+1 ; i < f.MaxLen+1 ; i++ { + fmt.Printf(" ") + } + fmt.Printf(" |") + } + fmt.Printf("\n") + for i := 0; i < totalLen ; i++ { + fmt.Printf("-") + } + fmt.Printf("\n") + + // Then display data + for _, l := range out { + for i, f := range l { + if i == 0 { + fmt.Printf("|") + } + fmt.Printf(" %s", f.Value) + for i := len(f.Value)+1 ; i < f.MaxLen+1 ; i++ { + fmt.Printf(" ") + } + fmt.Printf(" |") + } + fmt.Printf("\n") + } + for i := 0; i < totalLen ; i++ { + fmt.Printf("-") + } + fmt.Printf("\n") +} func listJails(args []string) { for _, d := range viper.GetStringSlice("datastore") { listJailsFromDatastore(d) } - for _, j := range (gJails) { + displayStructFields(gJails, []string{"JID", "Name", "RootPath"}) + +/* for _, j := range (gJails) { if j.Running { fmt.Printf("%d ; %s ; %s ; %s\n", j.JID, j.Name, j.Config.Ip4_addr, j.Config.Release) } else { fmt.Printf(" ; %s ; %s ; %s\n", j.Name, j.Config.Ip4_addr, j.Config.Release) } } +*/ }