go-ipfs: github.com/ipfs/go-ipfs/core/commands/dag Index | Files

package dagcmd

import "github.com/ipfs/go-ipfs/core/commands/dag"

Index

Package Files

dag.go

Variables

var DagCmd = &cmds.Command{
    Helptext: cmds.HelpText{
        Tagline:          "Interact with ipld dag objects.",
        ShortDescription: "" /* 229 byte string literal not displayed */,
    },
    Subcommands: map[string]*cmds.Command{
        "put":     DagPutCmd,
        "get":     DagGetCmd,
        "resolve": DagResolveCmd,
        "import":  DagImportCmd,
        "export":  DagExportCmd,
    },
}
var DagExportCmd = &cmds.Command{
    Helptext: cmds.HelpText{
        Tagline:          "Streams the selected DAG as a .car stream on stdout.",
        ShortDescription: "" /* 232 byte string literal not displayed */,
    },
    Arguments: []cmds.Argument{
        cmds.StringArg("root", true, false, "CID of a root to recursively 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])
        if err != nil {
            return fmt.Errorf(
                "unable to parse root specification (currently only bare CIDs are supported): %s",
                err,
            )
        }

        node, err := cmdenv.GetNode(env)
        if err != nil {
            return err
        }

        pipeR, pipeW := io.Pipe()

        errCh := make(chan error, 2)
        go func() {
            defer func() {
                if err := pipeW.Close(); err != nil {
                    errCh <- fmt.Errorf("stream flush failed: %s", err)
                }
                close(errCh)
            }()

            if err := gocar.WriteCar(
                req.Context,
                mdag.NewSession(
                    req.Context,
                    node.DAG,
                ),
                []cid.Cid{c},
                pipeW,
            ); err != nil {
                errCh <- err
            }
        }()

        if err := res.Emit(pipeR); err != nil {
            pipeR.Close()
            return err
        }

        err = <-errCh

        if err != nil &&
            !node.IsOnline &&
            err == ipld.ErrNotFound {
            err = fmt.Errorf("%s (currently offline, perhaps retry after attaching to the network)", err)
        }

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

            var showProgress bool
            val, specified := res.Request().Options[progressOptionName]
            if !specified {

                errStat, _ := os.Stderr.Stat()
                if 0 != (errStat.Mode() & os.ModeCharDevice) {
                    showProgress = true
                }
            } else if val.(bool) {
                showProgress = true
            }

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

            bar := pb.New64(0).SetUnits(pb.U_BYTES)
            bar.Output = os.Stderr
            bar.ShowSpeed = true
            bar.ShowElapsedTime = true
            bar.RefreshRate = 500 * time.Millisecond
            bar.Start()

            var processedOneResponse bool
            for {
                v, err := res.Next()
                if err == io.EOF {

                    bar.Finish()

                    return re.Close()
                } else if err != nil {
                    return re.CloseWithError(err)
                } else if processedOneResponse {
                    return re.CloseWithError(errors.New("unexpected multipart response during emit, please file a bugreport"))
                }

                r, ok := v.(io.Reader)
                if !ok {

                    return errors.New("unexpected non-stream passed to PostRun: please file a bugreport")
                }

                processedOneResponse = true

                if err := re.Emit(bar.NewProxyReader(r)); err != nil {
                    return err
                }
            }
        },
    },
}
var DagGetCmd = &cmds.Command{
    Helptext: cmds.HelpText{
        Tagline: "Get a dag node from ipfs.",
        ShortDescription: `
'ipfs dag get' fetches a dag node from ipfs and prints it out in the specified
format.
`,
    },
    Arguments: []cmds.Argument{
        cmds.StringArg("ref", true, false, "The object to get").EnableStdin(),
    },
    Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
        api, err := cmdenv.GetApi(env, req)
        if err != nil {
            return err
        }

        rp, err := api.ResolvePath(req.Context, path.New(req.Arguments[0]))
        if err != nil {
            return err
        }

        obj, err := api.Dag().Get(req.Context, rp.Cid())
        if err != nil {
            return err
        }

        var out interface{} = obj
        if len(rp.Remainder()) > 0 {
            rem := strings.Split(rp.Remainder(), "/")
            final, _, err := obj.Resolve(rem)
            if err != nil {
                return err
            }
            out = final
        }
        return cmds.EmitOnce(res, &out)
    },
}
var DagImportCmd = &cmds.Command{
    Helptext: cmds.HelpText{
        Tagline:          "Import the contents of .car files",
        ShortDescription: "" /* 820 byte string literal not displayed */,
    },
    Arguments: []cmds.Argument{
        cmds.FileArg("path", true, true, "The path of a .car file.").EnableStdin(),
    },
    Options: []cmds.Option{
        cmds.BoolOption(silentOptionName, "No output."),
        cmds.BoolOption(pinRootsOptionName, "Pin optional roots listed in the .car headers after importing.").WithDefault(true),
    },
    Type: CarImportOutput{},
    Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {

        node, err := cmdenv.GetNode(env)
        if err != nil {
            return err
        }

        api, err := cmdenv.GetApi(env, req)
        if err != nil {
            return err
        }

        api, err = api.WithOptions(options.Api.Offline(true))
        if err != nil {
            return err
        }

        unlocker := node.Blockstore.PinLock()
        defer unlocker.Unlock()

        doPinRoots, _ := req.Options[pinRootsOptionName].(bool)

        retCh := make(chan importResult, 1)
        go importWorker(req, res, api, retCh)

        done := <-retCh
        if done.err != nil {
            return done.err
        }

        roots := done.roots

        if doPinRoots {

            var failedPins int
            for c := range roots {

                ret := RootMeta{Cid: c}

                if block, err := node.Blockstore.Get(c); err != nil {
                    ret.PinErrorMsg = err.Error()
                } else if nd, err := ipld.Decode(block); err != nil {
                    ret.PinErrorMsg = err.Error()
                } else if err := node.Pinning.Pin(req.Context, nd, true); err != nil {
                    ret.PinErrorMsg = err.Error()
                } else if err := node.Pinning.Flush(req.Context); err != nil {
                    ret.PinErrorMsg = err.Error()
                }

                if ret.PinErrorMsg != "" {
                    failedPins++
                }

                if err := res.Emit(&CarImportOutput{Root: ret}); err != nil {
                    return err
                }
            }

            if failedPins > 0 {
                return fmt.Errorf(
                    "unable to pin all roots: %d out of %d failed",
                    failedPins,
                    len(roots),
                )
            }
        }

        return nil
    },
    Encoders: cmds.EncoderMap{
        cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, event *CarImportOutput) error {

            silent, _ := req.Options[silentOptionName].(bool)
            if silent {
                return nil
            }

            enc, err := cmdenv.GetLowLevelCidEncoder(req)
            if err != nil {
                return err
            }

            if event.Root.PinErrorMsg != "" {
                event.Root.PinErrorMsg = fmt.Sprintf("FAILED: %s", event.Root.PinErrorMsg)
            } else {
                event.Root.PinErrorMsg = "success"
            }

            _, err = fmt.Fprintf(
                w,
                "Pinned root\t%s\t%s\n",
                enc.Encode(event.Root.Cid),
                event.Root.PinErrorMsg,
            )
            return err
        }),
    },
}
var DagPutCmd = &cmds.Command{
    Helptext: cmds.HelpText{
        Tagline: "Add a dag node to ipfs.",
        ShortDescription: `
'ipfs dag put' accepts input from a file or stdin and parses it
into an object of the specified format.
`,
    },
    Arguments: []cmds.Argument{
        cmds.FileArg("object data", true, true, "The object to put").EnableStdin(),
    },
    Options: []cmds.Option{
        cmds.StringOption("format", "f", "Format that the object will be added as.").WithDefault("cbor"),
        cmds.StringOption("input-enc", "Format that the input object will be.").WithDefault("json"),
        cmds.BoolOption("pin", "Pin this object when adding."),
        cmds.StringOption("hash", "Hash function to use").WithDefault(""),
    },
    Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
        api, err := cmdenv.GetApi(env, req)
        if err != nil {
            return err
        }

        ienc, _ := req.Options["input-enc"].(string)
        format, _ := req.Options["format"].(string)
        hash, _ := req.Options["hash"].(string)
        dopin, _ := req.Options["pin"].(bool)

        mhType := uint64(math.MaxUint64)

        if hash != "" {
            var ok bool
            mhType, ok = mh.Names[hash]
            if !ok {
                return fmt.Errorf("%s in not a valid multihash name", hash)
            }
        }

        var adder ipld.NodeAdder = api.Dag()
        if dopin {
            adder = api.Dag().Pinning()
        }
        b := ipld.NewBatch(req.Context, adder)

        it := req.Files.Entries()
        for it.Next() {
            file := files.FileFromEntry(it)
            if file == nil {
                return fmt.Errorf("expected a regular file")
            }
            nds, err := coredag.ParseInputs(ienc, format, file, mhType, -1)
            if err != nil {
                return err
            }
            if len(nds) == 0 {
                return fmt.Errorf("no node returned from ParseInputs")
            }

            for _, nd := range nds {
                err := b.Add(req.Context, nd)
                if err != nil {
                    return err
                }
            }

            cid := nds[0].Cid()
            if err := res.Emit(&OutputObject{Cid: cid}); err != nil {
                return err
            }
        }
        if it.Err() != nil {
            return it.Err()
        }

        if err := b.Commit(); err != nil {
            return err
        }

        return nil
    },
    Type: OutputObject{},
    Encoders: cmds.EncoderMap{
        cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *OutputObject) error {
            enc, err := cmdenv.GetLowLevelCidEncoder(req)
            if err != nil {
                return err
            }
            fmt.Fprintln(w, enc.Encode(out.Cid))
            return nil
        }),
    },
}
var DagResolveCmd = &cmds.Command{
    Helptext: cmds.HelpText{
        Tagline: "Resolve ipld block",
        ShortDescription: `
'ipfs dag resolve' fetches a dag node from ipfs, prints its address and remaining path.
`,
    },
    Arguments: []cmds.Argument{
        cmds.StringArg("ref", true, false, "The path to resolve").EnableStdin(),
    },
    Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
        api, err := cmdenv.GetApi(env, req)
        if err != nil {
            return err
        }

        rp, err := api.ResolvePath(req.Context, path.New(req.Arguments[0]))
        if err != nil {
            return err
        }

        return cmds.EmitOnce(res, &ResolveOutput{
            Cid:     rp.Cid(),
            RemPath: rp.Remainder(),
        })
    },
    Encoders: cmds.EncoderMap{
        cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *ResolveOutput) error {
            var (
                enc cidenc.Encoder
                err error
            )
            switch {
            case !cmdenv.CidBaseDefined(req):

                enc, err = cmdenv.CidEncoderFromPath(req.Arguments[0])
                if err == nil {
                    break
                }

                fallthrough
            default:
                enc, err = cmdenv.GetLowLevelCidEncoder(req)
                if err != nil {
                    return err
                }
            }
            p := enc.Encode(out.Cid)
            if out.RemPath != "" {
                p = ipfspath.Join([]string{p, out.RemPath})
            }

            fmt.Fprint(w, p)
            return nil
        }),
    },
    Type: ResolveOutput{},
}

DagResolveCmd returns address of highest block within a path and a path remainder

type CarImportOutput Uses

type CarImportOutput struct {
    Root RootMeta
}

CarImportOutput is the output type of the 'dag import' commands

type OutputObject Uses

type OutputObject struct {
    Cid cid.Cid
}

OutputObject is the output type of 'dag put' command

type ResolveOutput Uses

type ResolveOutput struct {
    Cid     cid.Cid
    RemPath string
}

ResolveOutput is the output type of 'dag resolve' command

type RootMeta Uses

type RootMeta struct {
    Cid         cid.Cid
    PinErrorMsg string
}

Package dagcmd imports 22 packages (graph) and is imported by 32 packages. Updated 2020-05-05. Refresh now. Tools for package owners.