mirror of
https://github.com/ipfs/kubo.git
synced 2025-09-10 05:52:20 +08:00
refactor object patch command to work more betterer
License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
package commands
|
package objectcmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -13,14 +13,11 @@ import (
|
|||||||
|
|
||||||
mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
|
mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
|
||||||
|
|
||||||
key "github.com/ipfs/go-ipfs/blocks/key"
|
|
||||||
cmds "github.com/ipfs/go-ipfs/commands"
|
cmds "github.com/ipfs/go-ipfs/commands"
|
||||||
core "github.com/ipfs/go-ipfs/core"
|
core "github.com/ipfs/go-ipfs/core"
|
||||||
dag "github.com/ipfs/go-ipfs/merkledag"
|
dag "github.com/ipfs/go-ipfs/merkledag"
|
||||||
dagutils "github.com/ipfs/go-ipfs/merkledag/utils"
|
|
||||||
path "github.com/ipfs/go-ipfs/path"
|
path "github.com/ipfs/go-ipfs/path"
|
||||||
ft "github.com/ipfs/go-ipfs/unixfs"
|
ft "github.com/ipfs/go-ipfs/unixfs"
|
||||||
u "github.com/ipfs/go-ipfs/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrObjectTooLarge is returned when too much data was read from stdin. current limit 512k
|
// ErrObjectTooLarge is returned when too much data was read from stdin. current limit 512k
|
||||||
@ -61,17 +58,17 @@ ipfs object patch <args> - Create new object from old ones
|
|||||||
},
|
},
|
||||||
|
|
||||||
Subcommands: map[string]*cmds.Command{
|
Subcommands: map[string]*cmds.Command{
|
||||||
"data": objectDataCmd,
|
"data": ObjectDataCmd,
|
||||||
"links": objectLinksCmd,
|
"links": ObjectLinksCmd,
|
||||||
"get": objectGetCmd,
|
"get": ObjectGetCmd,
|
||||||
"put": objectPutCmd,
|
"put": ObjectPutCmd,
|
||||||
"stat": objectStatCmd,
|
"stat": ObjectStatCmd,
|
||||||
"new": objectNewCmd,
|
"new": ObjectNewCmd,
|
||||||
"patch": objectPatchCmd,
|
"patch": ObjectPatchCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var objectDataCmd = &cmds.Command{
|
var ObjectDataCmd = &cmds.Command{
|
||||||
Helptext: cmds.HelpText{
|
Helptext: cmds.HelpText{
|
||||||
Tagline: "Outputs the raw bytes in an IPFS object",
|
Tagline: "Outputs the raw bytes in an IPFS object",
|
||||||
ShortDescription: `
|
ShortDescription: `
|
||||||
@ -109,7 +106,7 @@ output is the raw data of the object.
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var objectLinksCmd = &cmds.Command{
|
var ObjectLinksCmd = &cmds.Command{
|
||||||
Helptext: cmds.HelpText{
|
Helptext: cmds.HelpText{
|
||||||
Tagline: "Outputs the links pointed to by the specified object",
|
Tagline: "Outputs the links pointed to by the specified object",
|
||||||
ShortDescription: `
|
ShortDescription: `
|
||||||
@ -158,7 +155,7 @@ multihash.
|
|||||||
Type: Object{},
|
Type: Object{},
|
||||||
}
|
}
|
||||||
|
|
||||||
var objectGetCmd = &cmds.Command{
|
var ObjectGetCmd = &cmds.Command{
|
||||||
Helptext: cmds.HelpText{
|
Helptext: cmds.HelpText{
|
||||||
Tagline: "Get and serialize the DAG node named by <key>",
|
Tagline: "Get and serialize the DAG node named by <key>",
|
||||||
ShortDescription: `
|
ShortDescription: `
|
||||||
@ -229,7 +226,7 @@ This command outputs data in the following encodings:
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var objectStatCmd = &cmds.Command{
|
var ObjectStatCmd = &cmds.Command{
|
||||||
Helptext: cmds.HelpText{
|
Helptext: cmds.HelpText{
|
||||||
Tagline: "Get stats for the DAG node named by <key>",
|
Tagline: "Get stats for the DAG node named by <key>",
|
||||||
ShortDescription: `
|
ShortDescription: `
|
||||||
@ -290,7 +287,7 @@ var objectStatCmd = &cmds.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var objectPutCmd = &cmds.Command{
|
var ObjectPutCmd = &cmds.Command{
|
||||||
Helptext: cmds.HelpText{
|
Helptext: cmds.HelpText{
|
||||||
Tagline: "Stores input as a DAG object, outputs its key",
|
Tagline: "Stores input as a DAG object, outputs its key",
|
||||||
ShortDescription: `
|
ShortDescription: `
|
||||||
@ -377,7 +374,7 @@ and then run
|
|||||||
Type: Object{},
|
Type: Object{},
|
||||||
}
|
}
|
||||||
|
|
||||||
var objectNewCmd = &cmds.Command{
|
var ObjectNewCmd = &cmds.Command{
|
||||||
Helptext: cmds.HelpText{
|
Helptext: cmds.HelpText{
|
||||||
Tagline: "creates a new object from an ipfs template",
|
Tagline: "creates a new object from an ipfs template",
|
||||||
ShortDescription: `
|
ShortDescription: `
|
||||||
@ -430,235 +427,6 @@ Available templates:
|
|||||||
Type: Object{},
|
Type: Object{},
|
||||||
}
|
}
|
||||||
|
|
||||||
var objectPatchCmd = &cmds.Command{
|
|
||||||
Helptext: cmds.HelpText{
|
|
||||||
Tagline: "Create a new merkledag object based on an existing one",
|
|
||||||
ShortDescription: `
|
|
||||||
'ipfs object patch <root> <cmd> <args>' is a plumbing command used to
|
|
||||||
build custom DAG objects. It adds and removes links from objects, creating a new
|
|
||||||
object as a result. This is the merkle-dag version of modifying an object. It
|
|
||||||
can also set the data inside a node with 'set-data' and append to that data as
|
|
||||||
well with 'append-data'.
|
|
||||||
|
|
||||||
Patch commands:
|
|
||||||
add-link <name> <ref> - adds a link to a node
|
|
||||||
rm-link <name> - removes a link from a node
|
|
||||||
set-data - sets a nodes data from stdin
|
|
||||||
append-data - appends to a nodes data from stdin
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
EMPTY_DIR=$(ipfs object new unixfs-dir)
|
|
||||||
BAR=$(echo "bar" | ipfs add -q)
|
|
||||||
ipfs object patch $EMPTY_DIR add-link foo $BAR
|
|
||||||
|
|
||||||
This takes an empty directory, and adds a link named foo under it, pointing to
|
|
||||||
a file containing 'bar', and returns the hash of the new object.
|
|
||||||
|
|
||||||
ipfs object patch $FOO_BAR rm-link foo
|
|
||||||
|
|
||||||
This removes the link named foo from the hash in $FOO_BAR and returns the
|
|
||||||
resulting object hash.
|
|
||||||
|
|
||||||
The data inside the node can be modified as well:
|
|
||||||
|
|
||||||
ipfs object patch $FOO_BAR set-data < file.dat
|
|
||||||
ipfs object patch $FOO_BAR append-data < file.dat
|
|
||||||
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
Options: []cmds.Option{
|
|
||||||
cmds.BoolOption("create", "p", "create intermediate directories on add-link"),
|
|
||||||
},
|
|
||||||
Arguments: []cmds.Argument{
|
|
||||||
cmds.StringArg("root", true, false, "the hash of the node to modify"),
|
|
||||||
cmds.StringArg("command", true, false, "the operation to perform"),
|
|
||||||
cmds.StringArg("args", true, true, "extra arguments").EnableStdin(),
|
|
||||||
},
|
|
||||||
Type: Object{},
|
|
||||||
Run: func(req cmds.Request, res cmds.Response) {
|
|
||||||
nd, err := req.InvocContext().GetNode()
|
|
||||||
if err != nil {
|
|
||||||
res.SetError(err, cmds.ErrNormal)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rootarg := req.Arguments()[0]
|
|
||||||
if strings.HasPrefix(rootarg, "/ipfs/") {
|
|
||||||
rootarg = rootarg[6:]
|
|
||||||
}
|
|
||||||
rhash := key.B58KeyDecode(rootarg)
|
|
||||||
if rhash == "" {
|
|
||||||
res.SetError(fmt.Errorf("incorrectly formatted root hash: %s", req.Arguments()[0]), cmds.ErrNormal)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rnode, err := nd.DAG.Get(req.Context(), rhash)
|
|
||||||
if err != nil {
|
|
||||||
res.SetError(err, cmds.ErrNormal)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
action := req.Arguments()[1]
|
|
||||||
|
|
||||||
switch action {
|
|
||||||
case "add-link":
|
|
||||||
k, err := addLinkCaller(req, rnode)
|
|
||||||
if err != nil {
|
|
||||||
res.SetError(err, cmds.ErrNormal)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res.SetOutput(&Object{Hash: k.B58String()})
|
|
||||||
case "rm-link":
|
|
||||||
k, err := rmLinkCaller(req, rnode)
|
|
||||||
if err != nil {
|
|
||||||
res.SetError(err, cmds.ErrNormal)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res.SetOutput(&Object{Hash: k.B58String()})
|
|
||||||
case "set-data":
|
|
||||||
k, err := setDataCaller(req, rnode)
|
|
||||||
if err != nil {
|
|
||||||
res.SetError(err, cmds.ErrNormal)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res.SetOutput(&Object{Hash: k.B58String()})
|
|
||||||
case "append-data":
|
|
||||||
k, err := appendDataCaller(req, rnode)
|
|
||||||
if err != nil {
|
|
||||||
res.SetError(err, cmds.ErrNormal)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res.SetOutput(&Object{Hash: k.B58String()})
|
|
||||||
default:
|
|
||||||
res.SetError(fmt.Errorf("unrecognized subcommand"), cmds.ErrNormal)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Marshalers: cmds.MarshalerMap{
|
|
||||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
|
||||||
o, ok := res.Output().(*Object)
|
|
||||||
if !ok {
|
|
||||||
return nil, u.ErrCast()
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.NewReader(o.Hash + "\n"), nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendDataCaller(req cmds.Request, root *dag.Node) (key.Key, error) {
|
|
||||||
if len(req.Arguments()) < 3 {
|
|
||||||
return "", fmt.Errorf("not enough arguments for set-data")
|
|
||||||
}
|
|
||||||
|
|
||||||
nd, err := req.InvocContext().GetNode()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
root.Data = append(root.Data, []byte(req.Arguments()[2])...)
|
|
||||||
|
|
||||||
newkey, err := nd.DAG.Add(root)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return newkey, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setDataCaller(req cmds.Request, root *dag.Node) (key.Key, error) {
|
|
||||||
if len(req.Arguments()) < 3 {
|
|
||||||
return "", fmt.Errorf("not enough arguments for set-data")
|
|
||||||
}
|
|
||||||
|
|
||||||
nd, err := req.InvocContext().GetNode()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
root.Data = []byte(req.Arguments()[2])
|
|
||||||
|
|
||||||
newkey, err := nd.DAG.Add(root)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return newkey, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func rmLinkCaller(req cmds.Request, root *dag.Node) (key.Key, error) {
|
|
||||||
if len(req.Arguments()) < 3 {
|
|
||||||
return "", fmt.Errorf("not enough arguments for rm-link")
|
|
||||||
}
|
|
||||||
|
|
||||||
nd, err := req.InvocContext().GetNode()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
path := req.Arguments()[2]
|
|
||||||
|
|
||||||
e := dagutils.NewDagEditor(root, nd.DAG)
|
|
||||||
|
|
||||||
err = e.RmLink(req.Context(), path)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
nnode, err := e.Finalize(nd.DAG)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nnode.Key()
|
|
||||||
}
|
|
||||||
|
|
||||||
func addLinkCaller(req cmds.Request, root *dag.Node) (key.Key, error) {
|
|
||||||
if len(req.Arguments()) < 4 {
|
|
||||||
return "", fmt.Errorf("not enough arguments for add-link")
|
|
||||||
}
|
|
||||||
|
|
||||||
nd, err := req.InvocContext().GetNode()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
path := req.Arguments()[2]
|
|
||||||
childk := key.B58KeyDecode(req.Arguments()[3])
|
|
||||||
|
|
||||||
create, _, err := req.Option("create").Bool()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
var createfunc func() *dag.Node
|
|
||||||
if create {
|
|
||||||
createfunc = func() *dag.Node {
|
|
||||||
return &dag.Node{Data: ft.FolderPBData()}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e := dagutils.NewDagEditor(root, nd.DAG)
|
|
||||||
|
|
||||||
childnd, err := nd.DAG.Get(req.Context(), childk)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = e.InsertNodeAtPath(req.Context(), path, childnd, createfunc)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
nnode, err := e.Finalize(nd.DAG)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nnode.Key()
|
|
||||||
}
|
|
||||||
|
|
||||||
func nodeFromTemplate(template string) (*dag.Node, error) {
|
func nodeFromTemplate(template string) (*dag.Node, error) {
|
||||||
switch template {
|
switch template {
|
||||||
case "unixfs-dir":
|
case "unixfs-dir":
|
||||||
@ -757,7 +525,6 @@ func getObjectEnc(o interface{}) objectEncoding {
|
|||||||
v, ok := o.(string)
|
v, ok := o.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
// chosen as default because it's human readable
|
// chosen as default because it's human readable
|
||||||
log.Warning("option is not a string - falling back to json")
|
|
||||||
return objectEncodingJSON
|
return objectEncodingJSON
|
||||||
}
|
}
|
||||||
|
|
308
core/commands/object/patch.go
Normal file
308
core/commands/object/patch.go
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
package objectcmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
key "github.com/ipfs/go-ipfs/blocks/key"
|
||||||
|
cmds "github.com/ipfs/go-ipfs/commands"
|
||||||
|
core "github.com/ipfs/go-ipfs/core"
|
||||||
|
dag "github.com/ipfs/go-ipfs/merkledag"
|
||||||
|
dagutils "github.com/ipfs/go-ipfs/merkledag/utils"
|
||||||
|
path "github.com/ipfs/go-ipfs/path"
|
||||||
|
ft "github.com/ipfs/go-ipfs/unixfs"
|
||||||
|
u "github.com/ipfs/go-ipfs/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ObjectPatchCmd = &cmds.Command{
|
||||||
|
Helptext: cmds.HelpText{
|
||||||
|
Tagline: "Create a new merkledag object based on an existing one",
|
||||||
|
ShortDescription: `
|
||||||
|
'ipfs object patch <root> <cmd> <args>' is a plumbing command used to
|
||||||
|
build custom DAG objects. It adds and removes links from objects, creating a new
|
||||||
|
object as a result. This is the merkle-dag version of modifying an object. It
|
||||||
|
can also set the data inside a node with 'set-data' and append to that data as
|
||||||
|
well with 'append-data'.
|
||||||
|
|
||||||
|
Patch commands:
|
||||||
|
add-link <name> <ref> - adds a link to a node
|
||||||
|
rm-link <name> - removes a link from a node
|
||||||
|
set-data - sets a nodes data from stdin
|
||||||
|
append-data - appends to a nodes data from stdin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ipfs object patch $FOO_BAR rm-link foo
|
||||||
|
|
||||||
|
This removes the link named foo from the hash in $FOO_BAR and returns the
|
||||||
|
resulting object hash.
|
||||||
|
|
||||||
|
The data inside the node can be modified as well:
|
||||||
|
|
||||||
|
ipfs object patch $FOO_BAR set-data < file.dat
|
||||||
|
ipfs object patch $FOO_BAR append-data < file.dat
|
||||||
|
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
Arguments: []cmds.Argument{},
|
||||||
|
Subcommands: map[string]*cmds.Command{
|
||||||
|
"append-data": patchAppendDataCmd,
|
||||||
|
"add-link": patchAddLinkCmd,
|
||||||
|
"rm-link": patchRmLinkCmd,
|
||||||
|
"set-data": patchSetDataCmd,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func objectMarshaler(res cmds.Response) (io.Reader, error) {
|
||||||
|
o, ok := res.Output().(*Object)
|
||||||
|
if !ok {
|
||||||
|
return nil, u.ErrCast()
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.NewReader(o.Hash + "\n"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var patchAppendDataCmd = &cmds.Command{
|
||||||
|
Helptext: cmds.HelpText{
|
||||||
|
Tagline: "Append data to the data segment of a dag node",
|
||||||
|
ShortDescription: `
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
Arguments: []cmds.Argument{
|
||||||
|
cmds.StringArg("root", true, false, "the hash of the node to modify"),
|
||||||
|
cmds.FileArg("data", true, false, "data to append").EnableStdin(),
|
||||||
|
},
|
||||||
|
Run: func(req cmds.Request, res cmds.Response) {
|
||||||
|
nd, err := req.InvocContext().GetNode()
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
root, err := path.ParsePath(req.Arguments()[0])
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rootnd, err := core.Resolve(req.Context(), nd, root)
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(req.Files())
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rootnd.Data = append(rootnd.Data, data...)
|
||||||
|
|
||||||
|
newkey, err := nd.DAG.Add(rootnd)
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res.SetOutput(&Object{Hash: newkey.B58String()})
|
||||||
|
},
|
||||||
|
Type: Object{},
|
||||||
|
Marshalers: cmds.MarshalerMap{
|
||||||
|
cmds.Text: objectMarshaler,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var patchSetDataCmd = &cmds.Command{
|
||||||
|
Helptext: cmds.HelpText{},
|
||||||
|
Arguments: []cmds.Argument{
|
||||||
|
cmds.StringArg("root", true, false, "the hash of the node to modify"),
|
||||||
|
cmds.FileArg("data", true, false, "data fill with").EnableStdin(),
|
||||||
|
},
|
||||||
|
Run: func(req cmds.Request, res cmds.Response) {
|
||||||
|
nd, err := req.InvocContext().GetNode()
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rp, err := path.ParsePath(req.Arguments()[0])
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
root, err := core.Resolve(req.Context(), nd, rp)
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(req.Files())
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
root.Data = data
|
||||||
|
|
||||||
|
newkey, err := nd.DAG.Add(root)
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res.SetOutput(&Object{Hash: newkey.B58String()})
|
||||||
|
},
|
||||||
|
Type: Object{},
|
||||||
|
Marshalers: cmds.MarshalerMap{
|
||||||
|
cmds.Text: objectMarshaler,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var patchRmLinkCmd = &cmds.Command{
|
||||||
|
Helptext: cmds.HelpText{},
|
||||||
|
Arguments: []cmds.Argument{
|
||||||
|
cmds.StringArg("root", true, false, "the hash of the node to modify"),
|
||||||
|
cmds.StringArg("link", true, false, "name of the link to remove"),
|
||||||
|
},
|
||||||
|
Run: func(req cmds.Request, res cmds.Response) {
|
||||||
|
nd, err := req.InvocContext().GetNode()
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rootp, err := path.ParsePath(req.Arguments()[0])
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
root, err := core.Resolve(req.Context(), nd, rootp)
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
path := req.Arguments()[1]
|
||||||
|
|
||||||
|
e := dagutils.NewDagEditor(root, nd.DAG)
|
||||||
|
|
||||||
|
err = e.RmLink(req.Context(), path)
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nnode, err := e.Finalize(nd.DAG)
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nk, err := nnode.Key()
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res.SetOutput(&Object{Hash: nk.B58String()})
|
||||||
|
},
|
||||||
|
Type: Object{},
|
||||||
|
Marshalers: cmds.MarshalerMap{
|
||||||
|
cmds.Text: objectMarshaler,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var patchAddLinkCmd = &cmds.Command{
|
||||||
|
Helptext: cmds.HelpText{
|
||||||
|
Tagline: "add a link to a given object",
|
||||||
|
ShortDescription: `
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
EMPTY_DIR=$(ipfs object new unixfs-dir)
|
||||||
|
BAR=$(echo "bar" | ipfs add -q)
|
||||||
|
ipfs object patch $EMPTY_DIR add-link foo $BAR
|
||||||
|
|
||||||
|
This takes an empty directory, and adds a link named foo under it, pointing to
|
||||||
|
a file containing 'bar', and returns the hash of the new object.
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
Options: []cmds.Option{
|
||||||
|
cmds.BoolOption("p", "create", "create intermediary nodes"),
|
||||||
|
},
|
||||||
|
Arguments: []cmds.Argument{
|
||||||
|
cmds.StringArg("root", true, false, "the hash of the node to modify"),
|
||||||
|
cmds.StringArg("name", true, false, "name of link to create"),
|
||||||
|
cmds.StringArg("ref", true, false, "ipfs object to add link to"),
|
||||||
|
},
|
||||||
|
Run: func(req cmds.Request, res cmds.Response) {
|
||||||
|
nd, err := req.InvocContext().GetNode()
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rootp, err := path.ParsePath(req.Arguments()[0])
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
root, err := core.Resolve(req.Context(), nd, rootp)
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
path := req.Arguments()[1]
|
||||||
|
childk := key.B58KeyDecode(req.Arguments()[2])
|
||||||
|
|
||||||
|
create, _, err := req.Option("create").Bool()
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var createfunc func() *dag.Node
|
||||||
|
if create {
|
||||||
|
createfunc = func() *dag.Node {
|
||||||
|
return &dag.Node{Data: ft.FolderPBData()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e := dagutils.NewDagEditor(root, nd.DAG)
|
||||||
|
|
||||||
|
childnd, err := nd.DAG.Get(req.Context(), childk)
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = e.InsertNodeAtPath(req.Context(), path, childnd, createfunc)
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nnode, err := e.Finalize(nd.DAG)
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nk, err := nnode.Key()
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmds.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res.SetOutput(&Object{Hash: nk.B58String()})
|
||||||
|
},
|
||||||
|
Type: Object{},
|
||||||
|
Marshalers: cmds.MarshalerMap{
|
||||||
|
cmds.Text: objectMarshaler,
|
||||||
|
},
|
||||||
|
}
|
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
cmds "github.com/ipfs/go-ipfs/commands"
|
cmds "github.com/ipfs/go-ipfs/commands"
|
||||||
files "github.com/ipfs/go-ipfs/core/commands/files"
|
files "github.com/ipfs/go-ipfs/core/commands/files"
|
||||||
|
ocmd "github.com/ipfs/go-ipfs/core/commands/object"
|
||||||
unixfs "github.com/ipfs/go-ipfs/core/commands/unixfs"
|
unixfs "github.com/ipfs/go-ipfs/core/commands/unixfs"
|
||||||
logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
|
logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
|
||||||
)
|
)
|
||||||
@ -107,7 +108,7 @@ var rootSubcommands = map[string]*cmds.Command{
|
|||||||
"ls": LsCmd,
|
"ls": LsCmd,
|
||||||
"mount": MountCmd,
|
"mount": MountCmd,
|
||||||
"name": NameCmd,
|
"name": NameCmd,
|
||||||
"object": ObjectCmd,
|
"object": ocmd.ObjectCmd,
|
||||||
"pin": PinCmd,
|
"pin": PinCmd,
|
||||||
"ping": PingCmd,
|
"ping": PingCmd,
|
||||||
"refs": RefsCmd,
|
"refs": RefsCmd,
|
||||||
@ -148,11 +149,11 @@ var rootROSubcommands = map[string]*cmds.Command{
|
|||||||
},
|
},
|
||||||
"object": &cmds.Command{
|
"object": &cmds.Command{
|
||||||
Subcommands: map[string]*cmds.Command{
|
Subcommands: map[string]*cmds.Command{
|
||||||
"data": objectDataCmd,
|
"data": ocmd.ObjectDataCmd,
|
||||||
"links": objectLinksCmd,
|
"links": ocmd.ObjectLinksCmd,
|
||||||
"get": objectGetCmd,
|
"get": ocmd.ObjectGetCmd,
|
||||||
"stat": objectStatCmd,
|
"stat": ocmd.ObjectStatCmd,
|
||||||
"patch": objectPatchCmd,
|
"patch": ocmd.ObjectPatchCmd,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"refs": RefsROCmd,
|
"refs": RefsROCmd,
|
||||||
|
@ -16,7 +16,7 @@ test_patch_create_path() {
|
|||||||
target=$3
|
target=$3
|
||||||
|
|
||||||
test_expect_success "object patch --create works" '
|
test_expect_success "object patch --create works" '
|
||||||
PCOUT=$(ipfs object patch --create $root add-link $name $target)
|
PCOUT=$(ipfs object patch $root add-link --create $name $target)
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "output looks good" '
|
test_expect_success "output looks good" '
|
||||||
|
Reference in New Issue
Block a user