Skip to content

Commit

Permalink
Add simple byte-counting export progress
Browse files Browse the repository at this point in the history
  • Loading branch information
ribasushi committed Mar 26, 2020
1 parent 210bb66 commit 31f8f54
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 105 deletions.
75 changes: 75 additions & 0 deletions core/commands/dag/dag.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package dagcmd

import (
"bytes"
"errors"
"fmt"
"io"
"math"
"os"
"strings"

"github.com/ipfs/go-ipfs/core/commands/cmdenv"
Expand All @@ -25,6 +28,10 @@ import (
//gipselectorbuilder "github.com/ipld/go-ipld-prime/traversal/selector/builder"
)

const (
progressOptionName = "progress"
)

var DagCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Interact with ipld dag objects.",
Expand Down Expand Up @@ -261,6 +268,9 @@ The output of blocks happens in strict DAG-traversal, first-seen, order.
Arguments: []cmds.Argument{
cmds.StringArg("root", true, false, "Expression evaluting to a single root of a dag to export").EnableStdin(),
},
Options: []cmds.Option{
cmds.BoolOption(progressOptionName, "p", "Display progress on CLI. Defaults to true when STDERR is a TTY."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {

c, err := cid.Decode(req.Arguments[0])
Expand Down Expand Up @@ -347,4 +357,69 @@ The output of blocks happens in strict DAG-traversal, first-seen, order.

return <-errCh
},
PostRun: cmds.PostRunMap{
cmds.CLI: func(res cmds.Response, re cmds.ResponseEmitter) error {

var showProgress bool
val, specified := res.Request().Options[progressOptionName]
if !specified {
// default based on TTY availability
errStat, _ := os.Stderr.Stat()
if 0 != (errStat.Mode() & os.ModeCharDevice) {
showProgress = true
}
} else if val.(bool) {
showProgress = true
}

// simple passthrough
if !showProgress {
return cmds.Copy(re, res)
}

// We will be supplied a reader, simply print out how many bytes were passed as a crude progress

var exportSize int64
buf := make([]byte, 4*1024*1024) // this does not mean "read 4MB at a time", rather make a buffer larger than any reasonable pipe size
defer func() {
if exportSize > 0 {
os.Stderr.WriteString("\n")
}
}()

for {
v, err := res.Next()
if err != nil {
return re.CloseWithError(err)
}

if r, ok := v.(io.Reader); ok {
// we got a reader passed as a response
// proxy it through with an increasing counter
for {
len, readErr := r.Read(buf)
if len > 0 {
if err := re.Emit(bytes.NewBuffer(buf[:len])); err != nil {
return err
}

exportSize += int64(len)
fmt.Fprintf(
os.Stderr,
"Exported .car size:\t%d\r",
exportSize,
)
}

if readErr != nil {
return re.CloseWithError(err)
}
}
} else {
// some sort of encoded response, this should not be happening
return errors.New("unexpected non-stream passed to PostRun: can't happen")
}
}
},
},
}
Loading

0 comments on commit 31f8f54

Please sign in to comment.