Merge pull request #2817 from filecoin-project/feat/improve-client-listdeals
client cli: Improve list-deals output
This commit is contained in:
commit
b264cd6c4a
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@ -81,7 +80,7 @@ func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n,
|
|||||||
s, err := miner.SectorsList(ctx) // Note - the test builder doesn't import genesis sectors into FSM
|
s, err := miner.SectorsList(ctx) // Note - the test builder doesn't import genesis sectors into FSM
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
fmt.Printf("Sectors: %d\n", len(s))
|
fmt.Printf("Sectors: %d\n", len(s))
|
||||||
if len(s) >= n + existing {
|
if len(s) >= n+existing {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
lapi "github.com/filecoin-project/lotus/api"
|
lapi "github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/lib/tablewriter"
|
||||||
)
|
)
|
||||||
|
|
||||||
var CidBaseFlag = cli.StringFlag{
|
var CidBaseFlag = cli.StringFlag{
|
||||||
@ -986,8 +987,8 @@ var clientListDeals = &cli.Command{
|
|||||||
|
|
||||||
color := cctx.Bool("color")
|
color := cctx.Bool("color")
|
||||||
|
|
||||||
w := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0)
|
|
||||||
if cctx.Bool("verbose") {
|
if cctx.Bool("verbose") {
|
||||||
|
w := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0)
|
||||||
fmt.Fprintf(w, "DealCid\tDealId\tProvider\tState\tOn Chain?\tSlashed?\tPieceCID\tSize\tPrice\tDuration\tMessage\n")
|
fmt.Fprintf(w, "DealCid\tDealId\tProvider\tState\tOn Chain?\tSlashed?\tPieceCID\tSize\tPrice\tDuration\tMessage\n")
|
||||||
for _, d := range deals {
|
for _, d := range deals {
|
||||||
onChain := "N"
|
onChain := "N"
|
||||||
@ -1003,8 +1004,19 @@ var clientListDeals = &cli.Command{
|
|||||||
price := types.FIL(types.BigMul(d.LocalDeal.PricePerEpoch, types.NewInt(d.LocalDeal.Duration)))
|
price := types.FIL(types.BigMul(d.LocalDeal.PricePerEpoch, types.NewInt(d.LocalDeal.Duration)))
|
||||||
fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%s\n", d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, dealStateString(color, d.LocalDeal.State), onChain, slashed, d.LocalDeal.PieceCID, types.SizeStr(types.NewInt(d.LocalDeal.Size)), price, d.LocalDeal.Duration, d.LocalDeal.Message)
|
fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%s\n", d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, dealStateString(color, d.LocalDeal.State), onChain, slashed, d.LocalDeal.PieceCID, types.SizeStr(types.NewInt(d.LocalDeal.Size)), price, d.LocalDeal.Duration, d.LocalDeal.Message)
|
||||||
}
|
}
|
||||||
|
return w.Flush()
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(w, "DealCid\tDealId\tProvider\tState\tOn Chain?\tSlashed?\tPieceCID\tSize\tPrice\tDuration\n")
|
w := tablewriter.New(tablewriter.Col("DealCid"),
|
||||||
|
tablewriter.Col("DealId"),
|
||||||
|
tablewriter.Col("Provider"),
|
||||||
|
tablewriter.Col("State"),
|
||||||
|
tablewriter.Col("On Chain?"),
|
||||||
|
tablewriter.Col("Slashed?"),
|
||||||
|
tablewriter.Col("PieceCID"),
|
||||||
|
tablewriter.Col("Size"),
|
||||||
|
tablewriter.Col("Price"),
|
||||||
|
tablewriter.Col("Duration"),
|
||||||
|
tablewriter.NewLineCol("Message"))
|
||||||
|
|
||||||
for _, d := range deals {
|
for _, d := range deals {
|
||||||
propcid := d.LocalDeal.ProposalCid.String()
|
propcid := d.LocalDeal.ProposalCid.String()
|
||||||
@ -1024,11 +1036,24 @@ var clientListDeals = &cli.Command{
|
|||||||
piece = "..." + piece[len(piece)-8:]
|
piece = "..." + piece[len(piece)-8:]
|
||||||
|
|
||||||
price := types.FIL(types.BigMul(d.LocalDeal.PricePerEpoch, types.NewInt(d.LocalDeal.Duration)))
|
price := types.FIL(types.BigMul(d.LocalDeal.PricePerEpoch, types.NewInt(d.LocalDeal.Duration)))
|
||||||
fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\n", propcid, d.LocalDeal.DealID, d.LocalDeal.Provider, dealStateString(color, d.LocalDeal.State), onChain, slashed, piece, types.SizeStr(types.NewInt(d.LocalDeal.Size)), price, d.LocalDeal.Duration)
|
|
||||||
|
w.Write(map[string]interface{}{
|
||||||
|
"DealCid": propcid,
|
||||||
|
"DealId": d.LocalDeal.DealID,
|
||||||
|
"Provider": d.LocalDeal.Provider,
|
||||||
|
"State": dealStateString(color, d.LocalDeal.State),
|
||||||
|
"On Chain?": onChain,
|
||||||
|
"Slashed?": slashed,
|
||||||
|
"PieceCID": piece,
|
||||||
|
"Size": types.SizeStr(types.NewInt(d.LocalDeal.Size)),
|
||||||
|
"Price": price,
|
||||||
|
"Duration": d.LocalDeal.Duration,
|
||||||
|
"Message": d.LocalDeal.Message,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return w.Flush(os.Stdout)
|
||||||
}
|
}
|
||||||
return w.Flush()
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
go.mod
1
go.mod
@ -11,6 +11,7 @@ require (
|
|||||||
github.com/GeertJohan/go.rice v1.0.0
|
github.com/GeertJohan/go.rice v1.0.0
|
||||||
github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee
|
github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee
|
||||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
|
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
|
||||||
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
|
||||||
github.com/coreos/go-systemd/v22 v22.0.0
|
github.com/coreos/go-systemd/v22 v22.0.0
|
||||||
github.com/dgraph-io/badger/v2 v2.0.3
|
github.com/dgraph-io/badger/v2 v2.0.3
|
||||||
github.com/docker/go-units v0.4.0
|
github.com/docker/go-units v0.4.0
|
||||||
|
2
go.sum
2
go.sum
@ -58,6 +58,8 @@ github.com/Stebalien/go-bitfield v0.0.0-20180330043415-076a62f9ce6e/go.mod h1:3o
|
|||||||
github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo=
|
github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo=
|
||||||
github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s=
|
github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s=
|
||||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||||
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
|
||||||
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
||||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||||
github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=
|
github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=
|
||||||
|
34
lib/tablewriter/tablewiter_test.go
Normal file
34
lib/tablewriter/tablewiter_test.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package tablewriter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTableWriter(t *testing.T) {
|
||||||
|
tw := New(Col("C1"), Col("X"), Col("C333"), NewLineCol("Thing"))
|
||||||
|
tw.Write(map[string]interface{}{
|
||||||
|
"C1": "234",
|
||||||
|
"C333": "ou",
|
||||||
|
})
|
||||||
|
tw.Write(map[string]interface{}{
|
||||||
|
"C1": "23uieui4",
|
||||||
|
"C333": "ou",
|
||||||
|
"X": color.GreenString("#"),
|
||||||
|
"Thing": "a very long thing, annoyingly so",
|
||||||
|
})
|
||||||
|
tw.Write(map[string]interface{}{
|
||||||
|
"C1": "ttttttttt",
|
||||||
|
"C333": "eui",
|
||||||
|
})
|
||||||
|
tw.Write(map[string]interface{}{
|
||||||
|
"C1": "1",
|
||||||
|
"C333": "2",
|
||||||
|
"SurpriseColumn": "42",
|
||||||
|
})
|
||||||
|
if err := tw.Flush(os.Stdout); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
129
lib/tablewriter/tablewriter.go
Normal file
129
lib/tablewriter/tablewriter.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package tablewriter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/acarl005/stripansi"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Column struct {
|
||||||
|
Name string
|
||||||
|
SeparateLine bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type TableWriter struct {
|
||||||
|
cols []Column
|
||||||
|
rows []map[int]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Col(name string) Column {
|
||||||
|
return Column{
|
||||||
|
Name: name,
|
||||||
|
SeparateLine: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLineCol(name string) Column {
|
||||||
|
return Column{
|
||||||
|
Name: name,
|
||||||
|
SeparateLine: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlike text/tabwriter, this works with CLI escape codes, and allows for info
|
||||||
|
// in separate lines
|
||||||
|
func New(cols ...Column) *TableWriter {
|
||||||
|
return &TableWriter{
|
||||||
|
cols: cols,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *TableWriter) Write(r map[string]interface{}) {
|
||||||
|
// this can cause columns to be out of order, but will at least work
|
||||||
|
byColID := map[int]string{}
|
||||||
|
|
||||||
|
cloop:
|
||||||
|
for col, val := range r {
|
||||||
|
for i, column := range w.cols {
|
||||||
|
if column.Name == col {
|
||||||
|
byColID[i] = fmt.Sprint(val)
|
||||||
|
continue cloop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byColID[len(w.cols)] = fmt.Sprint(val)
|
||||||
|
w.cols = append(w.cols, Column{
|
||||||
|
Name: col,
|
||||||
|
SeparateLine: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
w.rows = append(w.rows, byColID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *TableWriter) Flush(out io.Writer) error {
|
||||||
|
colLengths := make([]int, len(w.cols))
|
||||||
|
|
||||||
|
header := map[int]string{}
|
||||||
|
for i, col := range w.cols {
|
||||||
|
if col.SeparateLine {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
header[i] = col.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
w.rows = append([]map[int]string{header}, w.rows...)
|
||||||
|
|
||||||
|
for col := range w.cols {
|
||||||
|
for _, row := range w.rows {
|
||||||
|
val, found := row[col]
|
||||||
|
if !found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if cliStringLength(val) > colLengths[col] {
|
||||||
|
colLengths[col] = cliStringLength(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, row := range w.rows {
|
||||||
|
cols := make([]string, len(w.cols))
|
||||||
|
|
||||||
|
for ci, col := range w.cols {
|
||||||
|
e, _ := row[ci]
|
||||||
|
pad := colLengths[ci] - cliStringLength(e) + 2
|
||||||
|
if !col.SeparateLine {
|
||||||
|
e = e + strings.Repeat(" ", pad)
|
||||||
|
if _, err := fmt.Fprint(out, e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cols[ci] = e
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := fmt.Fprintln(out); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for ci, col := range w.cols {
|
||||||
|
if !col.SeparateLine || len(cols[ci]) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := fmt.Fprintf(out, " %s: %s\n", col.Name, cols[ci]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cliStringLength(s string) (n int) {
|
||||||
|
return utf8.RuneCountInString(stripansi.Strip(s))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user