Skip to content
This repository has been archived by the owner on Feb 17, 2024. It is now read-only.

Commit

Permalink
Merge pull request #31 from stealthrocket/sort-get-output
Browse files Browse the repository at this point in the history
order table output of get command
  • Loading branch information
achille-roussel committed May 30, 2023
2 parents 787a667 + 117f71e commit 07387b8
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 91 deletions.
127 changes: 71 additions & 56 deletions internal/cmd/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ Examples:
"digest": "sha256:9d7b7563baf3702cf24ed3688dc9a58faef2d0ac586041cb2dc95df919f5e5f2",
"size": 7150231,
"annotations": {
"timecraft.module.name": "app.wasm",
"timecraft.object.created-at": "2023-05-28T21:52:26Z"
"timecraft.module.name": "app.wasm"
}
}
Expand Down Expand Up @@ -146,88 +145,104 @@ Did you mean?%s`, resourceTypeLookup, joinResourceTypes(matchingResources, "\n
return err
}

func getConfigs(ctx context.Context, w io.Writer, r *timemachine.Registry) stream.WriteCloser[*format.Descriptor] {
func getConfigs(ctx context.Context, w io.Writer, reg *timemachine.Registry) stream.WriteCloser[*format.Descriptor] {
type config struct {
ID string `text:"CONFIG ID"`
Runtime string `text:"RUNTIME"`
Modules int `text:"MODULES"`
Size human.Bytes `text:"SIZE"`
}
return newDescTableWriter(w, func(desc *format.Descriptor) (config, error) {
c, err := r.LookupConfig(ctx, desc.Digest)
if err != nil {
return config{}, err
}
r, err := r.LookupRuntime(ctx, c.Runtime.Digest)
if err != nil {
return config{}, err
}
return config{
ID: desc.Digest.Short(),
Runtime: r.Runtime + " (" + r.Version + ")",
Modules: len(c.Modules),
Size: human.Bytes(desc.Size),
}, nil
})
return newDescTableWriter(w,
func(c1, c2 config) bool {
return c1.ID < c2.ID
},
func(desc *format.Descriptor) (config, error) {
c, err := reg.LookupConfig(ctx, desc.Digest)
if err != nil {
return config{}, err
}
r, err := reg.LookupRuntime(ctx, c.Runtime.Digest)
if err != nil {
return config{}, err
}
return config{
ID: desc.Digest.Short(),
Runtime: r.Runtime + " (" + r.Version + ")",
Modules: len(c.Modules),
Size: human.Bytes(desc.Size),
}, nil
})
}

func getModules(ctx context.Context, w io.Writer, r *timemachine.Registry) stream.WriteCloser[*format.Descriptor] {
func getModules(ctx context.Context, w io.Writer, reg *timemachine.Registry) stream.WriteCloser[*format.Descriptor] {
type module struct {
ID string `text:"MODULE ID"`
Name string `text:"MODULE NAME"`
Size human.Bytes `text:"SIZE"`
}
return newDescTableWriter(w, func(desc *format.Descriptor) (module, error) {
name := desc.Annotations["timecraft.module.name"]
if name == "" {
name = "(none)"
}
return module{
ID: desc.Digest.Short(),
Name: name,
Size: human.Bytes(desc.Size),
}, nil
})
return newDescTableWriter(w,
func(m1, m2 module) bool {
return m1.ID < m2.ID
},
func(desc *format.Descriptor) (module, error) {
name := desc.Annotations["timecraft.module.name"]
if name == "" {
name = "(none)"
}
return module{
ID: desc.Digest.Short(),
Name: name,
Size: human.Bytes(desc.Size),
}, nil
})
}

func getProcesses(ctx context.Context, w io.Writer, r *timemachine.Registry) stream.WriteCloser[*format.Descriptor] {
func getProcesses(ctx context.Context, w io.Writer, reg *timemachine.Registry) stream.WriteCloser[*format.Descriptor] {
type process struct {
ID format.UUID `text:"PROCESS ID"`
StartTime human.Time `text:"STARTED"`
}
return newDescTableWriter(w, func(desc *format.Descriptor) (process, error) {
p, err := r.LookupProcess(ctx, desc.Digest)
if err != nil {
return process{}, err
}
return process{
ID: p.ID,
StartTime: human.Time(p.StartTime),
}, nil
})
return newDescTableWriter(w,
func(p1, p2 process) bool {
return time.Time(p1.StartTime).Before(time.Time(p2.StartTime))
},
func(desc *format.Descriptor) (process, error) {
p, err := reg.LookupProcess(ctx, desc.Digest)
if err != nil {
return process{}, err
}
return process{
ID: p.ID,
StartTime: human.Time(p.StartTime),
}, nil
})
}

func getRuntimes(ctx context.Context, w io.Writer, r *timemachine.Registry) stream.WriteCloser[*format.Descriptor] {
func getRuntimes(ctx context.Context, w io.Writer, reg *timemachine.Registry) stream.WriteCloser[*format.Descriptor] {
type runtime struct {
ID string `text:"RUNTIME ID"`
Runtime string `text:"RUNTIME NAME"`
Version string `text:"VERSION"`
}
return newDescTableWriter(w, func(desc *format.Descriptor) (runtime, error) {
r, err := r.LookupRuntime(ctx, desc.Digest)
if err != nil {
return runtime{}, err
}
return runtime{
ID: desc.Digest.Short(),
Runtime: r.Runtime,
Version: r.Version,
}, nil
})
return newDescTableWriter(w,
func(r1, r2 runtime) bool {
return r1.ID < r2.ID
},
func(desc *format.Descriptor) (runtime, error) {
r, err := reg.LookupRuntime(ctx, desc.Digest)
if err != nil {
return runtime{}, err
}
return runtime{
ID: desc.Digest.Short(),
Runtime: r.Runtime,
Version: r.Version,
}, nil
})
}

func newDescTableWriter[T any](w io.Writer, conv func(*format.Descriptor) (T, error)) stream.WriteCloser[*format.Descriptor] {
tw := textprint.NewTableWriter[T](w)
func newDescTableWriter[T any](w io.Writer, orderBy func(T, T) bool, conv func(*format.Descriptor) (T, error)) stream.WriteCloser[*format.Descriptor] {
tw := textprint.NewTableWriter[T](w, textprint.OrderBy(orderBy))
cw := stream.ConvertWriter[T](tw, conv)
return stream.NewWriteCloser(cw, tw)
}
Expand Down
91 changes: 56 additions & 35 deletions internal/print/textprint/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,64 @@ import (
"text/tabwriter"

"github.com/stealthrocket/timecraft/internal/stream"
"golang.org/x/exp/slices"
)

func NewTableWriter[T any](w io.Writer) stream.WriteCloser[T] {
type TableOption[T any] func(*tableWriter[T])

func OrderBy[T any](f func(T, T) bool) TableOption[T] {
return func(t *tableWriter[T]) {
t.orderBy = f
}
}

func NewTableWriter[T any](w io.Writer, opts ...TableOption[T]) stream.WriteCloser[T] {
t := &tableWriter[T]{
writer: tabwriter.NewWriter(w, 0, 4, 2, ' ', 0),
valueOf: func(values []T, index int) reflect.Value {
return reflect.ValueOf(&values[index]).Elem()
},
output: w,
}
for _, opt := range opts {
opt(t)
}
return t
}

writeString := func(w io.Writer, s string) {
_, err := io.WriteString(w, s)
if err != nil {
panic(err)
}
type tableWriter[T any] struct {
output io.Writer
values []T
orderBy func(T, T) bool
}

func (t *tableWriter[T]) Write(values []T) (int, error) {
t.values = append(t.values, values...)
return len(values), nil
}

func (t *tableWriter[T]) Close() error {
tw := tabwriter.NewWriter(t.output, 0, 4, 2, ' ', 0)

if t.orderBy != nil {
slices.SortFunc(t.values, t.orderBy)
}

valueOf := func(values []T, index int) reflect.Value {
return reflect.ValueOf(&values[index]).Elem()
}

var v T
valueType := reflect.TypeOf(v)
if valueType.Kind() == reflect.Pointer {
valueType = valueType.Elem()
t.valueOf = func(values []T, index int) reflect.Value {
valueOf = func(values []T, index int) reflect.Value {
return reflect.ValueOf(values[index]).Elem()
}
}

var encoders []encodeFunc
for i, f := range reflect.VisibleFields(valueType) {
if i != 0 {
writeString(t.writer, "\t")
if _, err := io.WriteString(tw, "\t"); err != nil {
return err
}
}

name := f.Name
Expand All @@ -53,44 +82,36 @@ func NewTableWriter[T any](w io.Writer) stream.WriteCloser[T] {
continue
}

writeString(t.writer, name)
t.encoders = append(t.encoders, encodeFuncOfStructField(f.Type, f.Index))
if _, err := io.WriteString(tw, name); err != nil {
return err
}
encoders = append(encoders, encodeFuncOfStructField(f.Type, f.Index))
}

writeString(t.writer, "\n")
return t
}

type tableWriter[T any] struct {
writer *tabwriter.Writer
encoders []encodeFunc
valueOf func([]T, int) reflect.Value
}
if _, err := io.WriteString(tw, "\n"); err != nil {
return err
}

func (t *tableWriter[T]) Write(values []T) (int, error) {
for n := range values {
v := t.valueOf(values, n)
w := io.Writer(t.writer)
for n := range t.values {
v := valueOf(t.values, n)
w := io.Writer(tw)

for i, enc := range t.encoders {
for i, enc := range encoders {
if i != 0 {
_, err := io.WriteString(w, "\t")
if err != nil {
return n, err
return err
}
}
if err := enc(w, v); err != nil {
return n, err
return err
}
}

if _, err := io.WriteString(w, "\n"); err != nil {
return n, err
return err
}
}
return len(values), nil
}

func (t *tableWriter[T]) Close() error {
return t.writer.Flush()
return tw.Flush()
}

0 comments on commit 07387b8

Please sign in to comment.