From 3cf7b34d79a02b04fd8d2ee548b33a86c35bd769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Fri, 2 Feb 2018 22:36:01 +0100 Subject: [PATCH] commands: switch object commands to CoreAPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Ɓukasz Magiera --- core/commands/env.go | 11 + core/commands/object/diff.go | 40 ++-- core/commands/object/object.go | 275 +++++++---------------- core/commands/object/patch.go | 160 +++---------- core/coreapi/interface/object.go | 5 +- core/coreapi/interface/options/object.go | 4 +- core/coreapi/object.go | 14 +- 7 files changed, 151 insertions(+), 358 deletions(-) diff --git a/core/commands/env.go b/core/commands/env.go index d884292e3e9..d0536e3da28 100644 --- a/core/commands/env.go +++ b/core/commands/env.go @@ -5,6 +5,7 @@ import ( "github.com/ipfs/go-ipfs/commands" "github.com/ipfs/go-ipfs/core" + coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" "github.com/ipfs/go-ipfs/repo/config" ) @@ -18,6 +19,16 @@ func GetNode(env interface{}) (*core.IpfsNode, error) { return ctx.GetNode() } +// GetApi extracts CoreAPI instance from the environment. +func GetApi(env interface{}) (coreiface.CoreAPI, error) { + ctx, ok := env.(*commands.Context) + if !ok { + return nil, fmt.Errorf("expected env to be of type %T, got %T", ctx, env) + } + + return ctx.GetApi() +} + // GetConfig extracts the config from the environment. func GetConfig(env interface{}) (*config.Config, error) { ctx, ok := env.(*commands.Context) diff --git a/core/commands/object/diff.go b/core/commands/object/diff.go index 26f0feab2cf..49f1addcfb4 100644 --- a/core/commands/object/diff.go +++ b/core/commands/object/diff.go @@ -6,10 +6,10 @@ import ( "io" cmds "github.com/ipfs/go-ipfs/commands" - core "github.com/ipfs/go-ipfs/core" e "github.com/ipfs/go-ipfs/core/commands/e" + coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" "github.com/ipfs/go-ipfs/dagutils" - path "gx/ipfs/QmYKNMEUK7nCVAefgXF1LVtZEZg3uRmBqiae4FJRXDNAyJ/go-path" + cmdkit "gx/ipfs/QmdE4gMduCKCGAcczM2F5ioYDfdeKuPix138wrES1YSr7f/go-ipfs-cmdkit" ) @@ -52,7 +52,7 @@ Example: cmdkit.BoolOption("verbose", "v", "Print extra information."), }, Run: func(req cmds.Request, res cmds.Response) { - node, err := req.InvocContext().GetNode() + api, err := req.InvocContext().GetApi() if err != nil { res.SetError(err, cmdkit.ErrNormal) return @@ -61,39 +61,37 @@ Example: a := req.Arguments()[0] b := req.Arguments()[1] - pa, err := path.ParsePath(a) + pa, err := coreiface.ParsePath(a) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - pb, err := path.ParsePath(b) + pb, err := coreiface.ParsePath(b) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - ctx := req.Context() + changes, err := api.Object().Diff(req.Context(), pa, pb) - obj_a, err := core.Resolve(ctx, node.Namesys, node.Resolver, pa) - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } + out := make([]*dagutils.Change, len(changes)) + for i, change := range changes { + out[i] = &dagutils.Change{ + Type: change.Type, + Path: change.Path, + } - obj_b, err := core.Resolve(ctx, node.Namesys, node.Resolver, pb) - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } + if change.Before != nil { + out[i].Before = change.Before.Cid() + } - changes, err := dagutils.Diff(ctx, node.DAG, obj_a, obj_b) - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return + if change.After != nil { + out[i].After = change.After.Cid() + } } - res.SetOutput(&Changes{changes}) + res.SetOutput(&Changes{out}) }, Type: Changes{}, Marshalers: cmds.MarshalerMap{ diff --git a/core/commands/object/object.go b/core/commands/object/object.go index 36acd094361..2fde79186ff 100644 --- a/core/commands/object/object.go +++ b/core/commands/object/object.go @@ -2,10 +2,7 @@ package objectcmd import ( "bytes" - "context" "encoding/base64" - "encoding/json" - "encoding/xml" "errors" "fmt" "io" @@ -15,14 +12,12 @@ import ( oldcmds "github.com/ipfs/go-ipfs/commands" lgc "github.com/ipfs/go-ipfs/commands/legacy" - core "github.com/ipfs/go-ipfs/core" e "github.com/ipfs/go-ipfs/core/commands/e" - pin "github.com/ipfs/go-ipfs/pin" - ft "github.com/ipfs/go-ipfs/unixfs" - dag "gx/ipfs/QmRy4Qk9hbgFX9NGJRm8rBThrA8PZhNCitMgeRYyZ67s59/go-merkledag" - path "gx/ipfs/QmYKNMEUK7nCVAefgXF1LVtZEZg3uRmBqiae4FJRXDNAyJ/go-path" + coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" + "github.com/ipfs/go-ipfs/core/coreapi/interface/options" cmds "gx/ipfs/QmNueRyPRQiV7PUEpnP4GgGLuK1rKQLaRW7sfPvUetYig1/go-ipfs-cmds" + dag "gx/ipfs/QmRy4Qk9hbgFX9NGJRm8rBThrA8PZhNCitMgeRYyZ67s59/go-merkledag" cid "gx/ipfs/QmYVNvtQkeZ6AKSwDrjQTs432QtL6umrrK41EBq3cu7iSP/go-cid" ipld "gx/ipfs/QmZtNq8dArGfnpCZfx2pUNY7UcjGhVp5qqwQ4hH6mpTMRQ/go-ipld-format" cmdkit "gx/ipfs/QmdE4gMduCKCGAcczM2F5ioYDfdeKuPix138wrES1YSr7f/go-ipfs-cmdkit" @@ -88,31 +83,25 @@ is the raw data of the object. cmdkit.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(), }, Run: func(req oldcmds.Request, res oldcmds.Response) { - n, err := req.InvocContext().GetNode() + api, err := req.InvocContext().GetApi() if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - fpath, err := path.ParsePath(req.Arguments()[0]) + path, err := coreiface.ParsePath(req.Arguments()[0]) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - node, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, fpath) + data, err := api.Object().Data(req.Context(), path) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - pbnode, ok := node.(*dag.ProtoNode) - if !ok { - res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal) - return - } - - res.SetOutput(bytes.NewReader(pbnode.Data())) + res.SetOutput(data) }, } @@ -133,7 +122,7 @@ multihash. cmdkit.BoolOption("headers", "v", "Print table headers (Hash, Size, Name)."), }, Run: func(req oldcmds.Request, res oldcmds.Response) { - n, err := req.InvocContext().GetNode() + api, err := req.InvocContext().GetApi() if err != nil { res.SetError(err, cmdkit.ErrNormal) return @@ -145,19 +134,39 @@ multihash. return } - fpath := path.Path(req.Arguments()[0]) - node, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, fpath) + path, err := coreiface.ParsePath(req.Arguments()[0]) + if err != nil { + res.SetError(err, cmdkit.ErrNormal) + return + } + + rp, err := api.ResolvePath(req.Context(), path) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - output, err := getOutput(node) + links, err := api.Object().Links(req.Context(), rp) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - res.SetOutput(output) + + outLinks := make([]Link, len(links)) + for i, link := range links { + outLinks[i] = Link{ + Hash: link.Cid.String(), + Name: link.Name, + Size: link.Size, + } + } + + out := Object{ + Hash: rp.Cid().String(), + Links: outLinks, + } + + res.SetOutput(out) }, Marshalers: oldcmds.MarshalerMap{ oldcmds.Text: func(res oldcmds.Response) (io.Reader, error) { @@ -222,13 +231,17 @@ Supported values are: cmdkit.StringOption("data-encoding", "Encoding type of the data field, either \"text\" or \"base64\".").WithDefault("text"), }, Run: func(req oldcmds.Request, res oldcmds.Response) { - n, err := req.InvocContext().GetNode() + api, err := req.InvocContext().GetApi() if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - fpath := path.Path(req.Arguments()[0]) + path, err := coreiface.ParsePath(req.Arguments()[0]) + if err != nil { + res.SetError(err, cmdkit.ErrNormal) + return + } datafieldenc, _, err := req.Option("data-encoding").String() if err != nil { @@ -236,30 +249,36 @@ Supported values are: return } - object, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, fpath) + nd, err := api.Object().Get(req.Context(), path) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - pbo, ok := object.(*dag.ProtoNode) - if !ok { - res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal) + r, err := api.Object().Data(req.Context(), path) + if err != nil { + res.SetError(err, cmdkit.ErrNormal) return } - data, err := encodeData(pbo.Data(), datafieldenc) + data, err := ioutil.ReadAll(r) + if err != nil { + res.SetError(err, cmdkit.ErrNormal) + return + } + + out, err := encodeData(data, datafieldenc) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } node := &Node{ - Links: make([]Link, len(object.Links())), - Data: data, + Links: make([]Link, len(nd.Links())), + Data: out, } - for i, link := range object.Links() { + for i, link := range nd.Links() { node.Links[i] = Link{ Hash: link.Cid.String(), Name: link.Name, @@ -316,27 +335,34 @@ var ObjectStatCmd = &oldcmds.Command{ cmdkit.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(), }, Run: func(req oldcmds.Request, res oldcmds.Response) { - n, err := req.InvocContext().GetNode() + api, err := req.InvocContext().GetApi() if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - fpath := path.Path(req.Arguments()[0]) - - object, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, fpath) + path, err := coreiface.ParsePath(req.Arguments()[0]) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - ns, err := object.Stat() + ns, err := api.Object().Stat(req.Context(), path) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - res.SetOutput(ns) + oldStat := &ipld.NodeStat{ + Hash: ns.Cid.String(), + NumLinks: ns.NumLinks, + BlockSize: ns.BlockSize, + LinksSize: ns.LinksSize, + DataSize: ns.DataSize, + CumulativeSize: ns.CumulativeSize, + } + + res.SetOutput(oldStat) }, Type: ipld.NodeStat{}, Marshalers: oldcmds.MarshalerMap{ @@ -414,7 +440,7 @@ And then run: cmdkit.BoolOption("quiet", "q", "Write minimal output."), }, Run: func(req oldcmds.Request, res oldcmds.Response) { - n, err := req.InvocContext().GetNode() + api, err := req.InvocContext().GetApi() if err != nil { res.SetError(err, cmdkit.ErrNormal) return @@ -444,30 +470,16 @@ And then run: return } - if dopin { - defer n.Blockstore.PinLock().Unlock() - } - - objectCid, err := objectPut(req.Context(), n, input, inputenc, datafieldenc) + p, err := api.Object().Put(req.Context(), input, + options.Object.DataType(datafieldenc), + options.Object.InputEnc(inputenc), + options.Object.Pin(dopin)) if err != nil { - errType := cmdkit.ErrNormal - if err == ErrUnknownObjectEnc { - errType = cmdkit.ErrClient - } - res.SetError(err, errType) + res.SetError(err, cmdkit.ErrNormal) return } - if dopin { - n.Pinning.PinWithMode(objectCid, pin.Recursive) - err = n.Pinning.Flush() - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } - } - - res.SetOutput(&Object{Hash: objectCid.String()}) + res.SetOutput(&Object{Hash: p.Cid().String()}) }, Marshalers: oldcmds.MarshalerMap{ oldcmds.Text: func(res oldcmds.Response) (io.Reader, error) { @@ -513,29 +525,24 @@ Available templates: cmdkit.StringArg("template", false, false, "Template to use. Optional."), }, Run: func(req oldcmds.Request, res oldcmds.Response) { - n, err := req.InvocContext().GetNode() + api, err := req.InvocContext().GetApi() if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - node := new(dag.ProtoNode) + template := "empty" if len(req.Arguments()) == 1 { - template := req.Arguments()[0] - var err error - node, err = nodeFromTemplate(template) - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } + template = req.Arguments()[0] } - err = n.DAG.Add(req.Context(), node) - if err != nil { + nd, err := api.Object().New(req.Context(), options.Object.Type(template)) + if err != nil && err != io.EOF { res.SetError(err, cmdkit.ErrNormal) return } - res.SetOutput(&Object{Hash: node.Cid().String()}) + + res.SetOutput(&Object{Hash: nd.Cid().String()}) }, Marshalers: oldcmds.MarshalerMap{ oldcmds.Text: func(res oldcmds.Response) (io.Reader, error) { @@ -555,126 +562,6 @@ Available templates: Type: Object{}, } -func nodeFromTemplate(template string) (*dag.ProtoNode, error) { - switch template { - case "unixfs-dir": - return ft.EmptyDirNode(), nil - default: - return nil, fmt.Errorf("template '%s' not found", template) - } -} - -// ErrEmptyNode is returned when the input to 'ipfs object put' contains no data -var ErrEmptyNode = errors.New("no data or links in this node") - -// objectPut takes a format option, serializes bytes from stdin and updates the dag with that data -func objectPut(ctx context.Context, n *core.IpfsNode, input io.Reader, encoding string, dataFieldEncoding string) (*cid.Cid, error) { - - data, err := ioutil.ReadAll(io.LimitReader(input, inputLimit+10)) - if err != nil { - return nil, err - } - - if len(data) >= inputLimit { - return nil, ErrObjectTooLarge - } - - var dagnode *dag.ProtoNode - switch getObjectEnc(encoding) { - case objectEncodingJSON: - node := new(Node) - err = json.Unmarshal(data, node) - if err != nil { - return nil, err - } - - // check that we have data in the Node to add - // otherwise we will add the empty object without raising an error - if NodeEmpty(node) { - return nil, ErrEmptyNode - } - - dagnode, err = deserializeNode(node, dataFieldEncoding) - if err != nil { - return nil, err - } - - case objectEncodingProtobuf: - dagnode, err = dag.DecodeProtobuf(data) - - case objectEncodingXML: - node := new(Node) - err = xml.Unmarshal(data, node) - if err != nil { - return nil, err - } - - // check that we have data in the Node to add - // otherwise we will add the empty object without raising an error - if NodeEmpty(node) { - return nil, ErrEmptyNode - } - - dagnode, err = deserializeNode(node, dataFieldEncoding) - if err != nil { - return nil, err - } - - default: - return nil, ErrUnknownObjectEnc - } - - if err != nil { - return nil, err - } - - err = n.DAG.Add(ctx, dagnode) - if err != nil { - return nil, err - } - - return dagnode.Cid(), nil -} - -// ErrUnknownObjectEnc is returned if a invalid encoding is supplied -var ErrUnknownObjectEnc = errors.New("unknown object encoding") - -type objectEncoding string - -const ( - objectEncodingJSON objectEncoding = "json" - objectEncodingProtobuf = "protobuf" - objectEncodingXML = "xml" -) - -func getObjectEnc(o interface{}) objectEncoding { - v, ok := o.(string) - if !ok { - // chosen as default because it's human readable - return objectEncodingJSON - } - - return objectEncoding(v) -} - -func getOutput(dagnode ipld.Node) (*Object, error) { - c := dagnode.Cid() - output := &Object{ - Hash: c.String(), - Links: make([]Link, len(dagnode.Links())), - } - - for i, link := range dagnode.Links() { - output.Links[i] = Link{ - Name: link.Name, - Hash: link.Cid.String(), - Size: link.Size, - } - } - - return output, nil -} - // converts the Node object into a real dag.ProtoNode func deserializeNode(nd *Node, dataFieldEncoding string) (*dag.ProtoNode, error) { dagnode := new(dag.ProtoNode) @@ -708,10 +595,6 @@ func deserializeNode(nd *Node, dataFieldEncoding string) (*dag.ProtoNode, error) return dagnode, nil } -func NodeEmpty(node *Node) bool { - return node.Data == "" && len(node.Links) == 0 -} - // copy+pasted from ../commands.go func unwrapOutput(i interface{}) (interface{}, error) { var ( diff --git a/core/commands/object/patch.go b/core/commands/object/patch.go index b9cbd694aaa..fcadc49bec3 100644 --- a/core/commands/object/patch.go +++ b/core/commands/object/patch.go @@ -3,25 +3,18 @@ package objectcmd import ( "fmt" "io" - "io/ioutil" "strings" oldcmds "github.com/ipfs/go-ipfs/commands" lgc "github.com/ipfs/go-ipfs/commands/legacy" - core "github.com/ipfs/go-ipfs/core" e "github.com/ipfs/go-ipfs/core/commands/e" - "github.com/ipfs/go-ipfs/dagutils" - ft "github.com/ipfs/go-ipfs/unixfs" - dag "gx/ipfs/QmRy4Qk9hbgFX9NGJRm8rBThrA8PZhNCitMgeRYyZ67s59/go-merkledag" - path "gx/ipfs/QmYKNMEUK7nCVAefgXF1LVtZEZg3uRmBqiae4FJRXDNAyJ/go-path" + coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" + "github.com/ipfs/go-ipfs/core/coreapi/interface/options" cmds "gx/ipfs/QmNueRyPRQiV7PUEpnP4GgGLuK1rKQLaRW7sfPvUetYig1/go-ipfs-cmds" - logging "gx/ipfs/QmcVVHfdyv15GVPk7NrxdWjh2hLVccXnoD8j2tyQShiXJb/go-log" cmdkit "gx/ipfs/QmdE4gMduCKCGAcczM2F5ioYDfdeKuPix138wrES1YSr7f/go-ipfs-cmdkit" ) -var log = logging.Logger("core/commands/object") - var ObjectPatchCmd = &cmds.Command{ Helptext: cmdkit.HelpText{ Tagline: "Create a new merkledag object based on an existing one.", @@ -74,51 +67,31 @@ the limit will not be respected by the network. cmdkit.FileArg("data", true, false, "Data to append.").EnableStdin(), }, Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) { - nd, err := GetNode(env) - if err != nil { - re.SetError(err, cmdkit.ErrNormal) - return - } - - root, err := path.ParsePath(req.Arguments[0]) - if err != nil { - re.SetError(err, cmdkit.ErrNormal) - return - } - - rootnd, err := core.Resolve(req.Context, nd.Namesys, nd.Resolver, root) + api, err := GetApi(env) if err != nil { re.SetError(err, cmdkit.ErrNormal) return } - rtpb, ok := rootnd.(*dag.ProtoNode) - if !ok { - re.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal) - return - } - - fi, err := req.Files.NextFile() + root, err := coreiface.ParsePath(req.Arguments[0]) if err != nil { re.SetError(err, cmdkit.ErrNormal) return } - data, err := ioutil.ReadAll(fi) + data, err := req.Files.NextFile() if err != nil { re.SetError(err, cmdkit.ErrNormal) return } - rtpb.SetData(append(rtpb.Data(), data...)) - - err = nd.DAG.Add(req.Context, rtpb) + p, err := api.Object().AppendData(req.Context, root, data) if err != nil { re.SetError(err, cmdkit.ErrNormal) return } - cmds.EmitOnce(re, &Object{Hash: rtpb.Cid().String()}) + cmds.EmitOnce(re, &Object{Hash: p.Cid().String()}) }, Type: Object{}, Encoders: cmds.EncoderMap{ @@ -145,51 +118,27 @@ Example: cmdkit.FileArg("data", true, false, "The data to set the object to.").EnableStdin(), }, Run: func(req oldcmds.Request, res oldcmds.Response) { - nd, err := req.InvocContext().GetNode() - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } + api, err := req.InvocContext().GetApi() - rp, err := path.ParsePath(req.StringArguments()[0]) + root, err := coreiface.ParsePath(req.StringArguments()[0]) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - root, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, rp) - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } - - rtpb, ok := root.(*dag.ProtoNode) - if !ok { - res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal) - return - } - - fi, err := req.Files().NextFile() + data, err := req.Files().NextFile() if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - data, err := ioutil.ReadAll(fi) + p, err := api.Object().SetData(req.Context(), root, data) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - rtpb.SetData(data) - - err = nd.DAG.Add(req.Context(), rtpb) - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } - - res.SetOutput(&Object{Hash: rtpb.Cid().String()}) + res.SetOutput(&Object{Hash: p.Cid().String()}) }, Type: Object{}, Marshalers: oldcmds.MarshalerMap{ @@ -209,49 +158,26 @@ Removes a link by the given name from root. cmdkit.StringArg("link", true, false, "Name of the link to remove."), }, Run: func(req oldcmds.Request, res oldcmds.Response) { - nd, err := req.InvocContext().GetNode() - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } - - rootp, err := path.ParsePath(req.Arguments()[0]) + api, err := req.InvocContext().GetApi() if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - root, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, rootp) - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } - - rtpb, ok := root.(*dag.ProtoNode) - if !ok { - res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal) - return - } - - path := req.Arguments()[1] - - e := dagutils.NewDagEditor(rtpb, nd.DAG) - - err = e.RmLink(req.Context(), path) + root, err := coreiface.ParsePath(req.Arguments()[0]) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - nnode, err := e.Finalize(req.Context(), nd.DAG) + link := req.Arguments()[1] + p, err := api.Object().RmLink(req.Context(), root, link) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - nc := nnode.Cid() - - res.SetOutput(&Object{Hash: nc.String()}) + res.SetOutput(&Object{Hash: p.Cid().String()}) }, Type: Object{}, Marshalers: oldcmds.MarshalerMap{ @@ -284,32 +210,21 @@ to a file containing 'bar', and returns the hash of the new object. cmdkit.BoolOption("create", "p", "Create intermediary nodes."), }, Run: func(req oldcmds.Request, res oldcmds.Response) { - nd, err := req.InvocContext().GetNode() + api, err := req.InvocContext().GetApi() if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - rootp, err := path.ParsePath(req.Arguments()[0]) + root, err := coreiface.ParsePath(req.Arguments()[0]) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - root, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, rootp) - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } + name := req.Arguments()[1] - rtpb, ok := root.(*dag.ProtoNode) - if !ok { - res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal) - return - } - - npath := req.Arguments()[1] - childp, err := path.ParsePath(req.Arguments()[2]) + child, err := coreiface.ParsePath(req.Arguments()[2]) if err != nil { res.SetError(err, cmdkit.ErrNormal) return @@ -321,34 +236,14 @@ to a file containing 'bar', and returns the hash of the new object. return } - var createfunc func() *dag.ProtoNode - if create { - createfunc = ft.EmptyDirNode - } - - e := dagutils.NewDagEditor(rtpb, nd.DAG) - - childnd, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, childp) + p, err := api.Object().AddLink(req.Context(), root, name, child, + options.Object.Create(create)) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - err = e.InsertNodeAtPath(req.Context(), npath, childnd, createfunc) - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } - - nnode, err := e.Finalize(req.Context(), nd.DAG) - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } - - nc := nnode.Cid() - - res.SetOutput(&Object{Hash: nc.String()}) + res.SetOutput(&Object{Hash: p.Cid().String()}) }, Type: Object{}, Marshalers: oldcmds.MarshalerMap{ @@ -356,13 +251,14 @@ to a file containing 'bar', and returns the hash of the new object. }, } +// TODO: fix import loop with core/commands so we don't need that // COPIED FROM ONE LEVEL UP -// GetNode extracts the node from the environment. -func GetNode(env interface{}) (*core.IpfsNode, error) { +// GetApi extracts CoreAPI instance from the environment. +func GetApi(env interface{}) (coreiface.CoreAPI, error) { ctx, ok := env.(*oldcmds.Context) if !ok { return nil, fmt.Errorf("expected env to be of type %T, got %T", ctx, env) } - return ctx.GetNode() + return ctx.GetApi() } diff --git a/core/coreapi/interface/object.go b/core/coreapi/interface/object.go index 0a716dc97e7..1c7caeb77bc 100644 --- a/core/coreapi/interface/object.go +++ b/core/coreapi/interface/object.go @@ -31,7 +31,6 @@ type ObjectStat struct { CumulativeSize int } - const ( // DiffAdd is a Type of ObjectChange where a link was added to the graph DiffAdd = iota @@ -57,11 +56,11 @@ type ObjectChange struct { // Before holds the link path before the change. Note that when a link is // added, this will be nil. - Before Path + Before ResolvedPath // After holds the link path after the change. Note that when a link is // removed, this will be nil. - After Path + After ResolvedPath } // ObjectAPI specifies the interface to MerkleDAG and contains useful utilities diff --git a/core/coreapi/interface/options/object.go b/core/coreapi/interface/options/object.go index 9257ea6077c..e484a9f3632 100644 --- a/core/coreapi/interface/options/object.go +++ b/core/coreapi/interface/options/object.go @@ -105,9 +105,9 @@ func (objectOpts) DataType(t string) ObjectPutOption { } } -// WithPin is an option for Object.Put which specifies whether to pin the added +// Pin is an option for Object.Put which specifies whether to pin the added // objects, default is false -func (objectOpts) WithPin(pin bool) ObjectPutOption { +func (objectOpts) Pin(pin bool) ObjectPutOption { return func(settings *ObjectPutSettings) error { settings.Pin = pin return nil diff --git a/core/coreapi/object.go b/core/coreapi/object.go index d89f47bdfb7..bfaef19c9c7 100644 --- a/core/coreapi/object.go +++ b/core/coreapi/object.go @@ -316,10 +316,16 @@ func (api *ObjectAPI) Diff(ctx context.Context, before coreiface.Path, after cor out := make([]coreiface.ObjectChange, len(changes)) for i, change := range changes { out[i] = coreiface.ObjectChange{ - Type: change.Type, - Path: change.Path, - Before: coreiface.IpfsPath(change.Before), - After: coreiface.IpfsPath(change.After), + Type: change.Type, + Path: change.Path, + } + + if change.Before != nil { + out[i].Before = coreiface.IpfsPath(change.Before) + } + + if change.After != nil { + out[i].After = coreiface.IpfsPath(change.After) } }