Skip to content

Commit 8e8ca84

Browse files
ribasushiStebalien
authored andcommitted
Add simple byte-counting export progress-bar
1 parent 8695ab8 commit 8e8ca84

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

core/commands/dag/dag.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package dagcmd
22

33
import (
4+
"errors"
45
"fmt"
56
"io"
67
"math"
8+
"os"
79
"strings"
10+
"time"
811

912
"github.com/ipfs/go-ipfs/core/commands/cmdenv"
1013
"github.com/ipfs/go-ipfs/core/coredag"
@@ -23,6 +26,12 @@ import (
2326
//gipfree "github.com/ipld/go-ipld-prime/impl/free"
2427
//gipselector "github.com/ipld/go-ipld-prime/traversal/selector"
2528
//gipselectorbuilder "github.com/ipld/go-ipld-prime/traversal/selector/builder"
29+
30+
"gopkg.in/cheggaaa/pb.v1"
31+
)
32+
33+
const (
34+
progressOptionName = "progress"
2635
)
2736

2837
var DagCmd = &cmds.Command{
@@ -261,6 +270,9 @@ The output of blocks happens in strict DAG-traversal, first-seen, order.
261270
Arguments: []cmds.Argument{
262271
cmds.StringArg("root", true, false, "CID of a root to recursively export").EnableStdin(),
263272
},
273+
Options: []cmds.Option{
274+
cmds.BoolOption(progressOptionName, "p", "Display progress on CLI. Defaults to true when STDERR is a TTY."),
275+
},
264276
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
265277

266278
c, err := cid.Decode(req.Arguments[0])
@@ -334,4 +346,61 @@ The output of blocks happens in strict DAG-traversal, first-seen, order.
334346

335347
return err
336348
},
349+
PostRun: cmds.PostRunMap{
350+
cmds.CLI: func(res cmds.Response, re cmds.ResponseEmitter) error {
351+
352+
var showProgress bool
353+
val, specified := res.Request().Options[progressOptionName]
354+
if !specified {
355+
// default based on TTY availability
356+
errStat, _ := os.Stderr.Stat()
357+
if 0 != (errStat.Mode() & os.ModeCharDevice) {
358+
showProgress = true
359+
}
360+
} else if val.(bool) {
361+
showProgress = true
362+
}
363+
364+
// simple passthrough, no progress
365+
if !showProgress {
366+
return cmds.Copy(re, res)
367+
}
368+
369+
bar := pb.New64(0).SetUnits(pb.U_BYTES)
370+
bar.Output = os.Stderr
371+
bar.ShowSpeed = true
372+
bar.ShowElapsedTime = true
373+
bar.RefreshRate = 500 * time.Millisecond
374+
bar.Start()
375+
376+
var processedOneResponse bool
377+
for {
378+
v, err := res.Next()
379+
if err == io.EOF {
380+
381+
// We only write the final bar update on success
382+
// On error it looks too weird
383+
bar.Finish()
384+
385+
return re.Close()
386+
} else if err != nil {
387+
return re.CloseWithError(err)
388+
} else if processedOneResponse {
389+
return re.CloseWithError(errors.New("unexpected multipart response during emit, please file a bugreport"))
390+
}
391+
392+
r, ok := v.(io.Reader)
393+
if !ok {
394+
// some sort of encoded response, this should not be happening
395+
return errors.New("unexpected non-stream passed to PostRun: please file a bugreport")
396+
}
397+
398+
processedOneResponse = true
399+
400+
if err := re.Emit(bar.NewProxyReader(r)); err != nil {
401+
return err
402+
}
403+
}
404+
},
405+
},
337406
}

0 commit comments

Comments
 (0)