Backend: - Add registry_address configuration API (GET/POST) - Add tar image upload with OCI and Docker format support - Add image download with streaming optimization - Fix blob download using c.Send (Fiber v3 SendStream bug) - Add registry_address prefix stripping for all OCI v2 endpoints - Add AGENTS.md for project documentation Frontend: - Add settings store with Snackbar notifications - Add image upload dialog with progress bar - Add download state tracking with multi-stage feedback - Replace alert() with MUI Snackbar messages - Display image names without registry_address prefix 🤖 Generated with [Qoder](https://qoder.com)
126 lines
2.7 KiB
Go
126 lines
2.7 KiB
Go
package tool
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/jedib0t/go-pretty/v6/table"
|
|
)
|
|
|
|
func TablePrinter(data any, writers ...io.Writer) {
|
|
var w io.Writer = os.Stdout
|
|
if len(writers) > 0 && writers[0] != nil {
|
|
w = writers[0]
|
|
}
|
|
|
|
t := table.NewWriter()
|
|
structPrinter(t, "", data)
|
|
_, _ = fmt.Fprintln(w, t.Render())
|
|
}
|
|
|
|
func structPrinter(w table.Writer, prefix string, item any) {
|
|
Start:
|
|
rv := reflect.ValueOf(item)
|
|
if rv.IsZero() {
|
|
return
|
|
}
|
|
|
|
for rv.Type().Kind() == reflect.Pointer {
|
|
rv = rv.Elem()
|
|
}
|
|
|
|
switch rv.Type().Kind() {
|
|
case reflect.Invalid,
|
|
reflect.Uintptr,
|
|
reflect.Chan,
|
|
reflect.Func,
|
|
reflect.UnsafePointer:
|
|
case reflect.Bool,
|
|
reflect.Int,
|
|
reflect.Int8,
|
|
reflect.Int16,
|
|
reflect.Int32,
|
|
reflect.Int64,
|
|
reflect.Uint,
|
|
reflect.Uint8,
|
|
reflect.Uint16,
|
|
reflect.Uint32,
|
|
reflect.Uint64,
|
|
reflect.Float32,
|
|
reflect.Float64,
|
|
reflect.Complex64,
|
|
reflect.Complex128,
|
|
reflect.Interface:
|
|
w.AppendRow(table.Row{strings.TrimPrefix(prefix, "."), rv.Interface()})
|
|
case reflect.String:
|
|
val := rv.String()
|
|
if len(val) <= 160 {
|
|
w.AppendRow(table.Row{strings.TrimPrefix(prefix, "."), val})
|
|
return
|
|
}
|
|
|
|
w.AppendRow(table.Row{strings.TrimPrefix(prefix, "."), val[0:64] + "..." + val[len(val)-64:]})
|
|
case reflect.Array, reflect.Slice:
|
|
for i := 0; i < rv.Len(); i++ {
|
|
p := strings.Join([]string{prefix, fmt.Sprintf("[%d]", i)}, ".")
|
|
structPrinter(w, p, rv.Index(i).Interface())
|
|
}
|
|
case reflect.Map:
|
|
for _, k := range rv.MapKeys() {
|
|
structPrinter(w, fmt.Sprintf("%s.{%v}", prefix, k), rv.MapIndex(k).Interface())
|
|
}
|
|
case reflect.Pointer:
|
|
goto Start
|
|
case reflect.Struct:
|
|
for i := 0; i < rv.NumField(); i++ {
|
|
p := fmt.Sprintf("%s.%s", prefix, rv.Type().Field(i).Name)
|
|
field := rv.Field(i)
|
|
|
|
//log.Debug("TablePrinter: prefix: %s, field: %v", p, rv.Field(i))
|
|
|
|
if !field.CanInterface() {
|
|
return
|
|
}
|
|
|
|
structPrinter(w, p, field.Interface())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TableMapPrinter(data []byte) {
|
|
m := make(map[string]any)
|
|
if err := json.Unmarshal(data, &m); err != nil {
|
|
log.Printf("[E] unmarshal json err: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
t := table.NewWriter()
|
|
addRow(t, "", m)
|
|
fmt.Println(t.Render())
|
|
}
|
|
|
|
func addRow(w table.Writer, prefix string, m any) {
|
|
rv := reflect.ValueOf(m)
|
|
switch rv.Type().Kind() {
|
|
case reflect.Map:
|
|
for _, k := range rv.MapKeys() {
|
|
key := k.String()
|
|
if prefix != "" {
|
|
key = strings.Join([]string{prefix, k.String()}, ".")
|
|
}
|
|
addRow(w, key, rv.MapIndex(k).Interface())
|
|
}
|
|
case reflect.Slice, reflect.Array:
|
|
for i := 0; i < rv.Len(); i++ {
|
|
addRow(w, fmt.Sprintf("%s[%d]", prefix, i), rv.Index(i).Interface())
|
|
}
|
|
default:
|
|
w.AppendRow(table.Row{prefix, m})
|
|
}
|
|
}
|