object plumbing commands
Henry committed
Oct 18, 2014 at 04:35 UTC
e735addbb2721e92831715664f515720203c0866
3 files changed
+248
cmd/ipfs/ipfs.go
+5
@@ -37,6 +37,10 @@ Tool commands:
37
version Show ipfs version information.
38
commands List all available commands.
39
40
+Plumbing commands:
41
+ block Interact with raw blocks in the datastore
42
+ object Interact with raw dag nodes
43
+
44
Advanced Commands:
45
46
mount Mount an ipfs read-only mountpoint.
@@ -63,6 +67,7 @@ Use "ipfs help <command>" for more information about a command.
67
cmdIpfsBootstrap,
68
cmdIpfsDiag,
69
cmdIpfsBlock,
70
+ cmdIpfsObject,
71
cmdIpfsLog,
72
},
73
Flag: *flag.NewFlagSet("ipfs", flag.ExitOnError),
cmd/ipfs/objects.go
new
+112
@@ -0,0 +1,112 @@
1
+package main
2
+
3
+import (
4
+ flag "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
5
+ commander "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
6
+ "github.com/jbenet/go-ipfs/core/commands"
7
+)
8
+
9
+var cmdIpfsObject = &commander.Command{
10
+ UsageLine: "object",
11
+ Short: "interact with ipfs objects",
12
+ Long: `ipfs object - interact with ipfs objects
13
+
14
+ ipfs object data <key> - return the data for this key as raw bytes
15
+ ipfs object links <key> - lists (the keys of ?) the links this key points to
16
+ ipfs object get <key> - output dag object to stdout
17
+ ipfs object put - add dag object from stdin
18
+
19
+ipfs object is a plumbing command used to manipulate dag objects directly.
20
+- <key> is a base58 encoded multihash.
21
+- It reads from stdin or writes to stdout.
22
+- It accepts multiple encodings: --encoding=[ protobuf, json, ... ]`,
23
+ Subcommands: []*commander.Command{
24
+ cmdIpfsObjectData,
25
+ cmdIpfsObjectLinks,
26
+ cmdIpfsObjectGet,
27
+ cmdIpfsObjectPut,
28
+ },
29
+ Flag: *flag.NewFlagSet("ipfs-object", flag.ExitOnError),
30
+}
31
+
32
+var cmdIpfsObjectData = &commander.Command{
33
+ UsageLine: "data <key>",
34
+ Short: "data outputs the raw bytes named by <key>",
35
+ Long: `ipfs data <key> - data outputs the raw bytes named by <key>
36
+
37
+ipfs data is a plumbing command for retreiving the raw bytes stored in a dag node.
38
+It outputs to stdout, and <key> is a base58 encoded multihash.`,
39
+ Run: makeCommand(command{
40
+ name: "objectData",
41
+ args: 1,
42
+ flags: nil,
43
+ online: true,
44
+ cmdFn: commands.ObjectData,
45
+ }),
46
+}
47
+
48
+var cmdIpfsObjectLinks = &commander.Command{
49
+ UsageLine: "links <key>",
50
+ Short: "outputs the links pointed to by <key>",
51
+ Long: `ipfs links <key> - outputs the links pointed to by <key>
52
+
53
+ipfs block get is a plumbing command for retreiving raw ipfs blocks.
54
+It outputs to stdout, and <key> is a base58 encoded multihash.`,
55
+ Run: makeCommand(command{
56
+ name: "objectLinks",
57
+ args: 1,
58
+ flags: nil,
59
+ online: true,
60
+ cmdFn: commands.ObjectLinks,
61
+ }),
62
+}
63
+
64
+func init() {
65
+ cmdIpfsObjectGet.Flag.String("encoding", "json", "the encoding to use..")
66
+ cmdIpfsObjectPut.Flag.String("encoding", "json", "the encoding to use..")
67
+}
68
+
69
+var cmdIpfsObjectGet = &commander.Command{
70
+ UsageLine: "get <key>",
71
+ Short: "get and serialize the dag node named by <key>",
72
+ Long: `ipfs get <key> - get and output the dag node named by <key>
73
+
74
+ipfs object get is a plumbing command for retreiving dag nodes.
75
+It serialize the dag node to the format specified by the format flag.
76
+It outputs to stdout, and <key> is a base58 encoded multihash.
77
+
78
+Formats:
79
+
80
+This command outputs and accepts data in a variety of encodings: protobuf, json, etc.
81
+Use the --encoding flag
82
+`,
83
+ Run: makeCommand(command{
84
+ name: "blockGet",
85
+ args: 1,
86
+ flags: []string{"encoding"},
87
+ online: true,
88
+ cmdFn: commands.ObjectGet,
89
+ }),
90
+}
91
+
92
+var cmdIpfsObjectPut = &commander.Command{
93
+ UsageLine: "put",
94
+ Short: "store stdin as a dag object, outputs <key>",
95
+ Long: `ipfs put - store stdin as a dag object, outputs <key>
96
+
97
+ipfs object put is a plumbing command for storing dag nodes.
98
+It serialize the dag node to the format specified by the format flag.
99
+It reads from stding, and <key> is a base58 encoded multihash.
100
+
101
+Formats:
102
+
103
+This command outputs and accepts data in a variety of encodings: protobuf, json, etc.
104
+Use the --encoding flag`,
105
+ Run: makeCommand(command{
106
+ name: "blockPut",
107
+ args: 0,
108
+ flags: []string{"encoding"},
109
+ online: true,
110
+ cmdFn: commands.ObjectPut,
111
+ }),
112
+}
core/commands/object.go
new
+131
@@ -0,0 +1,131 @@
1
+package commands
2
+
3
+import (
4
+ "bytes"
5
+ "encoding/json"
6
+ "errors"
7
+ "fmt"
8
+ "io"
9
+ "io/ioutil"
10
+ "os"
11
+
12
+ "github.com/jbenet/go-ipfs/core"
13
+ dag "github.com/jbenet/go-ipfs/merkledag"
14
+)
15
+
16
+// ObjectData takes a key string from args and writes out the raw bytes of that node (if there is one)
17
+func ObjectData(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
18
+ dagnode, err := n.Resolver.ResolvePath(args[0])
19
+ if err != nil {
20
+ return fmt.Errorf("objectData error: %v", err)
21
+ }
22
+ log.Debug("objectData: found dagnode %q (# of bytes: %d - # links: %d)", args[0], len(dagnode.Data), len(dagnode.Links))
23
+
24
+ _, err = io.Copy(out, bytes.NewReader(dagnode.Data))
25
+ return err
26
+}
27
+
28
+// ObjectLinks takes a key string from args and lists the links it points to
29
+func ObjectLinks(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
30
+ dagnode, err := n.Resolver.ResolvePath(args[0])
31
+ if err != nil {
32
+ return fmt.Errorf("objectLinks error: %v", err)
33
+ }
34
+ log.Debug("ObjectLinks: found dagnode %q (# of bytes: %d - # links: %d)", args[0], len(dagnode.Data), len(dagnode.Links))
35
+
36
+ if len(dagnode.Links) == 0 {
37
+ // TODO(cryptix): named error?
38
+ return errors.New("objectLinks: no links in this node")
39
+ }
40
+
41
+ for _, link := range dagnode.Links {
42
+ _, err = fmt.Fprintf(out, "%s %d %q\n", link.Hash.B58String(), link.Size, link.Name)
43
+ if err != nil {
44
+ break
45
+ }
46
+ }
47
+
48
+ return err
49
+}
50
+
51
+// ErrUnknownObjectEnc is returned if a invalid encoding is supplied
52
+var ErrUnknownObjectEnc = errors.New("unknown object encoding")
53
+
54
+type objectEncoding string
55
+
56
+const (
57
+ objectEncodingJSON objectEncoding = "json"
58
+ objectEncodingProtobuf = "protobuf"
59
+)
60
+
61
+func getObjectEnc(o interface{}) objectEncoding {
62
+ v, ok := o.(string)
63
+ if !ok {
64
+ // chosen as default because it's human readable
65
+ log.Warning("option is not a string - falling back to json")
66
+ return objectEncodingJSON
67
+ }
68
+
69
+ return objectEncoding(v)
70
+}
71
+
72
+// ObjectGet takes a key string from args and a format option and serializes the dagnode to that format
73
+func ObjectGet(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
74
+ dagnode, err := n.Resolver.ResolvePath(args[0])
75
+ if err != nil {
76
+ return fmt.Errorf("ObjectGet error: %v", err)
77
+ }
78
+ log.Debug("objectGet: found dagnode %q (# of bytes: %d - # links: %d)", args[0], len(dagnode.Data), len(dagnode.Links))
79
+
80
+ // sadly all encodings dont implement a common interface
81
+ var data []byte
82
+ switch getObjectEnc(opts["encoding"]) {
83
+ case objectEncodingJSON:
84
+ data, err = json.MarshalIndent(dagnode, "", " ")
85
+
86
+ case objectEncodingProtobuf:
87
+ data, err = dagnode.Marshal()
88
+
89
+ default:
90
+ return ErrUnknownObjectEnc
91
+ }
92
+
93
+ if err != nil {
94
+ return fmt.Errorf("ObjectGet error: %v", err)
95
+ }
96
+
97
+ _, err = io.Copy(out, bytes.NewReader(data))
98
+ return err
99
+}
100
+
101
+// ObjectPut takes a format option, serilizes bytes from stdin and updates the dag with that data
102
+func ObjectPut(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
103
+ var (
104
+ dagnode *dag.Node
105
+ data []byte
106
+ err error
107
+ )
108
+
109
+ data, err = ioutil.ReadAll(os.Stdin)
110
+ if err != nil {
111
+ return fmt.Errorf("ObjectPut error: %v", err)
112
+ }
113
+
114
+ switch getObjectEnc(opts["encoding"]) {
115
+ case objectEncodingJSON:
116
+ dagnode = new(dag.Node)
117
+ err = json.Unmarshal(data, dagnode)
118
+
119
+ case objectEncodingProtobuf:
120
+ dagnode, err = dag.Decoded(data)
121
+
122
+ default:
123
+ return ErrUnknownObjectEnc
124
+ }
125
+
126
+ if err != nil {
127
+ return fmt.Errorf("ObjectPut error: %v", err)
128
+ }
129
+
130
+ return addNode(n, dagnode, "stdin", out)
131
+}