@cryptotaxi247 / kubo / commits / 4772ca613

Add simple byte-counting export progress-bar

Peter Rabbitson committed Mar 26, 2020 at 16:35 UTC 4772ca6134d77b77b59e60a36297badcdab3a4e8
1 file changed +69
core/commands/dag/dag.go
+69
@@ -1,10 +1,13 @@
1 package dagcmd
2
3 import (
4 + "errors"
5 "fmt"
6 "io"
7 "math"
8 + "os"
9 "strings"
10 + "time"
11
12 "github.com/ipfs/go-ipfs/core/commands/cmdenv"
13 "github.com/ipfs/go-ipfs/core/coredag"
@@ -23,6 +26,12 @@ import (
26 //gipfree "github.com/ipld/go-ipld-prime/impl/free"
27 //gipselector "github.com/ipld/go-ipld-prime/traversal/selector"
28 //gipselectorbuilder "github.com/ipld/go-ipld-prime/traversal/selector/builder"
29 +
30 + "gopkg.in/cheggaaa/pb.v1"
31 +)
32 +
33 +const (
34 + progressOptionName = "progress"
35 )
36
37 var DagCmd = &cmds.Command{
@@ -261,6 +270,9 @@ The output of blocks happens in strict DAG-traversal, first-seen, order.
270 Arguments: []cmds.Argument{
271 cmds.StringArg("root", true, false, "CID of a root to recursively export").EnableStdin(),
272 },
273 + Options: []cmds.Option{
274 + cmds.BoolOption(progressOptionName, "p", "Display progress on CLI. Defaults to true when STDERR is a TTY."),
275 + },
276 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
277
278 c, err := cid.Decode(req.Arguments[0])
@@ -334,4 +346,61 @@ The output of blocks happens in strict DAG-traversal, first-seen, order.
346
347 return err
348 },
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 + },
406 }