@cryptotaxi247 / kubo / commits / f28752494

cmd: use go-ipfs-cmds

License: MIT Signed-off-by: keks <keks@cryptoscope.co>

Jan Winkelmann committed Apr 1, 2017 at 16:58 UTC f28752494989792342168e0d7422bfb81ae508f1
119 files changed +2912 -3332
blocks/blockstore/caching.go
+1
@@ -4,6 +4,7 @@ import (
4 "errors"
5
6 context "context"
7 +
8 "gx/ipfs/QmRg1gKTHzc3CZXSKzem8aR4E3TubFhbgXwfVuWnSK5CC5/go-metrics-interface"
9 )
10
blocks/blockstore/util/remove.go
+10 -5
@@ -85,12 +85,17 @@ func FilterPinned(pins pin.Pinner, out chan<- interface{}, cids []*cid.Cid) []*c
85 return stillOkay
86 }
87
88 -// ProcRmOutput takes the channel returned by RmBlocks and writes
89 -// to stdout/stderr according to the RemovedBlock objects received in
90 -// that channel.
91 -func ProcRmOutput(in <-chan interface{}, sout io.Writer, serr io.Writer) error {
88 +// ProcRmOutput takes a function which returns a result from RmBlocks or EOF if there is no input.
89 +// It then writes to stdout/stderr according to the RemovedBlock object returned from the function.
90 +func ProcRmOutput(next func() (interface{}, error), sout io.Writer, serr io.Writer) error {
91 someFailed := false
93 - for res := range in {
92 + for {
93 + res, err := next()
94 + if err == io.EOF {
95 + break
96 + } else if err != nil {
97 + return err
98 + }
99 r := res.(*RemovedBlock)
100 if r.Hash == "" && r.Error != "" {
101 return fmt.Errorf("aborted: %s", r.Error)
cmd/ipfs/daemon.go
+41 -39
@@ -11,7 +11,6 @@ import (
11 "sort"
12 "sync"
13
14 - cmds "github.com/ipfs/go-ipfs/commands"
14 "github.com/ipfs/go-ipfs/core"
15 commands "github.com/ipfs/go-ipfs/core/commands"
16 corehttp "github.com/ipfs/go-ipfs/core/corehttp"
@@ -20,6 +19,8 @@ import (
19 fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
20 migrate "github.com/ipfs/go-ipfs/repo/fsrepo/migrations"
21
22 + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
23 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
24 mprome "gx/ipfs/QmSk46nSD78YiuNojYMS8NW6hSCjH95JajqqzzoychZgef/go-metrics-prometheus"
25 "gx/ipfs/QmX3QZ5jHEPidwUrymXV1iSCSUhdGxj15sm2gP4jKMef7B/client_golang/prometheus"
26 "gx/ipfs/QmX3U3YXCQ6UYBxq2LVWF8dARS1hPUTEYLrSx654Qyxyw6/go-multiaddr-net"
@@ -51,7 +52,7 @@ const (
52 )
53
54 var daemonCmd = &cmds.Command{
54 - Helptext: cmds.HelpText{
55 + Helptext: cmdkit.HelpText{
56 Tagline: "Run a network-connected IPFS node.",
57 ShortDescription: `
58 'ipfs daemon' runs a persistent ipfs daemon that can serve commands
@@ -142,24 +143,25 @@ Headers.
143 `,
144 },
145
145 - Options: []cmds.Option{
146 - cmds.BoolOption(initOptionKwd, "Initialize ipfs with default settings if not already initialized").Default(false),
147 - cmds.StringOption(routingOptionKwd, "Overrides the routing option").Default("dht"),
148 - cmds.BoolOption(mountKwd, "Mounts IPFS to the filesystem").Default(false),
149 - cmds.BoolOption(writableKwd, "Enable writing objects (with POST, PUT and DELETE)").Default(false),
150 - cmds.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount). Defaults to config setting."),
151 - cmds.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount). Defaults to config setting."),
152 - cmds.BoolOption(unrestrictedApiAccessKwd, "Allow API access to unlisted hashes").Default(false),
153 - cmds.BoolOption(unencryptTransportKwd, "Disable transport encryption (for debugging protocols)").Default(false),
154 - cmds.BoolOption(enableGCKwd, "Enable automatic periodic repo garbage collection").Default(false),
155 - cmds.BoolOption(adjustFDLimitKwd, "Check and raise file descriptor limits if needed").Default(true),
156 - cmds.BoolOption(offlineKwd, "Run offline. Do not connect to the rest of the network but provide local API.").Default(false),
157 - cmds.BoolOption(migrateKwd, "If true, assume yes at the migrate prompt. If false, assume no."),
158 - cmds.BoolOption(enableFloodSubKwd, "Instantiate the ipfs daemon with the experimental pubsub feature enabled."),
159 - cmds.BoolOption(enableMultiplexKwd, "Add the experimental 'go-multiplex' stream muxer to libp2p on construction.").Default(true),
146 + Options: []cmdkit.Option{
147 + cmdkit.BoolOption(initOptionKwd, "Initialize ipfs with default settings if not already initialized").Default(false),
148 + cmdkit.StringOption(routingOptionKwd, "Overrides the routing option").Default("dht"),
149 + cmdkit.BoolOption(mountKwd, "Mounts IPFS to the filesystem").Default(false),
150 + cmdkit.BoolOption(writableKwd, "Enable writing objects (with POST, PUT and DELETE)").Default(false),
151 + cmdkit.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount). Defaults to config setting."),
152 + cmdkit.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount). Defaults to config setting."),
153 + cmdkit.BoolOption(unrestrictedApiAccessKwd, "Allow API access to unlisted hashes").Default(false),
154 + cmdkit.BoolOption(unencryptTransportKwd, "Disable transport encryption (for debugging protocols)").Default(false),
155 + cmdkit.BoolOption(enableGCKwd, "Enable automatic periodic repo garbage collection").Default(false),
156 + cmdkit.BoolOption(adjustFDLimitKwd, "Check and raise file descriptor limits if needed").Default(true),
157 + cmdkit.BoolOption(offlineKwd, "Run offline. Do not connect to the rest of the network but provide local API.").Default(false),
158 + cmdkit.BoolOption(migrateKwd, "If true, assume yes at the migrate prompt. If false, assume no."),
159 + cmdkit.BoolOption(enableFloodSubKwd, "Instantiate the ipfs daemon with the experimental pubsub feature enabled."),
160 + cmdkit.BoolOption(enableMultiplexKwd, "Add the experimental 'go-multiplex' stream muxer to libp2p on construction.").Default(true),
161 +
162 // TODO: add way to override addresses. tricky part: updating the config if also --init.
161 - // cmds.StringOption(apiAddrKwd, "Address for the daemon rpc API (overrides config)"),
162 - // cmds.StringOption(swarmAddrKwd, "Address for the swarm socket (overrides config)"),
163 + // cmdkit.StringOption(apiAddrKwd, "Address for the daemon rpc API (overrides config)"),
164 + // cmdkit.StringOption(swarmAddrKwd, "Address for the swarm socket (overrides config)"),
165 },
166 Subcommands: map[string]*cmds.Command{},
167 Run: daemonFunc,
@@ -178,7 +180,7 @@ func defaultMux(path string) corehttp.ServeOption {
180
181 var fileDescriptorCheck = func() error { return nil }
182
181 -func daemonFunc(req cmds.Request, res cmds.Response) {
183 +func daemonFunc(req cmds.Request, re cmds.ResponseEmitter) {
184 // Inject metrics before we do anything
185
186 err := mprome.Inject()
@@ -216,7 +218,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
218 // running in an uninitialized state.
219 initialize, _, err := req.Option(initOptionKwd).Bool()
220 if err != nil {
219 - res.SetError(err, cmds.ErrNormal)
221 + re.SetError(err, cmdkit.ErrNormal)
222 return
223 }
224
@@ -226,7 +228,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
228 if !fsrepo.IsInitialized(cfg) {
229 err := initWithDefaults(os.Stdout, cfg)
230 if err != nil {
229 - res.SetError(err, cmds.ErrNormal)
231 + re.SetError(err, cmdkit.ErrNormal)
232 return
233 }
234 }
@@ -237,7 +239,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
239 repo, err := fsrepo.Open(ctx.ConfigRoot)
240 switch err {
241 default:
240 - res.SetError(err, cmds.ErrNormal)
242 + re.SetError(err, cmdkit.ErrNormal)
243 return
244 case fsrepo.ErrNeedMigration:
245 domigrate, found, _ := req.Option(migrateKwd).Bool()
@@ -250,7 +252,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
252 if !domigrate {
253 fmt.Println("Not running migrations of fs-repo now.")
254 fmt.Println("Please get fs-repo-migrations from https://dist.ipfs.io")
253 - res.SetError(fmt.Errorf("fs-repo requires migration"), cmds.ErrNormal)
255 + re.SetError(fmt.Errorf("fs-repo requires migration"), cmdkit.ErrNormal)
256 return
257 }
258
@@ -260,13 +262,13 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
262 fmt.Printf(" %s\n", err)
263 fmt.Println("If you think this is a bug, please file an issue and include this whole log output.")
264 fmt.Println(" https://github.com/ipfs/fs-repo-migrations")
263 - res.SetError(err, cmds.ErrNormal)
265 + re.SetError(err, cmdkit.ErrNormal)
266 return
267 }
268
269 repo, err = fsrepo.Open(ctx.ConfigRoot)
270 if err != nil {
269 - res.SetError(err, cmds.ErrNormal)
271 + re.SetError(err, cmdkit.ErrNormal)
272 return
273 }
274 case nil:
@@ -275,7 +277,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
277
278 cfg, err := ctx.GetConfig()
279 if err != nil {
278 - res.SetError(err, cmds.ErrNormal)
280 + re.SetError(err, cmdkit.ErrNormal)
281 return
282 }
283
@@ -297,12 +299,12 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
299
300 routingOption, _, err := req.Option(routingOptionKwd).String()
301 if err != nil {
300 - res.SetError(err, cmds.ErrNormal)
302 + re.SetError(err, cmdkit.ErrNormal)
303 return
304 }
305 switch routingOption {
306 case routingOptionSupernodeKwd:
305 - res.SetError(errors.New("supernode routing was never fully implemented and has been removed"), cmds.ErrNormal)
307 + re.SetError(errors.New("supernode routing was never fully implemented and has been removed"), cmdkit.ErrNormal)
308 return
309 case routingOptionDHTClientKwd:
310 ncfg.Routing = core.DHTClientOption
@@ -311,14 +313,14 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
313 case routingOptionNoneKwd:
314 ncfg.Routing = core.NilRouterOption
315 default:
314 - res.SetError(fmt.Errorf("unrecognized routing option: %s", routingOption), cmds.ErrNormal)
316 + re.SetError(fmt.Errorf("unrecognized routing option: %s", routingOption), cmdkit.ErrNormal)
317 return
318 }
319
320 node, err := core.NewNode(req.Context(), ncfg)
321 if err != nil {
322 log.Error("error from node construction: ", err)
321 - res.SetError(err, cmds.ErrNormal)
323 + re.SetError(err, cmdkit.ErrNormal)
324 return
325 }
326 node.SetLocal(false)
@@ -349,24 +351,24 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
351 // construct api endpoint - every time
352 err, apiErrc := serveHTTPApi(req)
353 if err != nil {
352 - res.SetError(err, cmds.ErrNormal)
354 + re.SetError(err, cmdkit.ErrNormal)
355 return
356 }
357
358 // construct fuse mountpoints - if the user provided the --mount flag
359 mount, _, err := req.Option(mountKwd).Bool()
360 if err != nil {
359 - res.SetError(err, cmds.ErrNormal)
361 + re.SetError(err, cmdkit.ErrNormal)
362 return
363 }
364 if mount && offline {
363 - res.SetError(errors.New("mount is not currently supported in offline mode"),
364 - cmds.ErrClient)
365 + re.SetError(errors.New("mount is not currently supported in offline mode"),
366 + cmdkit.ErrClient)
367 return
368 }
369 if mount {
370 if err := mountFuse(req); err != nil {
369 - res.SetError(err, cmds.ErrNormal)
371 + re.SetError(err, cmdkit.ErrNormal)
372 return
373 }
374 }
@@ -374,7 +376,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
376 // repo blockstore GC - if --enable-gc flag is present
377 err, gcErrc := maybeRunGC(req, node)
378 if err != nil {
377 - res.SetError(err, cmds.ErrNormal)
379 + re.SetError(err, cmdkit.ErrNormal)
380 return
381 }
382
@@ -384,7 +386,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
386 var err error
387 err, gwErrc = serveHTTPGateway(req)
388 if err != nil {
387 - res.SetError(err, cmds.ErrNormal)
389 + re.SetError(err, cmdkit.ErrNormal)
390 return
391 }
392 }
@@ -398,7 +400,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
400 for err := range merge(apiErrc, gwErrc, gcErrc) {
401 if err != nil {
402 log.Error(err)
401 - res.SetError(err, cmds.ErrNormal)
403 + re.SetError(err, cmdkit.ErrNormal)
404 }
405 }
406 }
cmd/ipfs/init.go
+21 -16
@@ -1,6 +1,7 @@
1 package main
2
3 import (
4 + "context"
5 "encoding/json"
6 "errors"
7 "fmt"
@@ -9,13 +10,14 @@ import (
10 "path"
11 "strings"
12
12 - context "context"
13 assets "github.com/ipfs/go-ipfs/assets"
14 cmds "github.com/ipfs/go-ipfs/commands"
15 core "github.com/ipfs/go-ipfs/core"
16 namesys "github.com/ipfs/go-ipfs/namesys"
17 config "github.com/ipfs/go-ipfs/repo/config"
18 fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
19 +
20 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
21 )
22
23 const (
@@ -23,7 +25,7 @@ const (
25 )
26
27 var initCmd = &cmds.Command{
26 - Helptext: cmds.HelpText{
28 + Helptext: cmdkit.HelpText{
29 Tagline: "Initializes ipfs config file.",
30 ShortDescription: `
31 Initializes ipfs configuration files and generates a new keypair.
@@ -44,18 +46,18 @@ environment variable:
46 export IPFS_PATH=/path/to/ipfsrepo
47 `,
48 },
47 - Arguments: []cmds.Argument{
48 - cmds.FileArg("default-config", false, false, "Initialize with the given configuration.").EnableStdin(),
49 + Arguments: []cmdkit.Argument{
50 + cmdkit.FileArg("default-config", false, false, "Initialize with the given configuration.").EnableStdin(),
51 },
50 - Options: []cmds.Option{
51 - cmds.IntOption("bits", "b", "Number of bits to use in the generated RSA private key.").Default(nBitsForKeypairDefault),
52 - cmds.BoolOption("empty-repo", "e", "Don't add and pin help files to the local storage.").Default(false),
53 - cmds.StringOption("profile", "p", "Apply profile settings to config. Multiple profiles can be separated by ','"),
52 + Options: []cmdkit.Option{
53 + cmdkit.IntOption("bits", "b", "Number of bits to use in the generated RSA private key.").Default(nBitsForKeypairDefault),
54 + cmdkit.BoolOption("empty-repo", "e", "Don't add and pin help files to the local storage.").Default(false),
55 + cmdkit.StringOption("profile", "p", "Apply profile settings to config. Multiple profiles can be separated by ','"),
56
57 // TODO need to decide whether to expose the override as a file or a
58 // directory. That is: should we allow the user to also specify the
59 // name of the file?
58 - // TODO cmds.StringOption("event-logs", "l", "Location for machine-readable event logs."),
60 + // TODO cmdkit.StringOption("event-logs", "l", "Location for machine-readable event logs."),
61 },
62 PreRun: func(req cmds.Request) error {
63 daemonLocked, err := fsrepo.LockedByOtherProcess(req.InvocContext().ConfigRoot)
@@ -73,20 +75,23 @@ environment variable:
75 return nil
76 },
77 Run: func(req cmds.Request, res cmds.Response) {
78 + // needs to be called at least once
79 + res.SetOutput(nil)
80 +
81 if req.InvocContext().Online {
77 - res.SetError(errors.New("init must be run offline only!"), cmds.ErrNormal)
82 + res.SetError(errors.New("init must be run offline only!"), cmdkit.ErrNormal)
83 return
84 }
85
86 empty, _, err := req.Option("e").Bool()
87 if err != nil {
83 - res.SetError(err, cmds.ErrNormal)
88 + res.SetError(err, cmdkit.ErrNormal)
89 return
90 }
91
92 nBitsForKeypair, _, err := req.Option("b").Int()
93 if err != nil {
89 - res.SetError(err, cmds.ErrNormal)
94 + res.SetError(err, cmdkit.ErrNormal)
95 return
96 }
97
@@ -96,20 +101,20 @@ environment variable:
101 if f != nil {
102 confFile, err := f.NextFile()
103 if err != nil {
99 - res.SetError(err, cmds.ErrNormal)
104 + res.SetError(err, cmdkit.ErrNormal)
105 return
106 }
107
108 conf = &config.Config{}
109 if err := json.NewDecoder(confFile).Decode(conf); err != nil {
105 - res.SetError(err, cmds.ErrNormal)
110 + res.SetError(err, cmdkit.ErrNormal)
111 return
112 }
113 }
114
115 profile, _, err := req.Option("profile").String()
116 if err != nil {
112 - res.SetError(err, cmds.ErrNormal)
117 + res.SetError(err, cmdkit.ErrNormal)
118 return
119 }
120
@@ -119,7 +124,7 @@ environment variable:
124 }
125
126 if err := doInit(os.Stdout, req.InvocContext().ConfigRoot, empty, nBitsForKeypair, profiles, conf); err != nil {
122 - res.SetError(err, cmds.ErrNormal)
127 + res.SetError(err, cmdkit.ErrNormal)
128 return
129 }
130 },
cmd/ipfs/ipfs.go
+19 -15
@@ -3,8 +3,10 @@ package main
3 import (
4 "fmt"
5
6 - cmds "github.com/ipfs/go-ipfs/commands"
6 + oldcmds "github.com/ipfs/go-ipfs/commands"
7 commands "github.com/ipfs/go-ipfs/core/commands"
8 +
9 + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
10 )
11
12 // This is the CLI root, used for executing commands accessible to CLI clients.
@@ -22,7 +24,7 @@ var commandsClientCmd = commands.CommandsCmd(Root)
24 // They can override subcommands in commands.Root by defining a subcommand with the same name.
25 var localCommands = map[string]*cmds.Command{
26 "daemon": daemonCmd,
25 - "init": initCmd,
27 + "init": cmds.NewCommand(initCmd),
28 "commands": commandsClientCmd,
29 }
30 var localMap = make(map[*cmds.Command]bool)
@@ -31,8 +33,14 @@ func init() {
33 // setting here instead of in literal to prevent initialization loop
34 // (some commands make references to Root)
35 Root.Subcommands = localCommands
36 + Root.OldSubcommands = map[string]*oldcmds.Command{}
37
38 // copy all subcommands from commands.Root into this root (if they aren't already present)
39 + for k, v := range commands.Root.OldSubcommands {
40 + if _, found := Root.OldSubcommands[k]; !found {
41 + Root.OldSubcommands[k] = v
42 + }
43 + }
44 for k, v := range commands.Root.Subcommands {
45 if _, found := Root.Subcommands[k]; !found {
46 Root.Subcommands[k] = v
@@ -88,17 +96,13 @@ func (d *cmdDetails) usesRepo() bool { return !d.doesNotUseRepo }
96 // not being able to run on all the same contexts. This map describes these
97 // properties so that other code can make decisions about whether to invoke a
98 // command or return an error to the user.
91 -var cmdDetailsMap = map[*cmds.Command]cmdDetails{
92 - initCmd: {doesNotUseConfigAsInput: true, cannotRunOnDaemon: true, doesNotUseRepo: true},
93 -
94 - // daemonCmd allows user to initialize the config. Thus, it may be called
95 - // without using the config as input
96 - daemonCmd: {doesNotUseConfigAsInput: true, cannotRunOnDaemon: true},
97 - commandsClientCmd: {doesNotUseRepo: true},
98 - commands.CommandsDaemonCmd: {doesNotUseRepo: true},
99 - commands.VersionCmd: {doesNotUseConfigAsInput: true, doesNotUseRepo: true}, // must be permitted to run before init
100 - commands.LogCmd: {cannotRunOnClient: true},
101 - commands.ActiveReqsCmd: {cannotRunOnClient: true},
102 - commands.RepoFsckCmd: {cannotRunOnDaemon: true},
103 - commands.ConfigCmd.Subcommand("edit"): {cannotRunOnDaemon: true, doesNotUseRepo: true},
99 +var cmdDetailsMap = map[string]cmdDetails{
100 + "init": {doesNotUseConfigAsInput: true, cannotRunOnDaemon: true, doesNotUseRepo: true},
101 + "daemon": {doesNotUseConfigAsInput: true, cannotRunOnDaemon: true},
102 + "commands": {doesNotUseRepo: true},
103 + "version": {doesNotUseConfigAsInput: true, doesNotUseRepo: true}, // must be permitted to run before init
104 + "log": {cannotRunOnClient: true},
105 + "diag/cmds": {cannotRunOnClient: true},
106 + "repo/fsck": {cannotRunOnDaemon: true},
107 + "config/edit": {cannotRunOnDaemon: true, doesNotUseRepo: true},
108 }
cmd/ipfs/main.go
+90 -63
@@ -18,9 +18,6 @@ import (
18 "syscall"
19 "time"
20
21 - cmds "github.com/ipfs/go-ipfs/commands"
22 - cmdsCli "github.com/ipfs/go-ipfs/commands/cli"
23 - cmdsHttp "github.com/ipfs/go-ipfs/commands/http"
21 core "github.com/ipfs/go-ipfs/core"
22 coreCmds "github.com/ipfs/go-ipfs/core/commands"
23 "github.com/ipfs/go-ipfs/plugin/loader"
@@ -28,6 +25,10 @@ import (
25 config "github.com/ipfs/go-ipfs/repo/config"
26 fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
27
28 + "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
29 + "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds/cli"
30 + "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds/http"
31 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
32 u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
33 logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
34 loggables "gx/ipfs/QmT4PgCNdv73hnFAqzHqwW44q7M9PWpykSswHDxndquZbc/go-libp2p-loggables"
@@ -54,6 +55,12 @@ type cmdInvocation struct {
55 node *core.IpfsNode
56 }
57
58 +type exitErr int
59 +
60 +func (e exitErr) Error() string {
61 + return fmt.Sprint("exit code", int(e))
62 +}
63 +
64 // main roadmap:
65 // - parse the commandline to get a cmdInvocation
66 // - if user requests help, print it and exit.
@@ -68,8 +75,6 @@ func mainRet() int {
75 rand.Seed(time.Now().UnixNano())
76 ctx := logging.ContextWithLoggable(context.Background(), loggables.Uuid("session"))
77 var err error
71 - var invoc cmdInvocation
72 - defer invoc.close()
78
79 // we'll call this local helper to output errors.
80 // this is so we control how to print errors in one place.
@@ -84,12 +89,15 @@ func mainRet() int {
89 }
90 defer stopFunc() // to be executed as late as possible
91
92 + var invoc cmdInvocation
93 + defer invoc.close()
94 +
95 // this is a local helper to print out help text.
96 // there's some considerations that this makes easier.
97 printHelp := func(long bool, w io.Writer) {
90 - helpFunc := cmdsCli.ShortHelp
98 + helpFunc := cli.ShortHelp
99 if long {
92 - helpFunc = cmdsCli.LongHelp
100 + helpFunc = cli.LongHelp
101 }
102
103 helpFunc("ipfs", Root, invoc.path, w)
@@ -154,8 +162,12 @@ func mainRet() int {
162 intrh, ctx := invoc.SetupInterruptHandler(ctx)
163 defer intrh.Close()
164
157 - output, err := invoc.Run(ctx)
165 + err = invoc.Run(ctx)
166 if err != nil {
167 + if code, ok := err.(exitErr); ok {
168 + return int(code)
169 + }
170 +
171 printErr(err)
172
173 // if this error was a client error, print short help too.
@@ -166,20 +178,15 @@ func mainRet() int {
178 }
179
180 // everything went better than expected :)
169 - _, err = io.Copy(os.Stdout, output)
170 - if err != nil {
171 - printErr(err)
172 - return 1
173 - }
181 return 0
182 }
183
177 -func (i *cmdInvocation) Run(ctx context.Context) (output io.Reader, err error) {
184 +func (i *cmdInvocation) Run(ctx context.Context) error {
185
186 // check if user wants to debug. option OR env var.
187 debug, _, err := i.req.Option("debug").Bool()
188 if err != nil {
182 - return nil, err
189 + return err
190 }
191 if debug || os.Getenv("IPFS_LOGGING") == "debug" {
192 u.Debug = true
@@ -189,20 +196,12 @@ func (i *cmdInvocation) Run(ctx context.Context) (output io.Reader, err error) {
196 u.Debug = true
197 }
198
192 - res, err := callCommand(ctx, i.req, Root, i.cmd)
193 - if err != nil {
194 - return nil, err
195 - }
196 -
197 - if err := res.Error(); err != nil {
198 - return nil, err
199 - }
200 -
201 - return res.Reader()
199 + err = callCommand(ctx, i.req, Root, i.cmd)
200 + return err
201 }
202
203 func (i *cmdInvocation) constructNodeFunc(ctx context.Context) func() (*core.IpfsNode, error) {
205 - return func() (*core.IpfsNode, error) {
204 + return func() (n *core.IpfsNode, err error) {
205 if i.req == nil {
206 return nil, errors.New("constructing node without a request")
207 }
@@ -219,7 +218,7 @@ func (i *cmdInvocation) constructNodeFunc(ctx context.Context) func() (*core.Ipf
218
219 // ok everything is good. set it on the invocation (for ownership)
220 // and return it.
222 - n, err := core.NewNode(ctx, &core.BuildCfg{
221 + n, err = core.NewNode(ctx, &core.BuildCfg{
222 Online: cmdctx.Online,
223 Repo: r,
224 })
@@ -245,7 +244,7 @@ func (i *cmdInvocation) close() {
244 func (i *cmdInvocation) Parse(ctx context.Context, args []string) error {
245 var err error
246
248 - i.req, i.cmd, i.path, err = cmdsCli.Parse(args, os.Stdin, Root)
247 + i.req, i.cmd, i.path, err = cli.Parse(args, os.Stdin, Root)
248 if err != nil {
249 return err
250 }
@@ -267,7 +266,7 @@ func (i *cmdInvocation) Parse(ctx context.Context, args []string) error {
266 // if no encoding was specified by user, default to plaintext encoding
267 // (if command doesn't support plaintext, use JSON instead)
268 if !i.req.Option("encoding").Found() {
270 - if i.req.Command().Marshalers != nil && i.req.Command().Marshalers[cmds.Text] != nil {
269 + if i.req.Command().Encoders != nil && i.req.Command().Encoders[cmds.Text] != nil {
270 i.req.SetOption("encoding", cmds.Text)
271 } else {
272 i.req.SetOption("encoding", cmds.JSON)
@@ -297,70 +296,106 @@ func callPreCommandHooks(ctx context.Context, details cmdDetails, req cmds.Reque
296 return nil
297 }
298
300 -func callCommand(ctx context.Context, req cmds.Request, root *cmds.Command, cmd *cmds.Command) (cmds.Response, error) {
299 +func callCommand(ctx context.Context, req cmds.Request, root *cmds.Command, cmd *cmds.Command) error {
300 log.Info(config.EnvDir, " ", req.InvocContext().ConfigRoot)
302 - var res cmds.Response
301
302 err := req.SetRootContext(ctx)
303 if err != nil {
306 - return nil, err
304 + return err
305 }
306
307 details, err := commandDetails(req.Path(), root)
308 if err != nil {
311 - return nil, err
309 + return err
310 }
311
312 client, err := commandShouldRunOnDaemon(*details, req, root)
313 if err != nil {
316 - return nil, err
314 + return err
315 }
316
317 err = callPreCommandHooks(ctx, *details, req, root)
318 if err != nil {
321 - return nil, err
319 + return err
320 + }
321 +
322 + encTypeStr, found, err := req.Option("encoding").String()
323 + if !found || err != nil {
324 + log.Error("error getting encoding - using JSON. reason: ", err)
325 + encTypeStr = "json"
326 + }
327 + encType := cmds.EncodingType(encTypeStr)
328 +
329 + var (
330 + re cmds.ResponseEmitter
331 + exitCh <-chan int
332 + )
333 +
334 + // first if condition checks the command's encoder map, second checks global encoder map (cmd vs. cmds)
335 + if enc, ok := cmd.Encoders[encType]; ok {
336 + re, exitCh = cli.NewResponseEmitter(os.Stdout, os.Stderr, enc, req)
337 + } else if enc, ok := cmds.Encoders[encType]; ok {
338 + re, exitCh = cli.NewResponseEmitter(os.Stdout, os.Stderr, enc, req)
339 + } else {
340 + return fmt.Errorf("could not find matching encoder for enctype %#v", encType)
341 }
342
343 if cmd.PreRun != nil {
344 err = cmd.PreRun(req)
345 if err != nil {
327 - return nil, err
346 + return err
347 }
348 }
349
350 + if cmd.PostRun != nil && cmd.PostRun[cmds.CLI] != nil {
351 + re = cmd.PostRun[cmds.CLI](req, re)
352 + }
353 +
354 if client != nil && !cmd.External {
355 log.Debug("executing command via API")
333 - res, err = client.Send(req)
356 +
357 + res, err := client.Send(req)
358 if err != nil {
359 if isConnRefused(err) {
360 err = repo.ErrApiNotRunning
361 }
338 - return nil, wrapContextCanceled(err)
362 +
363 + return wrapContextCanceled(err)
364 }
365
366 + go func() {
367 + err = cmds.Copy(re, res)
368 + if err != nil {
369 + re.SetError(err, cmdkit.ErrNormal|cmdkit.ErrFatal)
370 + }
371 + }()
372 } else {
373 log.Debug("executing command locally")
374
375 pluginpath := filepath.Join(req.InvocContext().ConfigRoot, "plugins")
376 if _, err := loader.LoadPlugins(pluginpath); err != nil {
346 - return nil, err
377 + return err
378 }
379
380 err := req.SetRootContext(ctx)
381 if err != nil {
351 - return nil, err
382 + return err
383 }
384
385 // Okay!!!!! NOW we can call the command.
355 - res = root.Call(req)
356 -
386 + go func() {
387 + err := root.Call(req, re)
388 + if err != nil {
389 + re.SetError(err, cmdkit.ErrNormal)
390 + }
391 + }()
392 }
393
359 - if cmd.PostRun != nil {
360 - cmd.PostRun(req, res)
394 + if returnCode := <-exitCh; returnCode != 0 {
395 + err = exitErr(returnCode)
396 }
397
363 - return res, nil
398 + return err
399 }
400
401 // commandDetails returns a command's details for the command given by |path|
@@ -372,13 +407,12 @@ func commandDetails(path []string, root *cmds.Command) (*cmdDetails, error) {
407 // find the last command in path that has a cmdDetailsMap entry
408 cmd := root
409 for _, cmp := range path {
375 - var found bool
376 - cmd, found = cmd.Subcommands[cmp]
377 - if !found {
410 + cmd = cmd.Subcommand(cmp)
411 + if cmd == nil {
412 return nil, fmt.Errorf("subcommand %s should be in root", cmp)
413 }
414
381 - if cmdDetails, found := cmdDetailsMap[cmd]; found {
415 + if cmdDetails, found := cmdDetailsMap[strings.Join(path, "/")]; found {
416 details = cmdDetails
417 }
418 }
@@ -391,7 +425,7 @@ func commandDetails(path []string, root *cmds.Command) (*cmdDetails, error) {
425 // It returns a client if the command should be executed on a daemon and nil if
426 // it should be executed on a client. It returns an error if the command must
427 // NOT be executed on either.
394 -func commandShouldRunOnDaemon(details cmdDetails, req cmds.Request, root *cmds.Command) (cmdsHttp.Client, error) {
428 +func commandShouldRunOnDaemon(details cmdDetails, req cmds.Request, root *cmds.Command) (http.Client, error) {
429 path := req.Path()
430 // root command.
431 if len(path) < 1 {
@@ -449,17 +483,10 @@ func commandShouldRunOnDaemon(details cmdDetails, req cmds.Request, root *cmds.C
483 }
484
485 func isClientError(err error) bool {
452 -
453 - // Somewhat suprisingly, the pointer cast fails to recognize commands.Error
454 - // passed as values, so we check both.
455 -
456 - // cast to cmds.Error
457 - switch e := err.(type) {
458 - case *cmds.Error:
459 - return e.Code == cmds.ErrClient
460 - case cmds.Error:
461 - return e.Code == cmds.ErrClient
486 + if e, ok := err.(*cmdkit.Error); ok {
487 + return e.Code == cmdkit.ErrClient
488 }
489 +
490 return false
491 }
492
@@ -606,7 +633,7 @@ var checkIPFSWinFmt = "Otherwise check:\n\ttasklist | findstr ipfs"
633 // getApiClient checks the repo, and the given options, checking for
634 // a running API service. if there is one, it returns a client.
635 // otherwise, it returns errApiNotRunning, or another error.
609 -func getApiClient(repoPath, apiAddrStr string) (cmdsHttp.Client, error) {
636 +func getApiClient(repoPath, apiAddrStr string) (http.Client, error) {
637 var apiErrorFmt string
638 switch {
639 case osh.IsUnix():
@@ -643,13 +670,13 @@ func getApiClient(repoPath, apiAddrStr string) (cmdsHttp.Client, error) {
670 return apiClientForAddr(addr)
671 }
672
646 -func apiClientForAddr(addr ma.Multiaddr) (cmdsHttp.Client, error) {
673 +func apiClientForAddr(addr ma.Multiaddr) (http.Client, error) {
674 _, host, err := manet.DialArgs(addr)
675 if err != nil {
676 return nil, err
677 }
678
652 - return cmdsHttp.NewClient(host), nil
679 + return http.NewClient(host), nil
680 }
681
682 func isConnRefused(err error) bool {
cmd/ipfs/main_test.go
+4 -7
@@ -3,15 +3,12 @@ package main
3 import (
4 "testing"
5
6 - "github.com/ipfs/go-ipfs/commands"
6 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
7 )
8
9 func TestIsCientErr(t *testing.T) {
10 - t.Log("Catch both pointers and values")
11 - if !isClientError(commands.Error{Code: commands.ErrClient}) {
12 - t.Errorf("misidentified value")
13 - }
14 - if !isClientError(&commands.Error{Code: commands.ErrClient}) {
15 - t.Errorf("misidentified pointer")
10 + t.Log("Only catch pointers")
11 + if !isClientError(&cmdkit.Error{Code: cmdkit.ErrClient}) {
12 + t.Errorf("misidentified error")
13 }
14 }
cmd/ipfswatch/main.go
+1 -2
@@ -9,7 +9,6 @@ import (
9 "path/filepath"
10 "syscall"
11
12 - commands "github.com/ipfs/go-ipfs/commands"
12 core "github.com/ipfs/go-ipfs/core"
13 corehttp "github.com/ipfs/go-ipfs/core/corehttp"
14 coreunix "github.com/ipfs/go-ipfs/core/coreunix"
@@ -18,8 +17,8 @@ import (
17
18 homedir "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir"
19
20 + commands "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
21 process "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess"
22 -
22 fsnotify "gx/ipfs/QmczzCMvJ3HV57WBKDy8b4ucp7quT325JjDbixYRS5Pwvv/fsnotify.v1"
23 )
24
cmd/seccat/seccat.go
+1 -1
@@ -9,6 +9,7 @@
9 package main
10
11 import (
12 + "context"
13 "errors"
14 "flag"
15 "fmt"
@@ -18,7 +19,6 @@ import (
19 "os/signal"
20 "syscall"
21
21 - context "context"
22 pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore"
23 logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
24 peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer"
commands/argument.go deleted
-56
@@ -1,56 +0,0 @@
1 -package commands
2 -
3 -type ArgumentType int
4 -
5 -const (
6 - ArgString ArgumentType = iota
7 - ArgFile
8 -)
9 -
10 -type Argument struct {
11 - Name string
12 - Type ArgumentType
13 - Required bool // error if no value is specified
14 - Variadic bool // unlimited values can be specfied
15 - SupportsStdin bool // can accept stdin as a value
16 - Recursive bool // supports recursive file adding (with '-r' flag)
17 - Description string
18 -}
19 -
20 -func StringArg(name string, required, variadic bool, description string) Argument {
21 - return Argument{
22 - Name: name,
23 - Type: ArgString,
24 - Required: required,
25 - Variadic: variadic,
26 - Description: description,
27 - }
28 -}
29 -
30 -func FileArg(name string, required, variadic bool, description string) Argument {
31 - return Argument{
32 - Name: name,
33 - Type: ArgFile,
34 - Required: required,
35 - Variadic: variadic,
36 - Description: description,
37 - }
38 -}
39 -
40 -// TODO: modifiers might need a different API?
41 -// e.g. passing enum values into arg constructors variadically
42 -// (`FileArg("file", ArgRequired, ArgStdin, ArgRecursive)`)
43 -
44 -func (a Argument) EnableStdin() Argument {
45 - a.SupportsStdin = true
46 - return a
47 -}
48 -
49 -func (a Argument) EnableRecursive() Argument {
50 - if a.Type != ArgFile {
51 - panic("Only FileArgs can enable recursive")
52 - }
53 -
54 - a.Recursive = true
55 - return a
56 -}
commands/channelmarshaler.go
+3 -1
@@ -1,6 +1,8 @@
1 package commands
2
3 -import "io"
3 +import (
4 + "io"
5 +)
6
7 type ChannelMarshaler struct {
8 Channel <-chan interface{}
commands/cli/cmd_suggestion.go
+4 -4
@@ -40,7 +40,7 @@ func suggestUnknownCmd(args []string, root *cmds.Command) []string {
40 var sFinal []string
41 const MIN_LEVENSHTEIN = 3
42
43 - var options levenshtein.Options = levenshtein.Options{
43 + var options = levenshtein.Options{
44 InsCost: 1,
45 DelCost: 3,
46 SubCost: 2,
@@ -50,7 +50,7 @@ func suggestUnknownCmd(args []string, root *cmds.Command) []string {
50 }
51
52 // Start with a simple strings.Contains check
53 - for name, _ := range root.Subcommands {
53 + for name := range root.Subcommands {
54 if strings.Contains(arg, name) {
55 suggestions = append(suggestions, name)
56 }
@@ -61,7 +61,7 @@ func suggestUnknownCmd(args []string, root *cmds.Command) []string {
61 return suggestions
62 }
63
64 - for name, _ := range root.Subcommands {
64 + for name := range root.Subcommands {
65 lev := levenshtein.DistanceForStrings([]rune(arg), []rune(name), options)
66 if lev <= MIN_LEVENSHTEIN {
67 sortableSuggestions = append(sortableSuggestions, &suggestion{name, lev})
@@ -83,7 +83,7 @@ func printSuggestions(inputs []string, root *cmds.Command) (err error) {
83 } else if len(suggestions) > 0 {
84 err = fmt.Errorf("Unknown Command \"%s\"\n\nDid you mean this?\n\n\t%s", inputs[0], suggestions[0])
85 } else {
86 - err = fmt.Errorf("Unknown Command \"%s\"\n", inputs[0])
86 + err = fmt.Errorf("Unknown Command %q", inputs[0])
87 }
88 return
89 }
commands/cli/helptext.go
+7 -6
@@ -8,6 +8,7 @@ import (
8 "text/template"
9
10 cmds "github.com/ipfs/go-ipfs/commands"
11 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
12 )
13
14 const (
@@ -231,13 +232,13 @@ func generateSynopsis(cmd *cmds.Command, path string) string {
232 if len(n) > 1 {
233 pre = "--"
234 }
234 - if opt.Type() == cmds.Bool && opt.DefaultVal() == true {
235 + if opt.Type() == cmdkit.Bool && opt.DefaultVal() == true {
236 pre = "--"
237 sopt = fmt.Sprintf("%s%s=false", pre, n)
238 break
239 } else {
240 if i == 0 {
240 - if opt.Type() == cmds.Bool {
241 + if opt.Type() == cmdkit.Bool {
242 sopt = fmt.Sprintf("%s%s", pre, n)
243 } else {
244 sopt = fmt.Sprintf("%s%s=<%s>", pre, n, valopt)
@@ -283,14 +284,14 @@ func argumentText(cmd *cmds.Command) []string {
284 func optionFlag(flag string) string {
285 if len(flag) == 1 {
286 return fmt.Sprintf(shortFlag, flag)
286 - } else {
287 - return fmt.Sprintf(longFlag, flag)
287 }
288 +
289 + return fmt.Sprintf(longFlag, flag)
290 }
291
292 func optionText(cmd ...*cmds.Command) []string {
293 // get a slice of the options we want to list out
293 - options := make([]cmds.Option, 0)
294 + options := make([]cmdkit.Option, 0)
295 for _, c := range cmd {
296 options = append(options, c.Options...)
297 }
@@ -387,7 +388,7 @@ func usageText(cmd *cmds.Command) string {
388 return s
389 }
390
390 -func argUsageText(arg cmds.Argument) string {
391 +func argUsageText(arg cmdkit.Argument) string {
392 s := arg.Name
393
394 if arg.Required {
commands/cli/helptext_test.go
+8 -6
@@ -5,18 +5,20 @@ import (
5 "testing"
6
7 cmds "github.com/ipfs/go-ipfs/commands"
8 +
9 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
10 )
11
12 func TestSynopsisGenerator(t *testing.T) {
13 command := &cmds.Command{
12 - Arguments: []cmds.Argument{
13 - cmds.StringArg("required", true, false, ""),
14 - cmds.StringArg("variadic", false, true, ""),
14 + Arguments: []cmdkit.Argument{
15 + cmdkit.StringArg("required", true, false, ""),
16 + cmdkit.StringArg("variadic", false, true, ""),
17 },
16 - Options: []cmds.Option{
17 - cmds.StringOption("opt", "o", "Option"),
18 + Options: []cmdkit.Option{
19 + cmdkit.StringOption("opt", "o", "Option"),
20 },
19 - Helptext: cmds.HelpText{
21 + Helptext: cmdkit.HelpText{
22 SynopsisOptionsValues: map[string]string{
23 "opt": "OPTION",
24 },
commands/cli/parse.go
+15 -15
@@ -10,8 +10,8 @@ import (
10 "strings"
11
12 cmds "github.com/ipfs/go-ipfs/commands"
13 - files "github.com/ipfs/go-ipfs/commands/files"
14 -
13 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
14 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files"
15 u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
16 logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
17 osh "gx/ipfs/QmXuBJ7DR6k3rmUEKtvVMhwjmXDuJgXXPUt4LQXKBMsU93/go-os-helper"
@@ -63,14 +63,14 @@ func Parse(input []string, stdin *os.File, root *cmds.Command) (cmds.Request, *c
63 return req, cmd, path, err
64 }
65
66 -func ParseArgs(req cmds.Request, inputs []string, stdin *os.File, argDefs []cmds.Argument, root *cmds.Command) ([]string, []files.File, error) {
66 +func ParseArgs(req cmds.Request, inputs []string, stdin *os.File, argDefs []cmdkit.Argument, root *cmds.Command) ([]string, []files.File, error) {
67 var err error
68
69 // if -r is provided, and it is associated with the package builtin
70 // recursive path option, allow recursive file paths
71 - recursiveOpt := req.Option(cmds.RecShort)
71 + recursiveOpt := req.Option(cmdkit.RecShort)
72 recursive := false
73 - if recursiveOpt != nil && recursiveOpt.Definition() == cmds.OptionRecursivePath {
73 + if recursiveOpt != nil && recursiveOpt.Definition() == cmdkit.OptionRecursivePath {
74 recursive, _, err = recursiveOpt.Bool()
75 if err != nil {
76 return nil, nil, u.ErrCast()
@@ -99,7 +99,7 @@ func parseOpts(args []string, root *cmds.Command) (
99 ) {
100 path = make([]string, 0, len(args))
101 stringVals = make([]string, 0, len(args))
102 - optDefs := map[string]cmds.Option{}
102 + optDefs := map[string]cmdkit.Option{}
103 opts = map[string]interface{}{}
104 cmd = root
105
@@ -121,7 +121,7 @@ func parseOpts(args []string, root *cmds.Command) (
121 // eg. ipfs -r <file> means disregard <file> since there is no '='
122 // mustUse == false in the above situation
123 //arg == nil implies the flag was specified without an argument
124 - if optDef.Type() == cmds.Bool {
124 + if optDef.Type() == cmdkit.Bool {
125 if arg == nil || !mustUse {
126 opts[name] = true
127 return false, nil
@@ -256,7 +256,7 @@ func parseOpts(args []string, root *cmds.Command) (
256
257 const msgStdinInfo = "ipfs: Reading from %s; send Ctrl-d to stop."
258
259 -func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursive, hidden bool, root *cmds.Command) ([]string, []files.File, error) {
259 +func parseArgs(inputs []string, stdin *os.File, argDefs []cmdkit.Argument, recursive, hidden bool, root *cmds.Command) ([]string, []files.File, error) {
260 // ignore stdin on Windows
261 if osh.IsWindows() {
262 stdin = nil
@@ -275,7 +275,7 @@ func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursi
275 // below to parse stdin.
276 numInputs := len(inputs)
277 if len(argDefs) > 0 && argDefs[len(argDefs)-1].SupportsStdin && stdin != nil {
278 - numInputs += 1
278 + numInputs++
279 }
280
281 // if we have more arg values provided than argument definitions,
@@ -305,7 +305,7 @@ func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursi
305
306 fillingVariadic := argDefIndex+1 > len(argDefs)
307 switch argDef.Type {
308 - case cmds.ArgString:
308 + case cmdkit.ArgString:
309 if len(inputs) > 0 {
310 stringArgs, inputs = append(stringArgs, inputs[0]), inputs[1:]
311 } else if stdin != nil && argDef.SupportsStdin && !fillingVariadic {
@@ -314,7 +314,7 @@ func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursi
314 stdin = nil
315 }
316 }
317 - case cmds.ArgFile:
317 + case cmdkit.ArgFile:
318 if len(inputs) > 0 {
319 // treat stringArg values as file paths
320 fpath := inputs[0]
@@ -367,7 +367,7 @@ func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursi
367
368 func filesMapToSortedArr(fs map[string]files.File) []files.File {
369 var names []string
370 - for name, _ := range fs {
370 + for name := range fs {
371 names = append(names, name)
372 }
373
@@ -381,7 +381,7 @@ func filesMapToSortedArr(fs map[string]files.File) []files.File {
381 return out
382 }
383
384 -func getArgDef(i int, argDefs []cmds.Argument) *cmds.Argument {
384 +func getArgDef(i int, argDefs []cmdkit.Argument) *cmdkit.Argument {
385 if i < len(argDefs) {
386 // get the argument definition (usually just argDefs[i])
387 return &argDefs[i]
@@ -399,7 +399,7 @@ const notRecursiveFmtStr = "'%s' is a directory, use the '-%s' flag to specify d
399 const dirNotSupportedFmtStr = "Invalid path '%s', argument '%s' does not support directories"
400 const winDriveLetterFmtStr = "%q is a drive letter, not a drive path"
401
402 -func appendFile(fpath string, argDef *cmds.Argument, recursive, hidden bool) (files.File, error) {
402 +func appendFile(fpath string, argDef *cmdkit.Argument, recursive, hidden bool) (files.File, error) {
403 // resolve Windows relative dot paths like `X:.\somepath`
404 if osh.IsWindows() {
405 if len(fpath) >= 3 && fpath[1:3] == ":." {
@@ -435,7 +435,7 @@ func appendFile(fpath string, argDef *cmds.Argument, recursive, hidden bool) (fi
435 return nil, fmt.Errorf(dirNotSupportedFmtStr, fpath, argDef.Name)
436 }
437 if !recursive {
438 - return nil, fmt.Errorf(notRecursiveFmtStr, fpath, cmds.RecShort)
438 + return nil, fmt.Errorf(notRecursiveFmtStr, fpath, cmdkit.RecShort)
439 }
440 }
441
commands/cli/parse_test.go
+30 -28
@@ -9,6 +9,8 @@ import (
9 "testing"
10
11 "github.com/ipfs/go-ipfs/commands"
12 +
13 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
14 )
15
16 type kvs map[string]interface{}
@@ -68,9 +70,9 @@ func TestSameWords(t *testing.T) {
70 func TestOptionParsing(t *testing.T) {
71 subCmd := &commands.Command{}
72 cmd := &commands.Command{
71 - Options: []commands.Option{
72 - commands.StringOption("string", "s", "a string"),
73 - commands.BoolOption("bool", "b", "a bool"),
73 + Options: []cmdkit.Option{
74 + cmdkit.StringOption("string", "s", "a string"),
75 + cmdkit.BoolOption("bool", "b", "a bool"),
76 },
77 Subcommands: map[string]*commands.Command{
78 "test": subCmd,
@@ -145,58 +147,58 @@ func TestArgumentParsing(t *testing.T) {
147 Subcommands: map[string]*commands.Command{
148 "noarg": {},
149 "onearg": {
148 - Arguments: []commands.Argument{
149 - commands.StringArg("a", true, false, "some arg"),
150 + Arguments: []cmdkit.Argument{
151 + cmdkit.StringArg("a", true, false, "some arg"),
152 },
153 },
154 "twoargs": {
153 - Arguments: []commands.Argument{
154 - commands.StringArg("a", true, false, "some arg"),
155 - commands.StringArg("b", true, false, "another arg"),
155 + Arguments: []cmdkit.Argument{
156 + cmdkit.StringArg("a", true, false, "some arg"),
157 + cmdkit.StringArg("b", true, false, "another arg"),
158 },
159 },
160 "variadic": {
159 - Arguments: []commands.Argument{
160 - commands.StringArg("a", true, true, "some arg"),
161 + Arguments: []cmdkit.Argument{
162 + cmdkit.StringArg("a", true, true, "some arg"),
163 },
164 },
165 "optional": {
164 - Arguments: []commands.Argument{
165 - commands.StringArg("b", false, true, "another arg"),
166 + Arguments: []cmdkit.Argument{
167 + cmdkit.StringArg("b", false, true, "another arg"),
168 },
169 },
170 "optionalsecond": {
169 - Arguments: []commands.Argument{
170 - commands.StringArg("a", true, false, "some arg"),
171 - commands.StringArg("b", false, false, "another arg"),
171 + Arguments: []cmdkit.Argument{
172 + cmdkit.StringArg("a", true, false, "some arg"),
173 + cmdkit.StringArg("b", false, false, "another arg"),
174 },
175 },
176 "reversedoptional": {
175 - Arguments: []commands.Argument{
176 - commands.StringArg("a", false, false, "some arg"),
177 - commands.StringArg("b", true, false, "another arg"),
177 + Arguments: []cmdkit.Argument{
178 + cmdkit.StringArg("a", false, false, "some arg"),
179 + cmdkit.StringArg("b", true, false, "another arg"),
180 },
181 },
182 "stdinenabled": {
181 - Arguments: []commands.Argument{
182 - commands.StringArg("a", true, true, "some arg").EnableStdin(),
183 + Arguments: []cmdkit.Argument{
184 + cmdkit.StringArg("a", true, true, "some arg").EnableStdin(),
185 },
186 },
187 "stdinenabled2args": &commands.Command{
186 - Arguments: []commands.Argument{
187 - commands.StringArg("a", true, false, "some arg"),
188 - commands.StringArg("b", true, true, "another arg").EnableStdin(),
188 + Arguments: []cmdkit.Argument{
189 + cmdkit.StringArg("a", true, false, "some arg"),
190 + cmdkit.StringArg("b", true, true, "another arg").EnableStdin(),
191 },
192 },
193 "stdinenablednotvariadic": &commands.Command{
192 - Arguments: []commands.Argument{
193 - commands.StringArg("a", true, false, "some arg").EnableStdin(),
194 + Arguments: []cmdkit.Argument{
195 + cmdkit.StringArg("a", true, false, "some arg").EnableStdin(),
196 },
197 },
198 "stdinenablednotvariadic2args": &commands.Command{
197 - Arguments: []commands.Argument{
198 - commands.StringArg("a", true, false, "some arg"),
199 - commands.StringArg("b", true, false, "another arg").EnableStdin(),
199 + Arguments: []cmdkit.Argument{
200 + cmdkit.StringArg("a", true, false, "some arg"),
201 + cmdkit.StringArg("b", true, false, "another arg").EnableStdin(),
202 },
203 },
204 },
commands/command.go
+27 -31
@@ -15,6 +15,7 @@ import (
15 "reflect"
16
17 "github.com/ipfs/go-ipfs/path"
18 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
19 logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
20 )
21
@@ -32,28 +33,11 @@ type Marshaler func(Response) (io.Reader, error)
33 // (or an error on failure)
34 type MarshalerMap map[EncodingType]Marshaler
35
35 -// HelpText is a set of strings used to generate command help text. The help
36 -// text follows formats similar to man pages, but not exactly the same.
37 -type HelpText struct {
38 - // required
39 - Tagline string // used in <cmd usage>
40 - ShortDescription string // used in DESCRIPTION
41 - SynopsisOptionsValues map[string]string // mappings for synopsis generator
42 -
43 - // optional - whole section overrides
44 - Usage string // overrides USAGE section
45 - LongDescription string // overrides DESCRIPTION section
46 - Options string // overrides OPTIONS section
47 - Arguments string // overrides ARGUMENTS section
48 - Subcommands string // overrides SUBCOMMANDS section
49 - Synopsis string // overrides SYNOPSIS field
50 -}
51 -
36 // Command is a runnable command, with input arguments and options (flags).
37 // It can also have Subcommands, to group units of work into sets.
38 type Command struct {
55 - Options []Option
56 - Arguments []Argument
39 + Options []cmdkit.Option
40 + Arguments []cmdkit.Argument
41 PreRun func(req Request) error
42
43 // Run is the function that processes the request to generate a response.
@@ -63,7 +47,7 @@ type Command struct {
47 Run Function
48 PostRun Function
49 Marshalers map[EncodingType]Marshaler
66 - Helptext HelpText
50 + Helptext cmdkit.HelpText
51
52 // External denotes that a command is actually an external binary.
53 // fewer checks and validations will be performed on such commands.
@@ -91,25 +75,25 @@ func (c *Command) Call(req Request) Response {
75
76 cmds, err := c.Resolve(req.Path())
77 if err != nil {
94 - res.SetError(err, ErrClient)
78 + res.SetError(err, cmdkit.ErrClient)
79 return res
80 }
81 cmd := cmds[len(cmds)-1]
82
83 if cmd.Run == nil {
100 - res.SetError(ErrNotCallable, ErrClient)
84 + res.SetError(ErrNotCallable, cmdkit.ErrClient)
85 return res
86 }
87
88 err = cmd.CheckArguments(req)
89 if err != nil {
106 - res.SetError(err, ErrClient)
90 + res.SetError(err, cmdkit.ErrClient)
91 return res
92 }
93
94 err = req.ConvertOptions()
95 if err != nil {
112 - res.SetError(err, ErrClient)
96 + res.SetError(err, cmdkit.ErrClient)
97 return res
98 }
99
@@ -145,7 +129,7 @@ func (c *Command) Call(req Request) Response {
129 expectedType := reflect.TypeOf(cmd.Type)
130
131 if actualType != expectedType {
148 - res.SetError(ErrIncorrectType, ErrNormal)
132 + res.SetError(ErrIncorrectType, cmdkit.ErrNormal)
133 return res
134 }
135 }
@@ -183,8 +167,8 @@ func (c *Command) Get(path []string) (*Command, error) {
167 }
168
169 // GetOptions returns the options in the given path of commands
186 -func (c *Command) GetOptions(path []string) (map[string]Option, error) {
187 - options := make([]Option, 0, len(c.Options))
170 +func (c *Command) GetOptions(path []string) (map[string]cmdkit.Option, error) {
171 + options := make([]cmdkit.Option, 0, len(c.Options))
172
173 cmds, err := c.Resolve(path)
174 if err != nil {
@@ -196,7 +180,7 @@ func (c *Command) GetOptions(path []string) (map[string]Option, error) {
180 options = append(options, cmd.Options...)
181 }
182
199 - optionsMap := make(map[string]Option)
183 + optionsMap := make(map[string]cmdkit.Option)
184 for _, opt := range options {
185 for _, name := range opt.Names() {
186 if _, found := optionsMap[name]; found {
@@ -227,7 +211,7 @@ func (c *Command) CheckArguments(req Request) error {
211 // skip optional argument definitions if there aren't
212 // sufficient remaining values
213 if len(args)-valueIndex <= numRequired && !argDef.Required ||
230 - argDef.Type == ArgFile {
214 + argDef.Type == cmdkit.ArgFile {
215 continue
216 }
217
@@ -290,7 +274,7 @@ func (c *Command) ProcessHelp() {
274
275 // checkArgValue returns an error if a given arg value is not valid for the
276 // given Argument
293 -func checkArgValue(v string, found bool, def Argument) error {
277 +func checkArgValue(v string, found bool, def cmdkit.Argument) error {
278 if def.Variadic && def.SupportsStdin {
279 return nil
280 }
@@ -303,5 +287,17 @@ func checkArgValue(v string, found bool, def Argument) error {
287 }
288
289 func ClientError(msg string) error {
306 - return &Error{Code: ErrClient, Message: msg}
290 + return &cmdkit.Error{Code: cmdkit.ErrClient, Message: msg}
291 +}
292 +
293 +// global options, added to every command
294 +var globalOptions = []cmdkit.Option{
295 + cmdkit.OptionEncodingType,
296 + cmdkit.OptionStreamChannels,
297 + cmdkit.OptionTimeout,
298 +}
299 +
300 +// the above array of Options, wrapped in a Command
301 +var globalCommand = &Command{
302 + Options: globalOptions,
303 }
commands/command_test.go
+17 -13
@@ -1,15 +1,19 @@
1 package commands
2
3 -import "testing"
3 +import (
4 + "testing"
5 +
6 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
7 +)
8
9 func noop(req Request, res Response) {
10 }
11
12 func TestOptionValidation(t *testing.T) {
13 cmd := Command{
10 - Options: []Option{
11 - IntOption("b", "beep", "enables beeper"),
12 - StringOption("B", "boop", "password for booper"),
14 + Options: []cmdkit.Option{
15 + cmdkit.IntOption("b", "beep", "enables beeper"),
16 + cmdkit.StringOption("B", "boop", "password for booper"),
17 },
18 Run: noop,
19 }
@@ -54,7 +58,7 @@ func TestOptionValidation(t *testing.T) {
58 }
59
60 req, _ = NewRequest(nil, nil, nil, nil, nil, opts)
57 - req.SetOption(EncShort, "json")
61 + req.SetOption(cmdkit.EncShort, "json")
62 res = cmd.Call(req)
63 if res.Error() != nil {
64 t.Error("Should have passed")
@@ -91,15 +95,15 @@ func TestOptionValidation(t *testing.T) {
95
96 func TestRegistration(t *testing.T) {
97 cmdA := &Command{
94 - Options: []Option{
95 - IntOption("beep", "number of beeps"),
98 + Options: []cmdkit.Option{
99 + cmdkit.IntOption("beep", "number of beeps"),
100 },
101 Run: noop,
102 }
103
104 cmdB := &Command{
101 - Options: []Option{
102 - IntOption("beep", "number of beeps"),
105 + Options: []cmdkit.Option{
106 + cmdkit.IntOption("beep", "number of beeps"),
107 },
108 Run: noop,
109 Subcommands: map[string]*Command{
@@ -108,8 +112,8 @@ func TestRegistration(t *testing.T) {
112 }
113
114 cmdC := &Command{
111 - Options: []Option{
112 - StringOption("encoding", "data encoding type"),
115 + Options: []cmdkit.Option{
116 + cmdkit.StringOption("encoding", "data encoding type"),
117 },
118 Run: noop,
119 }
@@ -173,12 +177,12 @@ func TestWalking(t *testing.T) {
177
178 func TestHelpProcessing(t *testing.T) {
179 cmdB := &Command{
176 - Helptext: HelpText{
180 + Helptext: cmdkit.HelpText{
181 ShortDescription: "This is other short",
182 },
183 }
184 cmdA := &Command{
181 - Helptext: HelpText{
185 + Helptext: cmdkit.HelpText{
186 ShortDescription: "This is short",
187 },
188 Subcommands: map[string]*Command{
commands/files/file.go deleted
-62
@@ -1,62 +0,0 @@
1 -package files
2 -
3 -import (
4 - "errors"
5 - "io"
6 - "os"
7 -)
8 -
9 -var (
10 - ErrNotDirectory = errors.New("Couldn't call NextFile(), this isn't a directory")
11 - ErrNotReader = errors.New("This file is a directory, can't use Reader functions")
12 -)
13 -
14 -// File is an interface that provides functionality for handling
15 -// files/directories as values that can be supplied to commands. For
16 -// directories, child files are accessed serially by calling `NextFile()`.
17 -type File interface {
18 - // Files implement ReadCloser, but can only be read from or closed if
19 - // they are not directories
20 - io.ReadCloser
21 -
22 - // FileName returns a filename associated with this file
23 - FileName() string
24 -
25 - // FullPath returns the full path used when adding this file
26 - FullPath() string
27 -
28 - // IsDirectory returns true if the File is a directory (and therefore
29 - // supports calling `NextFile`) and false if the File is a normal file
30 - // (and therefor supports calling `Read` and `Close`)
31 - IsDirectory() bool
32 -
33 - // NextFile returns the next child file available (if the File is a
34 - // directory). It will return (nil, io.EOF) if no more files are
35 - // available. If the file is a regular file (not a directory), NextFile
36 - // will return a non-nil error.
37 - NextFile() (File, error)
38 -}
39 -
40 -type StatFile interface {
41 - File
42 -
43 - Stat() os.FileInfo
44 -}
45 -
46 -type PeekFile interface {
47 - SizeFile
48 -
49 - Peek(n int) File
50 - Length() int
51 -}
52 -
53 -type SizeFile interface {
54 - File
55 -
56 - Size() (int64, error)
57 -}
58 -
59 -type FileInfo interface {
60 - AbsPath() string
61 - Stat() os.FileInfo
62 -}
commands/files/file_test.go deleted
-203
@@ -1,203 +0,0 @@
1 -package files
2 -
3 -import (
4 - "io"
5 - "io/ioutil"
6 - "mime/multipart"
7 - "strings"
8 - "testing"
9 -)
10 -
11 -func TestSliceFiles(t *testing.T) {
12 - name := "testname"
13 - files := []File{
14 - NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader("Some text!\n")), nil),
15 - NewReaderFile("beep.txt", "beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil),
16 - NewReaderFile("boop.txt", "boop.txt", ioutil.NopCloser(strings.NewReader("boop")), nil),
17 - }
18 - buf := make([]byte, 20)
19 -
20 - sf := NewSliceFile(name, name, files)
21 -
22 - if !sf.IsDirectory() {
23 - t.Fatal("SliceFile should always be a directory")
24 - }
25 -
26 - if n, err := sf.Read(buf); n > 0 || err != io.EOF {
27 - t.Fatal("Shouldn't be able to read data from a SliceFile")
28 - }
29 -
30 - if err := sf.Close(); err != ErrNotReader {
31 - t.Fatal("Shouldn't be able to call `Close` on a SliceFile")
32 - }
33 -
34 - file, err := sf.NextFile()
35 - if file == nil || err != nil {
36 - t.Fatal("Expected a file and nil error")
37 - }
38 - read, err := file.Read(buf)
39 - if read != 11 || err != nil {
40 - t.Fatal("NextFile got a file in the wrong order")
41 - }
42 -
43 - file, err = sf.NextFile()
44 - if file == nil || err != nil {
45 - t.Fatal("Expected a file and nil error")
46 - }
47 - file, err = sf.NextFile()
48 - if file == nil || err != nil {
49 - t.Fatal("Expected a file and nil error")
50 - }
51 -
52 - file, err = sf.NextFile()
53 - if file != nil || err != io.EOF {
54 - t.Fatal("Expected a nil file and io.EOF")
55 - }
56 -}
57 -
58 -func TestReaderFiles(t *testing.T) {
59 - message := "beep boop"
60 - rf := NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader(message)), nil)
61 - buf := make([]byte, len(message))
62 -
63 - if rf.IsDirectory() {
64 - t.Fatal("ReaderFile should never be a directory")
65 - }
66 - file, err := rf.NextFile()
67 - if file != nil || err != ErrNotDirectory {
68 - t.Fatal("Expected a nil file and ErrNotDirectory")
69 - }
70 -
71 - if n, err := rf.Read(buf); n == 0 || err != nil {
72 - t.Fatal("Expected to be able to read")
73 - }
74 - if err := rf.Close(); err != nil {
75 - t.Fatal("Should be able to close")
76 - }
77 - if n, err := rf.Read(buf); n != 0 || err != io.EOF {
78 - t.Fatal("Expected EOF when reading after close")
79 - }
80 -}
81 -
82 -func TestMultipartFiles(t *testing.T) {
83 - data := `
84 ---Boundary!
85 -Content-Type: text/plain
86 -Content-Disposition: file; filename="name"
87 -Some-Header: beep
88 -
89 -beep
90 ---Boundary!
91 -Content-Type: application/x-directory
92 -Content-Disposition: file; filename="dir"
93 -
94 ---Boundary!
95 -Content-Type: text/plain
96 -Content-Disposition: file; filename="dir/nested"
97 -
98 -some content
99 ---Boundary!
100 -Content-Type: application/symlink
101 -Content-Disposition: file; filename="dir/simlynk"
102 -
103 -anotherfile
104 ---Boundary!--
105 -
106 -`
107 -
108 - reader := strings.NewReader(data)
109 - mpReader := multipart.NewReader(reader, "Boundary!")
110 - buf := make([]byte, 20)
111 -
112 - // test properties of a file created from the first part
113 - part, err := mpReader.NextPart()
114 - if part == nil || err != nil {
115 - t.Fatal("Expected non-nil part, nil error")
116 - }
117 - mpf, err := NewFileFromPart(part)
118 - if mpf == nil || err != nil {
119 - t.Fatal("Expected non-nil MultipartFile, nil error")
120 - }
121 - if mpf.IsDirectory() {
122 - t.Fatal("Expected file to not be a directory")
123 - }
124 - if mpf.FileName() != "name" {
125 - t.Fatal("Expected filename to be \"name\"")
126 - }
127 - if file, err := mpf.NextFile(); file != nil || err != ErrNotDirectory {
128 - t.Fatal("Expected a nil file and ErrNotDirectory")
129 - }
130 - if n, err := mpf.Read(buf); n != 4 || err != io.EOF && err != nil {
131 - t.Fatal("Expected to be able to read 4 bytes: ", n, err)
132 - }
133 - if err := mpf.Close(); err != nil {
134 - t.Fatal("Expected to be able to close file")
135 - }
136 -
137 - // test properties of file created from second part (directory)
138 - part, err = mpReader.NextPart()
139 - if part == nil || err != nil {
140 - t.Fatal("Expected non-nil part, nil error")
141 - }
142 - mpf, err = NewFileFromPart(part)
143 - if mpf == nil || err != nil {
144 - t.Fatal("Expected non-nil MultipartFile, nil error")
145 - }
146 - if !mpf.IsDirectory() {
147 - t.Fatal("Expected file to be a directory")
148 - }
149 - if mpf.FileName() != "dir" {
150 - t.Fatal("Expected filename to be \"dir\"")
151 - }
152 - if n, err := mpf.Read(buf); n > 0 || err != ErrNotReader {
153 - t.Fatal("Shouldn't be able to call `Read` on a directory")
154 - }
155 - if err := mpf.Close(); err != ErrNotReader {
156 - t.Fatal("Shouldn't be able to call `Close` on a directory")
157 - }
158 -
159 - // test properties of file created from third part (nested file)
160 - part, err = mpReader.NextPart()
161 - if part == nil || err != nil {
162 - t.Fatal("Expected non-nil part, nil error")
163 - }
164 - mpf, err = NewFileFromPart(part)
165 - if mpf == nil || err != nil {
166 - t.Fatal("Expected non-nil MultipartFile, nil error")
167 - }
168 - if mpf.IsDirectory() {
169 - t.Fatal("Expected file, got directory")
170 - }
171 - if mpf.FileName() != "dir/nested" {
172 - t.Fatalf("Expected filename to be \"nested\", got %s", mpf.FileName())
173 - }
174 - if n, err := mpf.Read(buf); n != 12 || err != io.EOF && err != nil {
175 - t.Fatalf("expected to be able to read 12 bytes from file: %s (got %d)", err, n)
176 - }
177 - if err := mpf.Close(); err != nil {
178 - t.Fatalf("should be able to close file: %s", err)
179 - }
180 -
181 - // test properties of symlink created from fourth part (symlink)
182 - part, err = mpReader.NextPart()
183 - if part == nil || err != nil {
184 - t.Fatal("Expected non-nil part, nil error")
185 - }
186 - mpf, err = NewFileFromPart(part)
187 - if mpf == nil || err != nil {
188 - t.Fatal("Expected non-nil MultipartFile, nil error")
189 - }
190 - if mpf.IsDirectory() {
191 - t.Fatal("Expected file to be a symlink")
192 - }
193 - if mpf.FileName() != "dir/simlynk" {
194 - t.Fatal("Expected filename to be \"dir/simlynk\"")
195 - }
196 - slink, ok := mpf.(*Symlink)
197 - if !ok {
198 - t.Fatalf("expected file to be a symlink")
199 - }
200 - if slink.Target != "anotherfile" {
201 - t.Fatal("expected link to point to anotherfile")
202 - }
203 -}
commands/files/is_hidden.go deleted
-19
@@ -1,19 +0,0 @@
1 -// +build !windows
2 -
3 -package files
4 -
5 -import (
6 - "path/filepath"
7 - "strings"
8 -)
9 -
10 -func IsHidden(f File) bool {
11 -
12 - fName := filepath.Base(f.FileName())
13 -
14 - if strings.HasPrefix(fName, ".") && len(fName) > 1 {
15 - return true
16 - }
17 -
18 - return false
19 -}
commands/files/is_hidden_windows.go deleted
-29
@@ -1,29 +0,0 @@
1 -// +build windows
2 -
3 -package files
4 -
5 -import (
6 - "path/filepath"
7 - "strings"
8 - "syscall"
9 -)
10 -
11 -func IsHidden(f File) bool {
12 -
13 - fName := filepath.Base(f.FileName())
14 -
15 - if strings.HasPrefix(fName, ".") && len(fName) > 1 {
16 - return true
17 - }
18 -
19 - p, e := syscall.UTF16PtrFromString(f.FullPath())
20 - if e != nil {
21 - return false
22 - }
23 -
24 - attrs, e := syscall.GetFileAttributes(p)
25 - if e != nil {
26 - return false
27 - }
28 - return attrs&syscall.FILE_ATTRIBUTE_HIDDEN != 0
29 -}
commands/files/linkfile.go deleted
-50
@@ -1,50 +0,0 @@
1 -package files
2 -
3 -import (
4 - "io"
5 - "os"
6 - "strings"
7 -)
8 -
9 -type Symlink struct {
10 - name string
11 - path string
12 - Target string
13 - stat os.FileInfo
14 -
15 - reader io.Reader
16 -}
17 -
18 -func NewLinkFile(name, path, target string, stat os.FileInfo) File {
19 - return &Symlink{
20 - name: name,
21 - path: path,
22 - Target: target,
23 - stat: stat,
24 - reader: strings.NewReader(target),
25 - }
26 -}
27 -
28 -func (lf *Symlink) IsDirectory() bool {
29 - return false
30 -}
31 -
32 -func (lf *Symlink) NextFile() (File, error) {
33 - return nil, io.EOF
34 -}
35 -
36 -func (f *Symlink) FileName() string {
37 - return f.name
38 -}
39 -
40 -func (f *Symlink) Close() error {
41 - return nil
42 -}
43 -
44 -func (f *Symlink) FullPath() string {
45 - return f.path
46 -}
47 -
48 -func (f *Symlink) Read(b []byte) (int, error) {
49 - return f.reader.Read(b)
50 -}
commands/files/multipartfile.go deleted
-115
@@ -1,115 +0,0 @@
1 -package files
2 -
3 -import (
4 - "io"
5 - "io/ioutil"
6 - "mime"
7 - "mime/multipart"
8 - "net/url"
9 -)
10 -
11 -const (
12 - multipartFormdataType = "multipart/form-data"
13 -
14 - applicationDirectory = "application/x-directory"
15 - applicationSymlink = "application/symlink"
16 - applicationFile = "application/octet-stream"
17 -
18 - contentTypeHeader = "Content-Type"
19 -)
20 -
21 -// MultipartFile implements File, and is created from a `multipart.Part`.
22 -// It can be either a directory or file (checked by calling `IsDirectory()`).
23 -type MultipartFile struct {
24 - File
25 -
26 - Part *multipart.Part
27 - Reader *multipart.Reader
28 - Mediatype string
29 -}
30 -
31 -func NewFileFromPart(part *multipart.Part) (File, error) {
32 - f := &MultipartFile{
33 - Part: part,
34 - }
35 -
36 - contentType := part.Header.Get(contentTypeHeader)
37 - switch contentType {
38 - case applicationSymlink:
39 - out, err := ioutil.ReadAll(part)
40 - if err != nil {
41 - return nil, err
42 - }
43 -
44 - return &Symlink{
45 - Target: string(out),
46 - name: f.FileName(),
47 - }, nil
48 - case applicationFile:
49 - return &ReaderFile{
50 - reader: part,
51 - filename: f.FileName(),
52 - abspath: part.Header.Get("abspath"),
53 - fullpath: f.FullPath(),
54 - }, nil
55 - }
56 -
57 - var err error
58 - f.Mediatype, _, err = mime.ParseMediaType(contentType)
59 - if err != nil {
60 - return nil, err
61 - }
62 -
63 - return f, nil
64 -}
65 -
66 -func (f *MultipartFile) IsDirectory() bool {
67 - return f.Mediatype == multipartFormdataType || f.Mediatype == applicationDirectory
68 -}
69 -
70 -func (f *MultipartFile) NextFile() (File, error) {
71 - if !f.IsDirectory() {
72 - return nil, ErrNotDirectory
73 - }
74 - if f.Reader != nil {
75 - part, err := f.Reader.NextPart()
76 - if err != nil {
77 - return nil, err
78 - }
79 -
80 - return NewFileFromPart(part)
81 - }
82 -
83 - return nil, io.EOF
84 -}
85 -
86 -func (f *MultipartFile) FileName() string {
87 - if f == nil || f.Part == nil {
88 - return ""
89 - }
90 -
91 - filename, err := url.QueryUnescape(f.Part.FileName())
92 - if err != nil {
93 - // if there is a unescape error, just treat the name as unescaped
94 - return f.Part.FileName()
95 - }
96 - return filename
97 -}
98 -
99 -func (f *MultipartFile) FullPath() string {
100 - return f.FileName()
101 -}
102 -
103 -func (f *MultipartFile) Read(p []byte) (int, error) {
104 - if f.IsDirectory() {
105 - return 0, ErrNotReader
106 - }
107 - return f.Part.Read(p)
108 -}
109 -
110 -func (f *MultipartFile) Close() error {
111 - if f.IsDirectory() {
112 - return ErrNotReader
113 - }
114 - return f.Part.Close()
115 -}
commands/files/readerfile.go deleted
-70
@@ -1,70 +0,0 @@
1 -package files
2 -
3 -import (
4 - "errors"
5 - "io"
6 - "os"
7 - "path/filepath"
8 -)
9 -
10 -// ReaderFile is a implementation of File created from an `io.Reader`.
11 -// ReaderFiles are never directories, and can be read from and closed.
12 -type ReaderFile struct {
13 - filename string
14 - fullpath string
15 - abspath string
16 - reader io.ReadCloser
17 - stat os.FileInfo
18 -}
19 -
20 -func NewReaderFile(filename, path string, reader io.ReadCloser, stat os.FileInfo) *ReaderFile {
21 - return &ReaderFile{filename, path, path, reader, stat}
22 -}
23 -
24 -func NewReaderPathFile(filename, path string, reader io.ReadCloser, stat os.FileInfo) (*ReaderFile, error) {
25 - abspath, err := filepath.Abs(path)
26 - if err != nil {
27 - return nil, err
28 - }
29 -
30 - return &ReaderFile{filename, path, abspath, reader, stat}, nil
31 -}
32 -
33 -func (f *ReaderFile) IsDirectory() bool {
34 - return false
35 -}
36 -
37 -func (f *ReaderFile) NextFile() (File, error) {
38 - return nil, ErrNotDirectory
39 -}
40 -
41 -func (f *ReaderFile) FileName() string {
42 - return f.filename
43 -}
44 -
45 -func (f *ReaderFile) FullPath() string {
46 - return f.fullpath
47 -}
48 -
49 -func (f *ReaderFile) AbsPath() string {
50 - return f.abspath
51 -}
52 -
53 -func (f *ReaderFile) Read(p []byte) (int, error) {
54 - return f.reader.Read(p)
55 -}
56 -
57 -func (f *ReaderFile) Close() error {
58 - return f.reader.Close()
59 -}
60 -
61 -func (f *ReaderFile) Stat() os.FileInfo {
62 - return f.stat
63 -}
64 -
65 -func (f *ReaderFile) Size() (int64, error) {
66 - if f.stat == nil {
67 - return 0, errors.New("File size unknown")
68 - }
69 - return f.stat.Size(), nil
70 -}
commands/files/serialfile.go deleted
-154
@@ -1,154 +0,0 @@
1 -package files
2 -
3 -import (
4 - "fmt"
5 - "io"
6 - "io/ioutil"
7 - "os"
8 - "path/filepath"
9 - "strings"
10 - "syscall"
11 -)
12 -
13 -// serialFile implements File, and reads from a path on the OS filesystem.
14 -// No more than one file will be opened at a time (directories will advance
15 -// to the next file when NextFile() is called).
16 -type serialFile struct {
17 - name string
18 - path string
19 - files []os.FileInfo
20 - stat os.FileInfo
21 - current *File
22 - handleHiddenFiles bool
23 -}
24 -
25 -func NewSerialFile(name, path string, hidden bool, stat os.FileInfo) (File, error) {
26 -
27 - switch mode := stat.Mode(); {
28 - case mode.IsRegular():
29 - file, err := os.Open(path)
30 - if err != nil {
31 - return nil, err
32 - }
33 - return NewReaderPathFile(name, path, file, stat)
34 - case mode.IsDir():
35 - // for directories, stat all of the contents first, so we know what files to
36 - // open when NextFile() is called
37 - contents, err := ioutil.ReadDir(path)
38 - if err != nil {
39 - return nil, err
40 - }
41 - return &serialFile{name, path, contents, stat, nil, hidden}, nil
42 - case mode&os.ModeSymlink != 0:
43 - target, err := os.Readlink(path)
44 - if err != nil {
45 - return nil, err
46 - }
47 - return NewLinkFile(name, path, target, stat), nil
48 - default:
49 - return nil, fmt.Errorf("Unrecognized file type for %s: %s", name, mode.String())
50 - }
51 -}
52 -
53 -func (f *serialFile) IsDirectory() bool {
54 - // non-directories get created as a ReaderFile, so serialFiles should only
55 - // represent directories
56 - return true
57 -}
58 -
59 -func (f *serialFile) NextFile() (File, error) {
60 - // if a file was opened previously, close it
61 - err := f.Close()
62 - if err != nil {
63 - switch err2 := err.(type) {
64 - case *os.PathError:
65 - if err2.Err != os.ErrClosed {
66 - return nil, err
67 - }
68 - default:
69 - return nil, err
70 - }
71 - }
72 -
73 - // if there aren't any files left in the root directory, we're done
74 - if len(f.files) == 0 {
75 - return nil, io.EOF
76 - }
77 -
78 - stat := f.files[0]
79 - f.files = f.files[1:]
80 -
81 - for !f.handleHiddenFiles && strings.HasPrefix(stat.Name(), ".") {
82 - if len(f.files) == 0 {
83 - return nil, io.EOF
84 - }
85 -
86 - stat = f.files[0]
87 - f.files = f.files[1:]
88 - }
89 -
90 - // open the next file
91 - fileName := filepath.ToSlash(filepath.Join(f.name, stat.Name()))
92 - filePath := filepath.ToSlash(filepath.Join(f.path, stat.Name()))
93 -
94 - // recursively call the constructor on the next file
95 - // if it's a regular file, we will open it as a ReaderFile
96 - // if it's a directory, files in it will be opened serially
97 - sf, err := NewSerialFile(fileName, filePath, f.handleHiddenFiles, stat)
98 - if err != nil {
99 - return nil, err
100 - }
101 -
102 - f.current = &sf
103 -
104 - return sf, nil
105 -}
106 -
107 -func (f *serialFile) FileName() string {
108 - return f.name
109 -}
110 -
111 -func (f *serialFile) FullPath() string {
112 - return f.path
113 -}
114 -
115 -func (f *serialFile) Read(p []byte) (int, error) {
116 - return 0, io.EOF
117 -}
118 -
119 -func (f *serialFile) Close() error {
120 - // close the current file if there is one
121 - if f.current != nil {
122 - err := (*f.current).Close()
123 - // ignore EINVAL error, the file might have already been closed
124 - if err != nil && err != syscall.EINVAL {
125 - return err
126 - }
127 - }
128 -
129 - return nil
130 -}
131 -
132 -func (f *serialFile) Stat() os.FileInfo {
133 - return f.stat
134 -}
135 -
136 -func (f *serialFile) Size() (int64, error) {
137 - if !f.stat.IsDir() {
138 - return f.stat.Size(), nil
139 - }
140 -
141 - var du int64
142 - err := filepath.Walk(f.FullPath(), func(p string, fi os.FileInfo, err error) error {
143 - if err != nil {
144 - return err
145 - }
146 -
147 - if fi != nil && fi.Mode()&(os.ModeSymlink|os.ModeNamedPipe) == 0 {
148 - du += fi.Size()
149 - }
150 - return nil
151 - })
152 -
153 - return du, err
154 -}
commands/files/slicefile.go deleted
-76
@@ -1,76 +0,0 @@
1 -package files
2 -
3 -import (
4 - "errors"
5 - "io"
6 -)
7 -
8 -// SliceFile implements File, and provides simple directory handling.
9 -// It contains children files, and is created from a `[]File`.
10 -// SliceFiles are always directories, and can't be read from or closed.
11 -type SliceFile struct {
12 - filename string
13 - path string
14 - files []File
15 - n int
16 -}
17 -
18 -func NewSliceFile(filename, path string, files []File) *SliceFile {
19 - return &SliceFile{filename, path, files, 0}
20 -}
21 -
22 -func (f *SliceFile) IsDirectory() bool {
23 - return true
24 -}
25 -
26 -func (f *SliceFile) NextFile() (File, error) {
27 - if f.n >= len(f.files) {
28 - return nil, io.EOF
29 - }
30 - file := f.files[f.n]
31 - f.n++
32 - return file, nil
33 -}
34 -
35 -func (f *SliceFile) FileName() string {
36 - return f.filename
37 -}
38 -
39 -func (f *SliceFile) FullPath() string {
40 - return f.path
41 -}
42 -
43 -func (f *SliceFile) Read(p []byte) (int, error) {
44 - return 0, io.EOF
45 -}
46 -
47 -func (f *SliceFile) Close() error {
48 - return ErrNotReader
49 -}
50 -
51 -func (f *SliceFile) Peek(n int) File {
52 - return f.files[n]
53 -}
54 -
55 -func (f *SliceFile) Length() int {
56 - return len(f.files)
57 -}
58 -
59 -func (f *SliceFile) Size() (int64, error) {
60 - var size int64
61 -
62 - for _, file := range f.files {
63 - sizeFile, ok := file.(SizeFile)
64 - if !ok {
65 - return 0, errors.New("Could not get size of child file")
66 - }
67 -
68 - s, err := sizeFile.Size()
69 - if err != nil {
70 - return 0, err
71 - }
72 - size += s
73 - }
74 -
75 - return size, nil
76 -}
commands/http/client.go
+14 -13
@@ -1,6 +1,7 @@
1 package http
2
3 import (
4 + "context"
5 "encoding/json"
6 "errors"
7 "fmt"
@@ -15,7 +16,7 @@ import (
16 cmds "github.com/ipfs/go-ipfs/commands"
17 config "github.com/ipfs/go-ipfs/repo/config"
18
18 - context "context"
19 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
20 )
21
22 const (
@@ -54,16 +55,16 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) {
55 }
56
57 // save user-provided encoding
57 - previousUserProvidedEncoding, found, err := req.Option(cmds.EncShort).String()
58 + previousUserProvidedEncoding, found, err := req.Option(cmdkit.EncShort).String()
59 if err != nil {
60 return nil, err
61 }
62
63 // override with json to send to server
63 - req.SetOption(cmds.EncShort, cmds.JSON)
64 + req.SetOption(cmdkit.EncShort, cmds.JSON)
65
66 // stream channel output
66 - req.SetOption(cmds.ChanOpt, "true")
67 + req.SetOption(cmdkit.ChanOpt, "true")
68
69 query, err := getQuery(req)
70 if err != nil {
@@ -112,7 +113,7 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) {
113 // reset to user provided encoding after sending request
114 // NB: if user has provided an encoding but it is the empty string,
115 // still leave it as JSON.
115 - req.SetOption(cmds.EncShort, previousUserProvidedEncoding)
116 + req.SetOption(cmdkit.EncShort, previousUserProvidedEncoding)
117 }
118
119 return res, nil
@@ -136,7 +137,7 @@ func getQuery(req cmds.Request) (string, error) {
137 for _, arg := range args {
138 argDef := argDefs[argDefIndex]
139 // skip ArgFiles
139 - for argDef.Type == cmds.ArgFile {
140 + for argDef.Type == cmdkit.ArgFile {
141 argDefIndex++
142 argDef = argDefs[argDefIndex]
143 }
@@ -190,13 +191,12 @@ func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error
191
192 // If we ran into an error
193 if httpRes.StatusCode >= http.StatusBadRequest {
193 - e := cmds.Error{}
194 + var e *cmdkit.Error
195
196 switch {
197 case httpRes.StatusCode == http.StatusNotFound:
198 // handle 404s
198 - e.Message = "Command not found."
199 - e.Code = cmds.ErrClient
199 + e = &cmdkit.Error{Message: "Command not found.", Code: cmdkit.ErrClient}
200
201 case contentType == plainText:
202 // handle non-marshalled errors
@@ -204,15 +204,16 @@ func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error
204 if err != nil {
205 return nil, err
206 }
207 - e.Message = string(mes)
208 - e.Code = cmds.ErrNormal
207
208 + e = &cmdkit.Error{Message: string(mes), Code: cmdkit.ErrNormal}
209 default:
210 // handle marshalled errors
212 - err = dec.Decode(&e)
211 + var rxErr cmdkit.Error
212 + err = dec.Decode(&rxErr)
213 if err != nil {
214 return nil, err
215 }
216 + e = &rxErr
217 }
218
219 res.SetError(e, e.Code)
@@ -245,7 +246,7 @@ func readStreamedJson(req cmds.Request, rr io.Reader, out chan<- interface{}, re
246 if err != nil {
247 if err != io.EOF {
248 log.Error(err)
248 - resp.SetError(err, cmds.ErrNormal)
249 + resp.SetError(err, cmdkit.ErrNormal)
250 }
251 return
252 }
commands/http/handler.go
+5 -4
@@ -16,6 +16,7 @@ import (
16 "github.com/ipfs/go-ipfs/repo/config"
17
18 cors "gx/ipfs/QmPG2kW5t27LuHgHnvhUwbHCNHAt2eUcb4gPHqofrESUdB/cors"
19 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
20 logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
21 )
22
@@ -167,8 +168,8 @@ func (i internalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
168 return
169 }
170
170 - rlog := i.ctx.ReqLog.Add(req)
171 - defer rlog.Finish()
171 + reqLogEnt := i.ctx.ReqLog.Add(req)
172 + defer i.ctx.ReqLog.Finish(reqLogEnt)
173
174 //ps: take note of the name clash - commands.Context != context.Context
175 req.SetInvocContext(i.ctx)
@@ -195,7 +196,7 @@ func (i internalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
196
197 func guessMimeType(res cmds.Response) (string, error) {
198 // Try to guess mimeType from the encoding option
198 - enc, found, err := res.Request().Option(cmds.EncShort).String()
199 + enc, found, err := res.Request().Option(cmdkit.EncShort).String()
200 if err != nil {
201 return "", err
202 }
@@ -224,7 +225,7 @@ func sendResponse(w http.ResponseWriter, r *http.Request, res cmds.Response, req
225 status := http.StatusOK
226 // if response contains an error, write an HTTP error status code
227 if e := res.Error(); e != nil {
227 - if e.Code == cmds.ErrClient {
228 + if e.Code == cmdkit.ErrClient {
229 status = http.StatusBadRequest
230 } else {
231 status = http.StatusInternalServerError
commands/http/multifilereader.go
+1 -1
@@ -9,7 +9,7 @@ import (
9 "net/url"
10 "sync"
11
12 - files "github.com/ipfs/go-ipfs/commands/files"
12 + files "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files"
13 )
14
15 // MultiFileReader reads from a `commands.File` (which can be a directory of files
commands/http/multifilereader_test.go
+1 -1
@@ -7,7 +7,7 @@ import (
7 "strings"
8 "testing"
9
10 - files "github.com/ipfs/go-ipfs/commands/files"
10 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files"
11 )
12
13 func TestOutput(t *testing.T) {
commands/http/parse.go
+8 -7
@@ -8,8 +8,10 @@ import (
8 "strings"
9
10 cmds "github.com/ipfs/go-ipfs/commands"
11 - files "github.com/ipfs/go-ipfs/commands/files"
11 path "github.com/ipfs/go-ipfs/path"
12 +
13 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
14 + files "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files"
15 )
16
17 // Parse parses the data in a http.Request and returns a command Request object
@@ -31,7 +33,6 @@ func Parse(r *http.Request, root *cmds.Command) (cmds.Request, error) {
33 if err != nil {
34 // 404 if there is no command at that path
35 return nil, ErrNotFound
34 -
36 }
37
38 if sub := cmd.Subcommand(pth[len(pth)-1]); sub == nil {
@@ -74,7 +75,7 @@ func Parse(r *http.Request, root *cmds.Command) (cmds.Request, error) {
75 numRequired--
76 }
77
77 - if argDef.Type == cmds.ArgString {
78 + if argDef.Type == cmdkit.ArgString {
79 if argDef.Variadic {
80 for _, s := range stringArgs {
81 args[valIndex] = s
@@ -90,7 +91,7 @@ func Parse(r *http.Request, root *cmds.Command) (cmds.Request, error) {
91 } else {
92 break
93 }
93 - } else if argDef.Type == cmds.ArgFile && argDef.Required && len(requiredFile) == 0 {
94 + } else if argDef.Type == cmdkit.ArgFile && argDef.Required && len(requiredFile) == 0 {
95 requiredFile = argDef.Name
96 }
97 }
@@ -149,10 +150,10 @@ func parseOptions(r *http.Request) (map[string]interface{}, []string) {
150 }
151
152 // default to setting encoding to JSON
152 - _, short := opts[cmds.EncShort]
153 - _, long := opts[cmds.EncLong]
153 + _, short := opts[cmdkit.EncShort]
154 + _, long := opts[cmdkit.EncLong]
155 if !short && !long {
155 - opts[cmds.EncShort] = cmds.JSON
156 + opts[cmdkit.EncShort] = cmds.JSON
157 }
158
159 return opts, args
commands/option.go deleted
-209
@@ -1,209 +0,0 @@
1 -package commands
2 -
3 -import (
4 - "fmt"
5 - "reflect"
6 - "strings"
7 -
8 - "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
9 -)
10 -
11 -// Types of Command options
12 -const (
13 - Invalid = reflect.Invalid
14 - Bool = reflect.Bool
15 - Int = reflect.Int
16 - Uint = reflect.Uint
17 - Float = reflect.Float64
18 - String = reflect.String
19 -)
20 -
21 -// Option is used to specify a field that will be provided by a consumer
22 -type Option interface {
23 - Names() []string // a list of unique names matched with user-provided flags
24 - Type() reflect.Kind // value must be this type
25 - Description() string // a short string that describes this option
26 - Default(interface{}) Option // sets the default value of the option
27 - DefaultVal() interface{}
28 -}
29 -
30 -type option struct {
31 - names []string
32 - kind reflect.Kind
33 - description string
34 - defaultVal interface{}
35 -}
36 -
37 -func (o *option) Names() []string {
38 - return o.names
39 -}
40 -
41 -func (o *option) Type() reflect.Kind {
42 - return o.kind
43 -}
44 -
45 -func (o *option) Description() string {
46 - if len(o.description) == 0 {
47 - return ""
48 - }
49 - if !strings.HasSuffix(o.description, ".") {
50 - o.description += "."
51 - }
52 - if o.defaultVal != nil {
53 - if strings.Contains(o.description, "<<default>>") {
54 - return strings.Replace(o.description, "<<default>>",
55 - fmt.Sprintf("Default: %v.", o.defaultVal), -1)
56 - } else {
57 - return fmt.Sprintf("%s Default: %v.", o.description, o.defaultVal)
58 - }
59 - }
60 - return o.description
61 -}
62 -
63 -// constructor helper functions
64 -func NewOption(kind reflect.Kind, names ...string) Option {
65 - if len(names) < 2 {
66 - // FIXME(btc) don't panic (fix_before_merge)
67 - panic("Options require at least two string values (name and description)")
68 - }
69 -
70 - desc := names[len(names)-1]
71 - names = names[:len(names)-1]
72 -
73 - return &option{
74 - names: names,
75 - kind: kind,
76 - description: desc,
77 - }
78 -}
79 -
80 -func (o *option) Default(v interface{}) Option {
81 - o.defaultVal = v
82 - return o
83 -}
84 -
85 -func (o *option) DefaultVal() interface{} {
86 - return o.defaultVal
87 -}
88 -
89 -// TODO handle description separately. this will take care of the panic case in
90 -// NewOption
91 -
92 -// For all func {Type}Option(...string) functions, the last variadic argument
93 -// is treated as the description field.
94 -
95 -func BoolOption(names ...string) Option {
96 - return NewOption(Bool, names...)
97 -}
98 -func IntOption(names ...string) Option {
99 - return NewOption(Int, names...)
100 -}
101 -func UintOption(names ...string) Option {
102 - return NewOption(Uint, names...)
103 -}
104 -func FloatOption(names ...string) Option {
105 - return NewOption(Float, names...)
106 -}
107 -func StringOption(names ...string) Option {
108 - return NewOption(String, names...)
109 -}
110 -
111 -type OptionValue struct {
112 - value interface{}
113 - found bool
114 - def Option
115 -}
116 -
117 -// Found returns true if the option value was provided by the user (not a default value)
118 -func (ov OptionValue) Found() bool {
119 - return ov.found
120 -}
121 -
122 -// Definition returns the option definition for the provided value
123 -func (ov OptionValue) Definition() Option {
124 - return ov.def
125 -}
126 -
127 -// value accessor methods, gets the value as a certain type
128 -func (ov OptionValue) Bool() (value bool, found bool, err error) {
129 - if !ov.found && ov.value == nil {
130 - return false, false, nil
131 - }
132 - val, ok := ov.value.(bool)
133 - if !ok {
134 - err = util.ErrCast()
135 - }
136 - return val, ov.found, err
137 -}
138 -
139 -func (ov OptionValue) Int() (value int, found bool, err error) {
140 - if !ov.found && ov.value == nil {
141 - return 0, false, nil
142 - }
143 - val, ok := ov.value.(int)
144 - if !ok {
145 - err = util.ErrCast()
146 - }
147 - return val, ov.found, err
148 -}
149 -
150 -func (ov OptionValue) Uint() (value uint, found bool, err error) {
151 - if !ov.found && ov.value == nil {
152 - return 0, false, nil
153 - }
154 - val, ok := ov.value.(uint)
155 - if !ok {
156 - err = util.ErrCast()
157 - }
158 - return val, ov.found, err
159 -}
160 -
161 -func (ov OptionValue) Float() (value float64, found bool, err error) {
162 - if !ov.found && ov.value == nil {
163 - return 0, false, nil
164 - }
165 - val, ok := ov.value.(float64)
166 - if !ok {
167 - err = util.ErrCast()
168 - }
169 - return val, ov.found, err
170 -}
171 -
172 -func (ov OptionValue) String() (value string, found bool, err error) {
173 - if !ov.found && ov.value == nil {
174 - return "", false, nil
175 - }
176 - val, ok := ov.value.(string)
177 - if !ok {
178 - err = util.ErrCast()
179 - }
180 - return val, ov.found, err
181 -}
182 -
183 -// Flag names
184 -const (
185 - EncShort = "enc"
186 - EncLong = "encoding"
187 - RecShort = "r"
188 - RecLong = "recursive"
189 - ChanOpt = "stream-channels"
190 - TimeoutOpt = "timeout"
191 -)
192 -
193 -// options that are used by this package
194 -var OptionEncodingType = StringOption(EncLong, EncShort, "The encoding type the output should be encoded with (json, xml, or text)")
195 -var OptionRecursivePath = BoolOption(RecLong, RecShort, "Add directory paths recursively").Default(false)
196 -var OptionStreamChannels = BoolOption(ChanOpt, "Stream channel output")
197 -var OptionTimeout = StringOption(TimeoutOpt, "set a global timeout on the command")
198 -
199 -// global options, added to every command
200 -var globalOptions = []Option{
201 - OptionEncodingType,
202 - OptionStreamChannels,
203 - OptionTimeout,
204 -}
205 -
206 -// the above array of Options, wrapped in a Command
207 -var globalCommand = &Command{
208 - Options: globalOptions,
209 -}
commands/option_test.go deleted
-45
@@ -1,45 +0,0 @@
1 -package commands
2 -
3 -import (
4 - "strings"
5 - "testing"
6 -)
7 -
8 -func TestOptionValueExtractBoolNotFound(t *testing.T) {
9 - t.Log("ensure that no error is returned when value is not found")
10 - optval := &OptionValue{found: false}
11 - _, _, err := optval.Bool()
12 - if err != nil {
13 - t.Fatal("Found was false. Err should have been nil")
14 - }
15 -}
16 -
17 -func TestOptionValueExtractWrongType(t *testing.T) {
18 -
19 - t.Log("ensure that error is returned when value if of wrong type")
20 -
21 - optval := &OptionValue{value: "wrong type: a string", found: true}
22 - _, _, err := optval.Bool()
23 - if err == nil {
24 - t.Fatal("No error returned. Failure.")
25 - }
26 -
27 - optval = &OptionValue{value: "wrong type: a string", found: true}
28 - _, _, err = optval.Int()
29 - if err == nil {
30 - t.Fatal("No error returned. Failure.")
31 - }
32 -}
33 -
34 -func TestLackOfDescriptionOfOptionDoesNotPanic(t *testing.T) {
35 - opt := BoolOption("a", "")
36 - opt.Description()
37 -}
38 -
39 -func TestDotIsAddedInDescripton(t *testing.T) {
40 - opt := BoolOption("a", "desc without dot")
41 - dest := opt.Description()
42 - if !strings.HasSuffix(dest, ".") {
43 - t.Fatal("dot should have been added at the end of description")
44 - }
45 -}
commands/reqlog.go
+33 -21
@@ -6,6 +6,7 @@ import (
6 "time"
7 )
8
9 +// ReqLogEntry is an entry in the request log
10 type ReqLogEntry struct {
11 StartTime time.Time
12 EndTime time.Time
@@ -15,31 +16,17 @@ type ReqLogEntry struct {
16 Args []string
17 ID int
18
18 - req Request
19 log *ReqLog
20 }
21
22 -func (r *ReqLogEntry) Finish() {
23 - log := r.log
24 - log.lock.Lock()
25 - defer log.lock.Unlock()
26 -
27 - r.Active = false
28 - r.EndTime = time.Now()
29 - r.log.maybeCleanup()
30 -
31 - // remove references to save memory
32 - r.req = nil
33 - r.log = nil
34 -
35 -}
36 -
22 +// Copy returns a copy of the ReqLogEntry
23 func (r *ReqLogEntry) Copy() *ReqLogEntry {
24 out := *r
25 out.log = nil
26 return &out
27 }
28
29 +// ReqLog is a log of requests
30 type ReqLog struct {
31 Requests []*ReqLogEntry
32 nextID int
@@ -47,10 +34,8 @@ type ReqLog struct {
34 keep time.Duration
35 }
36
37 +// Add creates a ReqLogEntry from a request and adds it to the log
38 func (rl *ReqLog) Add(req Request) *ReqLogEntry {
51 - rl.lock.Lock()
52 - defer rl.lock.Unlock()
53 -
39 rle := &ReqLogEntry{
40 StartTime: time.Now(),
41 Active: true,
@@ -58,18 +43,33 @@ func (rl *ReqLog) Add(req Request) *ReqLogEntry {
43 Options: req.Options(),
44 Args: req.StringArguments(),
45 ID: rl.nextID,
61 - req: req,
46 log: rl,
47 }
48
49 + rl.AddEntry(rle)
50 + return rle
51 +}
52 +
53 +// AddEntry adds an entry to the log
54 +func (rl *ReqLog) AddEntry(rle *ReqLogEntry) {
55 + rl.lock.Lock()
56 + defer rl.lock.Unlock()
57 +
58 rl.nextID++
59 rl.Requests = append(rl.Requests, rle)
67 - return rle
60 +
61 + if rle == nil || !rle.Active {
62 + rl.maybeCleanup()
63 + }
64 +
65 + return
66 }
67
68 +// ClearInactive removes stale entries
69 func (rl *ReqLog) ClearInactive() {
70 rl.lock.Lock()
71 defer rl.lock.Unlock()
72 +
73 k := rl.keep
74 rl.keep = 0
75 rl.cleanup()
@@ -97,6 +97,7 @@ func (rl *ReqLog) cleanup() {
97 rl.Requests = rl.Requests[:i]
98 }
99
100 +// SetKeepTime sets a duration after which an entry will be considered inactive
101 func (rl *ReqLog) SetKeepTime(t time.Duration) {
102 rl.lock.Lock()
103 defer rl.lock.Unlock()
@@ -115,3 +116,14 @@ func (rl *ReqLog) Report() []*ReqLogEntry {
116
117 return out
118 }
119 +
120 +// Finish marks an entry in the log as finished
121 +func (rl *ReqLog) Finish(rle *ReqLogEntry) {
122 + rl.lock.Lock()
123 + defer rl.lock.Unlock()
124 +
125 + rle.Active = false
126 + rle.EndTime = time.Now()
127 +
128 + rl.maybeCleanup()
129 +}
commands/request.go
+23 -23
@@ -11,13 +11,13 @@ import (
11 "strconv"
12 "time"
13
14 - "github.com/ipfs/go-ipfs/commands/files"
14 "github.com/ipfs/go-ipfs/core"
15 "github.com/ipfs/go-ipfs/repo/config"
16 u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
18 -)
17
20 -type OptMap map[string]interface{}
18 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
19 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files"
20 +)
21
22 type Context struct {
23 Online bool
@@ -66,10 +66,10 @@ func (c *Context) NodeWithoutConstructing() *core.IpfsNode {
66 // Request represents a call to a command from a consumer
67 type Request interface {
68 Path() []string
69 - Option(name string) *OptionValue
70 - Options() OptMap
69 + Option(name string) *cmdkit.OptionValue
70 + Options() cmdkit.OptMap
71 SetOption(name string, val interface{})
72 - SetOptions(opts OptMap) error
72 + SetOptions(opts cmdkit.OptMap) error
73 Arguments() []string
74 StringArguments() []string
75 SetArguments([]string)
@@ -89,13 +89,13 @@ type Request interface {
89
90 type request struct {
91 path []string
92 - options OptMap
92 + options cmdkit.OptMap
93 arguments []string
94 files files.File
95 cmd *Command
96 ctx Context
97 rctx context.Context
98 - optionDefs map[string]Option
98 + optionDefs map[string]cmdkit.Option
99 values map[string]interface{}
100 stdin io.Reader
101 }
@@ -106,7 +106,7 @@ func (r *request) Path() []string {
106 }
107
108 // Option returns the value of the option for given name.
109 -func (r *request) Option(name string) *OptionValue {
109 +func (r *request) Option(name string) *cmdkit.OptionValue {
110 // find the option with the specified name
111 option, found := r.optionDefs[name]
112 if !found {
@@ -117,16 +117,16 @@ func (r *request) Option(name string) *OptionValue {
117 for _, n := range option.Names() {
118 val, found := r.options[n]
119 if found {
120 - return &OptionValue{val, found, option}
120 + return &cmdkit.OptionValue{val, found, option}
121 }
122 }
123
124 - return &OptionValue{option.DefaultVal(), false, option}
124 + return &cmdkit.OptionValue{option.DefaultVal(), false, option}
125 }
126
127 // Options returns a copy of the option map
128 -func (r *request) Options() OptMap {
129 - output := make(OptMap)
128 +func (r *request) Options() cmdkit.OptMap {
129 + output := make(cmdkit.OptMap)
130 for k, v := range r.options {
131 output[k] = v
132 }
@@ -164,7 +164,7 @@ func (r *request) SetOption(name string, val interface{}) {
164 }
165
166 // SetOptions sets the option values, unsetting any values that were previously set
167 -func (r *request) SetOptions(opts OptMap) error {
167 +func (r *request) SetOptions(opts cmdkit.OptMap) error {
168 r.options = opts
169 return r.ConvertOptions()
170 }
@@ -212,7 +212,7 @@ func (r *request) haveVarArgsFromStdin() bool {
212 }
213
214 last := r.cmd.Arguments[len(r.cmd.Arguments)-1]
215 - return last.SupportsStdin && last.Type == ArgString && (last.Required || last.Variadic) &&
215 + return last.SupportsStdin && last.Type == cmdkit.ArgString && (last.Required || last.Variadic) &&
216 len(r.arguments) < len(r.cmd.Arguments)
217 }
218
@@ -293,27 +293,27 @@ func (r *request) Command() *Command {
293 type converter func(string) (interface{}, error)
294
295 var converters = map[reflect.Kind]converter{
296 - Bool: func(v string) (interface{}, error) {
296 + cmdkit.Bool: func(v string) (interface{}, error) {
297 if v == "" {
298 return true, nil
299 }
300 return strconv.ParseBool(v)
301 },
302 - Int: func(v string) (interface{}, error) {
302 + cmdkit.Int: func(v string) (interface{}, error) {
303 val, err := strconv.ParseInt(v, 0, 32)
304 if err != nil {
305 return nil, err
306 }
307 return int(val), err
308 },
309 - Uint: func(v string) (interface{}, error) {
309 + cmdkit.Uint: func(v string) (interface{}, error) {
310 val, err := strconv.ParseUint(v, 0, 32)
311 if err != nil {
312 return nil, err
313 }
314 return int(val), err
315 },
316 - Float: func(v string) (interface{}, error) {
316 + cmdkit.Float: func(v string) (interface{}, error) {
317 return strconv.ParseFloat(v, 64)
318 },
319 }
@@ -335,7 +335,7 @@ func (r *request) ConvertOptions() error {
335
336 kind := reflect.TypeOf(v).Kind()
337 if kind != opt.Type() {
338 - if kind == String {
338 + if kind == cmdkit.String {
339 convert := converters[opt.Type()]
340 str, ok := v.(string)
341 if !ok {
@@ -378,12 +378,12 @@ func NewEmptyRequest() (Request, error) {
378
379 // NewRequest returns a request initialized with given arguments
380 // An non-nil error will be returned if the provided option values are invalid
381 -func NewRequest(path []string, opts OptMap, args []string, file files.File, cmd *Command, optDefs map[string]Option) (Request, error) {
381 +func NewRequest(path []string, opts cmdkit.OptMap, args []string, file files.File, cmd *Command, optDefs map[string]cmdkit.Option) (Request, error) {
382 if opts == nil {
383 - opts = make(OptMap)
383 + opts = make(cmdkit.OptMap)
384 }
385 if optDefs == nil {
386 - optDefs = make(map[string]Option)
386 + optDefs = make(map[string]cmdkit.Option)
387 }
388
389 ctx := Context{}
commands/response.go
+9 -26
@@ -8,30 +8,13 @@ import (
8 "io"
9 "os"
10 "strings"
11 +
12 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
13 )
14
15 // ErrorType signfies a category of errors
16 type ErrorType uint
17
16 -// ErrorTypes convey what category of error ocurred
17 -const (
18 - ErrNormal ErrorType = iota // general errors
19 - ErrClient // error was caused by the client, (e.g. invalid CLI usage)
20 - ErrImplementation // programmer error in the server
21 - ErrNotFound // == HTTP 404 Not Found
22 - // TODO: add more types of errors for better error-specific handling
23 -)
24 -
25 -// Error is a struct for marshalling errors
26 -type Error struct {
27 - Message string
28 - Code ErrorType
29 -}
30 -
31 -func (e Error) Error() string {
32 - return e.Message
33 -}
34 -
18 // EncodingType defines a supported encoding
19 type EncodingType string
20
@@ -94,8 +77,8 @@ type Response interface {
77 Request() Request
78
79 // Set/Return the response Error
97 - SetError(err error, code ErrorType)
98 - Error() *Error
80 + SetError(err error, code cmdkit.ErrorType)
81 + Error() *cmdkit.Error
82
83 // Sets/Returns the response value
84 SetOutput(interface{})
@@ -123,7 +106,7 @@ type Response interface {
106
107 type response struct {
108 req Request
126 - err *Error
109 + err *cmdkit.Error
110 value interface{}
111 out io.Reader
112 length uint64
@@ -152,12 +135,12 @@ func (r *response) SetLength(l uint64) {
135 r.length = l
136 }
137
155 -func (r *response) Error() *Error {
138 +func (r *response) Error() *cmdkit.Error {
139 return r.err
140 }
141
159 -func (r *response) SetError(err error, code ErrorType) {
160 - r.err = &Error{Message: err.Error(), Code: code}
142 +func (r *response) SetError(err error, code cmdkit.ErrorType) {
143 + r.err = &cmdkit.Error{Message: err.Error(), Code: code}
144 }
145
146 func (r *response) Marshal() (io.Reader, error) {
@@ -165,7 +148,7 @@ func (r *response) Marshal() (io.Reader, error) {
148 return bytes.NewReader([]byte{}), nil
149 }
150
168 - enc, found, err := r.req.Option(EncShort).String()
151 + enc, found, err := r.req.Option(cmdkit.EncShort).String()
152 if err != nil {
153 return nil, err
154 }
commands/response_test.go
+6 -4
@@ -5,6 +5,8 @@ import (
5 "fmt"
6 "strings"
7 "testing"
8 +
9 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
10 )
11
12 type TestOutput struct {
@@ -26,7 +28,7 @@ func TestMarshalling(t *testing.T) {
28 t.Error("Should have failed (no encoding type specified in request)")
29 }
30
29 - req.SetOption(EncShort, JSON)
31 + req.SetOption(cmdkit.EncShort, JSON)
32
33 reader, err := res.Marshal()
34 if err != nil {
@@ -39,7 +41,7 @@ func TestMarshalling(t *testing.T) {
41 t.Error("Incorrect JSON output")
42 }
43
42 - res.SetError(fmt.Errorf("Oops!"), ErrClient)
44 + res.SetError(fmt.Errorf("Oops!"), cmdkit.ErrClient)
45 reader, err = res.Marshal()
46 if err != nil {
47 t.Error("Should have passed")
@@ -48,13 +50,13 @@ func TestMarshalling(t *testing.T) {
50 buf.ReadFrom(reader)
51 output = buf.String()
52 fmt.Println(removeWhitespace(output))
51 - if removeWhitespace(output) != "{\"Message\":\"Oops!\",\"Code\":1}" {
53 + if removeWhitespace(output) != `{"Message":"Oops!","Code":1,"Type":"error"}` {
54 t.Error("Incorrect JSON output")
55 }
56 }
57
58 func TestErrTypeOrder(t *testing.T) {
57 - if ErrNormal != 0 || ErrClient != 1 || ErrImplementation != 2 || ErrNotFound != 3 {
59 + if cmdkit.ErrNormal != 0 || cmdkit.ErrClient != 1 || cmdkit.ErrImplementation != 2 || cmdkit.ErrNotFound != 3 {
60 t.Fatal("ErrType order is wrong")
61 }
62 }
core/bootstrap.go
+1 -1
@@ -1,6 +1,7 @@
1 package core
2
3 import (
4 + "context"
5 "errors"
6 "fmt"
7 "io"
@@ -12,7 +13,6 @@ import (
13 math2 "github.com/ipfs/go-ipfs/thirdparty/math2"
14 lgbl "gx/ipfs/QmT4PgCNdv73hnFAqzHqwW44q7M9PWpykSswHDxndquZbc/go-libp2p-loggables"
15
15 - context "context"
16 inet "gx/ipfs/QmNa31VPzC561NWwRsJLE7nGYZYuuD2QfpK2b1q9BK54J1/go-libp2p-net"
17 pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore"
18 goprocess "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess"
core/commands/active.go
+19 -12
@@ -9,10 +9,13 @@ import (
9 "time"
10
11 cmds "github.com/ipfs/go-ipfs/commands"
12 + e "github.com/ipfs/go-ipfs/core/commands/e"
13 +
14 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
15 )
16
17 var ActiveReqsCmd = &cmds.Command{
15 - Helptext: cmds.HelpText{
18 + Helptext: cmdkit.HelpText{
19 Tagline: "List commands run on this IPFS node.",
20 ShortDescription: `
21 Lists running and recently run commands.
@@ -21,8 +24,8 @@ Lists running and recently run commands.
24 Run: func(req cmds.Request, res cmds.Response) {
25 res.SetOutput(req.InvocContext().ReqLog.Report())
26 },
24 - Options: []cmds.Option{
25 - cmds.BoolOption("verbose", "v", "Print extra information.").Default(false),
27 + Options: []cmdkit.Option{
28 + cmdkit.BoolOption("verbose", "v", "Print extra information.").Default(false),
29 },
30 Subcommands: map[string]*cmds.Command{
31 "clear": clearInactiveCmd,
@@ -30,10 +33,14 @@ Lists running and recently run commands.
33 },
34 Marshalers: map[cmds.EncodingType]cmds.Marshaler{
35 cmds.Text: func(res cmds.Response) (io.Reader, error) {
33 - out, ok := res.Output().(*[]*cmds.ReqLogEntry)
36 + v, err := unwrapOutput(res.Output())
37 + if err != nil {
38 + return nil, err
39 + }
40 +
41 + out, ok := v.(*[]*cmds.ReqLogEntry)
42 if !ok {
35 - log.Errorf("%#v", res.Output())
36 - return nil, cmds.ErrIncorrectType
43 + return nil, e.TypeErr(out, v)
44 }
45 buf := new(bytes.Buffer)
46
@@ -57,7 +64,7 @@ Lists running and recently run commands.
64 if verbose {
65 fmt.Fprintf(w, "%v\t[", req.Args)
66 var keys []string
60 - for k, _ := range req.Options {
67 + for k := range req.Options {
68 keys = append(keys, k)
69 }
70 sort.Strings(keys)
@@ -86,7 +93,7 @@ Lists running and recently run commands.
93 }
94
95 var clearInactiveCmd = &cmds.Command{
89 - Helptext: cmds.HelpText{
96 + Helptext: cmdkit.HelpText{
97 Tagline: "Clear inactive requests from the log.",
98 },
99 Run: func(req cmds.Request, res cmds.Response) {
@@ -95,16 +102,16 @@ var clearInactiveCmd = &cmds.Command{
102 }
103
104 var setRequestClearCmd = &cmds.Command{
98 - Helptext: cmds.HelpText{
105 + Helptext: cmdkit.HelpText{
106 Tagline: "Set how long to keep inactive requests in the log.",
107 },
101 - Arguments: []cmds.Argument{
102 - cmds.StringArg("time", true, false, "Time to keep inactive requests in log."),
108 + Arguments: []cmdkit.Argument{
109 + cmdkit.StringArg("time", true, false, "Time to keep inactive requests in log."),
110 },
111 Run: func(req cmds.Request, res cmds.Response) {
112 tval, err := time.ParseDuration(req.Arguments()[0])
113 if err != nil {
107 - res.SetError(err, cmds.ErrNormal)
114 + res.SetError(err, cmdkit.ErrNormal)
115 return
116 }
117
core/commands/add.go
+174 -126
@@ -4,12 +4,11 @@ import (
4 "errors"
5 "fmt"
6 "io"
7 + "os"
8 "strings"
9
10 bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
11 blockservice "github.com/ipfs/go-ipfs/blockservice"
11 - cmds "github.com/ipfs/go-ipfs/commands"
12 - files "github.com/ipfs/go-ipfs/commands/files"
12 core "github.com/ipfs/go-ipfs/core"
13 "github.com/ipfs/go-ipfs/core/coreunix"
14 offline "github.com/ipfs/go-ipfs/exchange/offline"
@@ -18,12 +17,14 @@ import (
17 mfs "github.com/ipfs/go-ipfs/mfs"
18 ft "github.com/ipfs/go-ipfs/unixfs"
19
21 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
20 + "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
21 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
22 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files"
23 mh "gx/ipfs/QmU9a9NV9RdPNwZQDYd5uKsm6N6LJLSvLbywDDYFbaaC6P/go-multihash"
24 "gx/ipfs/QmeWjRodbcZFKe5tMN7poEx3izym6osrLSnTLf9UjJZBbs/pb"
25 )
26
26 -// Error indicating the max depth has been exceded.
27 +// ErrDepthLimitExceeded indicates that the max depth has been exceded.
28 var ErrDepthLimitExceeded = fmt.Errorf("depth limit exceeded")
29
30 const (
@@ -47,7 +48,7 @@ const (
48 const adderOutChanSize = 8
49
50 var AddCmd = &cmds.Command{
50 - Helptext: cmds.HelpText{
51 + Helptext: cmdkit.HelpText{
52 Tagline: "Add a file or directory to ipfs.",
53 ShortDescription: `
54 Adds contents of <path> to ipfs. Use -r to add directories (recursively).
@@ -98,26 +99,26 @@ You can now check what blocks have been created by:
99 `,
100 },
101
101 - Arguments: []cmds.Argument{
102 - cmds.FileArg("path", true, true, "The path to a file to be added to ipfs.").EnableRecursive().EnableStdin(),
102 + Arguments: []cmdkit.Argument{
103 + cmdkit.FileArg("path", true, true, "The path to a file to be added to ipfs.").EnableRecursive().EnableStdin(),
104 },
104 - Options: []cmds.Option{
105 - cmds.OptionRecursivePath, // a builtin option that allows recursive paths (-r, --recursive)
106 - cmds.BoolOption(quietOptionName, "q", "Write minimal output."),
107 - cmds.BoolOption(quieterOptionName, "Q", "Write only final hash."),
108 - cmds.BoolOption(silentOptionName, "Write no output."),
109 - cmds.BoolOption(progressOptionName, "p", "Stream progress data."),
110 - cmds.BoolOption(trickleOptionName, "t", "Use trickle-dag format for dag generation."),
111 - cmds.BoolOption(onlyHashOptionName, "n", "Only chunk and hash - do not write to disk."),
112 - cmds.BoolOption(wrapOptionName, "w", "Wrap files with a directory object."),
113 - cmds.BoolOption(hiddenOptionName, "H", "Include files that are hidden. Only takes effect on recursive add."),
114 - cmds.StringOption(chunkerOptionName, "s", "Chunking algorithm, size-[bytes] or rabin-[min]-[avg]-[max]").Default("size-262144"),
115 - cmds.BoolOption(pinOptionName, "Pin this object when adding.").Default(true),
116 - cmds.BoolOption(rawLeavesOptionName, "Use raw blocks for leaf nodes. (experimental)"),
117 - cmds.BoolOption(noCopyOptionName, "Add the file using filestore. (experimental)"),
118 - cmds.BoolOption(fstoreCacheOptionName, "Check the filestore for pre-existing blocks. (experimental)"),
119 - cmds.IntOption(cidVersionOptionName, "Cid version. Non-zero value will change default of 'raw-leaves' to true. (experimental)").Default(0),
120 - cmds.StringOption(hashOptionName, "Hash function to use. Will set Cid version to 1 if used. (experimental)").Default("sha2-256"),
105 + Options: []cmdkit.Option{
106 + cmdkit.OptionRecursivePath, // a builtin option that allows recursive paths (-r, --recursive)
107 + cmdkit.BoolOption(quietOptionName, "q", "Write minimal output."),
108 + cmdkit.BoolOption(quieterOptionName, "Q", "Write only final hash."),
109 + cmdkit.BoolOption(silentOptionName, "Write no output."),
110 + cmdkit.BoolOption(progressOptionName, "p", "Stream progress data."),
111 + cmdkit.BoolOption(trickleOptionName, "t", "Use trickle-dag format for dag generation."),
112 + cmdkit.BoolOption(onlyHashOptionName, "n", "Only chunk and hash - do not write to disk."),
113 + cmdkit.BoolOption(wrapOptionName, "w", "Wrap files with a directory object."),
114 + cmdkit.BoolOption(hiddenOptionName, "H", "Include files that are hidden. Only takes effect on recursive add."),
115 + cmdkit.StringOption(chunkerOptionName, "s", "Chunking algorithm, size-[bytes] or rabin-[min]-[avg]-[max]").Default("size-262144"),
116 + cmdkit.BoolOption(pinOptionName, "Pin this object when adding.").Default(true),
117 + cmdkit.BoolOption(rawLeavesOptionName, "Use raw blocks for leaf nodes. (experimental)"),
118 + cmdkit.BoolOption(noCopyOptionName, "Add the file using filestore. (experimental)"),
119 + cmdkit.BoolOption(fstoreCacheOptionName, "Check the filestore for pre-existing blocks. (experimental)"),
120 + cmdkit.IntOption(cidVersionOptionName, "Cid version. Non-zero value will change default of 'raw-leaves' to true. (experimental)").Default(0),
121 + cmdkit.StringOption(hashOptionName, "Hash function to use. Will set Cid version to 1 if used. (experimental)").Default("sha2-256"),
122 },
123 PreRun: func(req cmds.Request) error {
124 quiet, _, _ := req.Option(quietOptionName).Bool()
@@ -154,29 +155,28 @@ You can now check what blocks have been created by:
155 return
156 }
157
157 - log.Debugf("Total size of file being added: %v\n", size)
158 sizeCh <- size
159 }()
160
161 return nil
162 },
163 - Run: func(req cmds.Request, res cmds.Response) {
163 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
164 n, err := req.InvocContext().GetNode()
165 if err != nil {
166 - res.SetError(err, cmds.ErrNormal)
166 + res.SetError(err, cmdkit.ErrNormal)
167 return
168 }
169
170 cfg, err := n.Repo.Config()
171 if err != nil {
172 - res.SetError(err, cmds.ErrNormal)
172 + res.SetError(err, cmdkit.ErrNormal)
173 return
174 }
175 // check if repo will exceed storage limit if added
176 // TODO: this doesn't handle the case if the hashed file is already in blocks (deduplicated)
177 // TODO: conditional GC is disabled due to it is somehow not possible to pass the size to the daemon
178 //if err := corerepo.ConditionalGC(req.Context(), n, uint64(size)); err != nil {
179 - // res.SetError(err, cmds.ErrNormal)
179 + // res.SetError(err, cmdkit.ErrNormal)
180 // return
181 //}
182
@@ -196,7 +196,7 @@ You can now check what blocks have been created by:
196
197 if nocopy && !cfg.Experimental.FilestoreEnabled {
198 res.SetError(errors.New("filestore is not enabled, see https://git.io/vy4XN"),
199 - cmds.ErrClient)
199 + cmdkit.ErrClient)
200 return
201 }
202
@@ -205,7 +205,7 @@ You can now check what blocks have been created by:
205 }
206
207 if nocopy && !rawblks {
208 - res.SetError(fmt.Errorf("nocopy option requires '--raw-leaves' to be enabled as well"), cmds.ErrNormal)
208 + res.SetError(fmt.Errorf("nocopy option requires '--raw-leaves' to be enabled as well"), cmdkit.ErrNormal)
209 return
210 }
211
@@ -219,13 +219,13 @@ You can now check what blocks have been created by:
219
220 prefix, err := dag.PrefixForCidVersion(cidVer)
221 if err != nil {
222 - res.SetError(err, cmds.ErrNormal)
222 + res.SetError(err, cmdkit.ErrNormal)
223 return
224 }
225
226 hashFunCode, ok := mh.Names[strings.ToLower(hashFunStr)]
227 if !ok {
228 - res.SetError(fmt.Errorf("unrecognized hash function: %s", strings.ToLower(hashFunStr)), cmds.ErrNormal)
228 + res.SetError(fmt.Errorf("unrecognized hash function: %s", strings.ToLower(hashFunStr)), cmdkit.ErrNormal)
229 return
230 }
231
@@ -239,7 +239,7 @@ You can now check what blocks have been created by:
239 NilRepo: true,
240 })
241 if err != nil {
242 - res.SetError(err, cmds.ErrNormal)
242 + res.SetError(err, cmdkit.ErrNormal)
243 return
244 }
245 n = nilnode
@@ -259,15 +259,14 @@ You can now check what blocks have been created by:
259 bserv := blockservice.New(addblockstore, exch)
260 dserv := dag.NewDAGService(bserv)
261
262 + outChan := make(chan interface{}, adderOutChanSize)
263 +
264 fileAdder, err := coreunix.NewAdder(req.Context(), n.Pinning, n.Blockstore, dserv)
265 if err != nil {
264 - res.SetError(err, cmds.ErrNormal)
266 + res.SetError(err, cmdkit.ErrNormal)
267 return
268 }
269
268 - outChan := make(chan interface{}, adderOutChanSize)
269 - res.SetOutput((<-chan interface{})(outChan))
270 -
270 fileAdder.Out = outChan
271 fileAdder.Chunker = chunker
272 fileAdder.Progress = progress
@@ -284,7 +283,7 @@ You can now check what blocks have been created by:
283 md := dagtest.Mock()
284 mr, err := mfs.NewRoot(req.Context(), md, ft.EmptyDirNode(), nil)
285 if err != nil {
287 - res.SetError(err, cmds.ErrNormal)
286 + res.SetError(err, cmdkit.ErrNormal)
287 return
288 }
289
@@ -321,112 +320,161 @@ You can now check what blocks have been created by:
320 return fileAdder.PinRoot()
321 }
322
323 + errCh := make(chan error)
324 go func() {
325 + var err error
326 + defer func() { errCh <- err }()
327 defer close(outChan)
326 - if err := addAllAndPin(req.Files()); err != nil {
327 - res.SetError(err, cmds.ErrNormal)
328 - return
329 - }
330 -
328 + err = addAllAndPin(req.Files())
329 }()
332 - },
333 - PostRun: func(req cmds.Request, res cmds.Response) {
334 - if res.Error() != nil {
330 +
331 + defer res.Close()
332 +
333 + err = res.Emit(outChan)
334 + if err != nil {
335 + log.Error(err)
336 return
337 }
337 - outChan, ok := res.Output().(<-chan interface{})
338 - if !ok {
339 - res.SetError(u.ErrCast(), cmds.ErrNormal)
340 - return
338 + err = <-errCh
339 + if err != nil {
340 + res.SetError(err, cmdkit.ErrNormal)
341 }
342 - res.SetOutput(nil)
342 + },
343 + PostRun: map[cmds.EncodingType]func(cmds.Request, cmds.ResponseEmitter) cmds.ResponseEmitter{
344 + cmds.CLI: func(req cmds.Request, re cmds.ResponseEmitter) cmds.ResponseEmitter {
345 + reNext, res := cmds.NewChanResponsePair(req)
346 + outChan := make(chan interface{})
347
344 - quiet, _, _ := req.Option(quietOptionName).Bool()
345 - quieter, _, _ := req.Option(quieterOptionName).Bool()
346 - quiet = quiet || quieter
348 + progressBar := func(wait chan struct{}) {
349 + defer close(wait)
350
348 - progress, _, _ := req.Option(progressOptionName).Bool()
351 + quiet, _, _ := req.Option(quietOptionName).Bool()
352 + quieter, _, _ := req.Option(quieterOptionName).Bool()
353 + quiet = quiet || quieter
354
350 - var bar *pb.ProgressBar
351 - if progress {
352 - bar = pb.New64(0).SetUnits(pb.U_BYTES)
353 - bar.ManualUpdate = true
354 - bar.ShowTimeLeft = false
355 - bar.ShowPercent = false
356 - bar.Output = res.Stderr()
357 - bar.Start()
358 - }
355 + progress, _, _ := req.Option(progressOptionName).Bool()
356
360 - var sizeChan chan int64
361 - s, found := req.Values()["size"]
362 - if found {
363 - sizeChan = s.(chan int64)
364 - }
357 + var bar *pb.ProgressBar
358 + if progress {
359 + bar = pb.New64(0).SetUnits(pb.U_BYTES)
360 + bar.ManualUpdate = true
361 + bar.ShowTimeLeft = false
362 + bar.ShowPercent = false
363 + bar.Output = os.Stderr
364 + bar.Start()
365 + }
366
366 - lastFile := ""
367 - lastHash := ""
368 - var totalProgress, prevFiles, lastBytes int64
369 -
370 - LOOP:
371 - for {
372 - select {
373 - case out, ok := <-outChan:
374 - if !ok {
375 - if quieter {
376 - fmt.Fprintln(res.Stdout(), lastHash)
377 - }
378 - break LOOP
367 + var sizeChan chan int64
368 + s, found := req.Values()["size"]
369 + if found {
370 + sizeChan = s.(chan int64)
371 }
380 - output := out.(*coreunix.AddedObject)
381 - if len(output.Hash) > 0 {
382 - lastHash = output.Hash
383 - if quieter {
384 - continue
385 - }
372
387 - if progress {
388 - // clear progress bar line before we print "added x" output
389 - fmt.Fprintf(res.Stderr(), "\033[2K\r")
373 + lastFile := ""
374 + lastHash := ""
375 + var totalProgress, prevFiles, lastBytes int64
376 +
377 + LOOP:
378 + for {
379 + select {
380 + case out, ok := <-outChan:
381 + if !ok {
382 + if quieter {
383 + fmt.Fprintln(os.Stdout, lastHash)
384 + }
385 +
386 + break LOOP
387 + }
388 + output := out.(*coreunix.AddedObject)
389 + if len(output.Hash) > 0 {
390 + lastHash = output.Hash
391 + if quieter {
392 + continue
393 + }
394 +
395 + if progress {
396 + // clear progress bar line before we print "added x" output
397 + fmt.Fprintf(os.Stderr, "\033[2K\r")
398 + }
399 + if quiet {
400 + fmt.Fprintf(os.Stdout, "%s\n", output.Hash)
401 + } else {
402 + fmt.Fprintf(os.Stdout, "added %s %s\n", output.Hash, output.Name)
403 + }
404 +
405 + } else {
406 + if !progress {
407 + continue
408 + }
409 +
410 + if len(lastFile) == 0 {
411 + lastFile = output.Name
412 + }
413 + if output.Name != lastFile || output.Bytes < lastBytes {
414 + prevFiles += lastBytes
415 + lastFile = output.Name
416 + }
417 + lastBytes = output.Bytes
418 + delta := prevFiles + lastBytes - totalProgress
419 + totalProgress = bar.Add64(delta)
420 + }
421 +
422 + if progress {
423 + bar.Update()
424 + }
425 + case size := <-sizeChan:
426 + if progress {
427 + bar.Total = size
428 + bar.ShowPercent = true
429 + bar.ShowBar = true
430 + bar.ShowTimeLeft = true
431 + }
432 + case <-req.Context().Done():
433 + re.SetError(req.Context().Err(), cmdkit.ErrNormal)
434 + return
435 }
391 - if quiet {
392 - fmt.Fprintf(res.Stdout(), "%s\n", output.Hash)
393 - } else {
394 - fmt.Fprintf(res.Stdout(), "added %s %s\n", output.Hash, output.Name)
395 - }
396 - } else {
397 - log.Debugf("add progress: %v %v\n", output.Name, output.Bytes)
436 + }
437 + }
438
399 - if !progress {
400 - continue
401 - }
439 + go func() {
440 + // defer order important! First close outChan, then wait for output to finish, then close re
441 + defer re.Close()
442
403 - if len(lastFile) == 0 {
404 - lastFile = output.Name
405 - }
406 - if output.Name != lastFile || output.Bytes < lastBytes {
407 - prevFiles += lastBytes
408 - lastFile = output.Name
409 - }
410 - lastBytes = output.Bytes
411 - delta := prevFiles + lastBytes - totalProgress
412 - totalProgress = bar.Add64(delta)
443 + if e := res.Error(); e != nil {
444 + defer close(outChan)
445 + re.SetError(e.Message, e.Code)
446 + return
447 }
448
415 - if progress {
416 - bar.Update()
417 - }
418 - case size := <-sizeChan:
419 - if progress {
420 - bar.Total = size
421 - bar.ShowPercent = true
422 - bar.ShowBar = true
423 - bar.ShowTimeLeft = true
449 + wait := make(chan struct{})
450 + go progressBar(wait)
451 +
452 + defer func() { <-wait }()
453 + defer close(outChan)
454 +
455 + for {
456 + v, err := res.Next()
457 + if err != nil {
458 + // replace error by actual error - will be looked at by next if-statement
459 + if err == cmds.ErrRcvdError {
460 + err = res.Error()
461 + }
462 +
463 + if e, ok := err.(*cmdkit.Error); ok {
464 + re.Emit(e)
465 + } else if err != io.EOF {
466 + re.SetError(err, cmdkit.ErrNormal)
467 + }
468 +
469 + return
470 + }
471 +
472 + outChan <- v
473 }
425 - case <-req.Context().Done():
426 - res.SetError(req.Context().Err(), cmds.ErrNormal)
427 - return
428 - }
429 - }
474 + }()
475 +
476 + return reNext
477 + },
478 },
479 Type: coreunix.AddedObject{},
480 }
core/commands/bitswap.go
+84 -70
@@ -5,52 +5,57 @@ import (
5 "fmt"
6 "io"
7
8 - cmds "github.com/ipfs/go-ipfs/commands"
8 + oldcmds "github.com/ipfs/go-ipfs/commands"
9 + e "github.com/ipfs/go-ipfs/core/commands/e"
10 bitswap "github.com/ipfs/go-ipfs/exchange/bitswap"
11 decision "github.com/ipfs/go-ipfs/exchange/bitswap/decision"
12
13 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
14 "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
14 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
15 + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
16 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
17 peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer"
18 )
19
20 var BitswapCmd = &cmds.Command{
19 - Helptext: cmds.HelpText{
21 + Helptext: cmdkit.HelpText{
22 Tagline: "Interact with the bitswap agent.",
23 ShortDescription: ``,
24 },
25 +
26 Subcommands: map[string]*cmds.Command{
27 + "stat": bitswapStatCmd,
28 + },
29 + OldSubcommands: map[string]*oldcmds.Command{
30 "wantlist": showWantlistCmd,
25 - "stat": bitswapStatCmd,
31 "unwant": unwantCmd,
32 "ledger": ledgerCmd,
33 "reprovide": reprovideCmd,
34 },
35 }
36
32 -var unwantCmd = &cmds.Command{
33 - Helptext: cmds.HelpText{
37 +var unwantCmd = &oldcmds.Command{
38 + Helptext: cmdkit.HelpText{
39 Tagline: "Remove a given block from your wantlist.",
40 },
36 - Arguments: []cmds.Argument{
37 - cmds.StringArg("key", true, true, "Key(s) to remove from your wantlist.").EnableStdin(),
41 + Arguments: []cmdkit.Argument{
42 + cmdkit.StringArg("key", true, true, "Key(s) to remove from your wantlist.").EnableStdin(),
43 },
39 - Run: func(req cmds.Request, res cmds.Response) {
44 + Run: func(req oldcmds.Request, res oldcmds.Response) {
45 nd, err := req.InvocContext().GetNode()
46 if err != nil {
42 - res.SetError(err, cmds.ErrNormal)
47 + res.SetError(err, cmdkit.ErrNormal)
48 return
49 }
50
51 if !nd.OnlineMode() {
47 - res.SetError(errNotOnline, cmds.ErrClient)
52 + res.SetError(errNotOnline, cmdkit.ErrClient)
53 return
54 }
55
56 bs, ok := nd.Exchange.(*bitswap.Bitswap)
57 if !ok {
53 - res.SetError(u.ErrCast(), cmds.ErrNormal)
58 + res.SetError(e.TypeErr(bs, nd.Exchange), cmdkit.ErrNormal)
59 return
60 }
61
@@ -58,7 +63,7 @@ var unwantCmd = &cmds.Command{
63 for _, arg := range req.Arguments() {
64 c, err := cid.Decode(arg)
65 if err != nil {
61 - res.SetError(err, cmds.ErrNormal)
66 + res.SetError(err, cmdkit.ErrNormal)
67 return
68 }
69
@@ -73,43 +78,43 @@ var unwantCmd = &cmds.Command{
78 },
79 }
80
76 -var showWantlistCmd = &cmds.Command{
77 - Helptext: cmds.HelpText{
81 +var showWantlistCmd = &oldcmds.Command{
82 + Helptext: cmdkit.HelpText{
83 Tagline: "Show blocks currently on the wantlist.",
84 ShortDescription: `
85 Print out all blocks currently on the bitswap wantlist for the local peer.`,
86 },
82 - Options: []cmds.Option{
83 - cmds.StringOption("peer", "p", "Specify which peer to show wantlist for. Default: self."),
87 + Options: []cmdkit.Option{
88 + cmdkit.StringOption("peer", "p", "Specify which peer to show wantlist for. Default: self."),
89 },
90 Type: KeyList{},
86 - Run: func(req cmds.Request, res cmds.Response) {
91 + Run: func(req oldcmds.Request, res oldcmds.Response) {
92 nd, err := req.InvocContext().GetNode()
93 if err != nil {
89 - res.SetError(err, cmds.ErrNormal)
94 + res.SetError(err, cmdkit.ErrNormal)
95 return
96 }
97
98 if !nd.OnlineMode() {
94 - res.SetError(errNotOnline, cmds.ErrClient)
99 + res.SetError(errNotOnline, cmdkit.ErrClient)
100 return
101 }
102
103 bs, ok := nd.Exchange.(*bitswap.Bitswap)
104 if !ok {
100 - res.SetError(u.ErrCast(), cmds.ErrNormal)
105 + res.SetError(e.TypeErr(bs, nd.Exchange), cmdkit.ErrNormal)
106 return
107 }
108
109 pstr, found, err := req.Option("peer").String()
110 if err != nil {
106 - res.SetError(err, cmds.ErrNormal)
111 + res.SetError(err, cmdkit.ErrNormal)
112 return
113 }
114 if found {
115 pid, err := peer.IDB58Decode(pstr)
116 if err != nil {
112 - res.SetError(err, cmds.ErrNormal)
117 + res.SetError(err, cmdkit.ErrNormal)
118 return
119 }
120 if pid == nd.Identity {
@@ -122,73 +127,74 @@ Print out all blocks currently on the bitswap wantlist for the local peer.`,
127 res.SetOutput(&KeyList{bs.GetWantlist()})
128 }
129 },
125 - Marshalers: cmds.MarshalerMap{
126 - cmds.Text: KeyListTextMarshaler,
130 + Marshalers: oldcmds.MarshalerMap{
131 + oldcmds.Text: KeyListTextMarshaler,
132 },
133 }
134
135 var bitswapStatCmd = &cmds.Command{
131 - Helptext: cmds.HelpText{
136 + Helptext: cmdkit.HelpText{
137 Tagline: "Show some diagnostic information on the bitswap agent.",
138 ShortDescription: ``,
139 },
140 Type: bitswap.Stat{},
136 - Run: func(req cmds.Request, res cmds.Response) {
141 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
142 nd, err := req.InvocContext().GetNode()
143 if err != nil {
139 - res.SetError(err, cmds.ErrNormal)
144 + res.SetError(err, cmdkit.ErrNormal)
145 return
146 }
147
148 if !nd.OnlineMode() {
144 - res.SetError(errNotOnline, cmds.ErrClient)
149 + res.SetError(errNotOnline, cmdkit.ErrClient)
150 return
151 }
152
153 bs, ok := nd.Exchange.(*bitswap.Bitswap)
154 if !ok {
150 - res.SetError(u.ErrCast(), cmds.ErrNormal)
155 + res.SetError(e.TypeErr(bs, nd.Exchange), cmdkit.ErrNormal)
156 return
157 }
158
159 st, err := bs.Stat()
160 if err != nil {
156 - res.SetError(err, cmds.ErrNormal)
161 + res.SetError(err, cmdkit.ErrNormal)
162 return
163 }
164
160 - res.SetOutput(st)
165 + res.Emit(st)
166 },
162 - Marshalers: cmds.MarshalerMap{
163 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
164 - out, ok := res.Output().(*bitswap.Stat)
167 + Encoders: cmds.EncoderMap{
168 + cmds.Text: cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error {
169 + out, ok := v.(*bitswap.Stat)
170 if !ok {
166 - return nil, u.ErrCast()
171 + return e.TypeErr(out, v)
172 }
168 - buf := new(bytes.Buffer)
169 - fmt.Fprintln(buf, "bitswap status")
170 - fmt.Fprintf(buf, "\tprovides buffer: %d / %d\n", out.ProvideBufLen, bitswap.HasBlockBufferSize)
171 - fmt.Fprintf(buf, "\tblocks received: %d\n", out.BlocksReceived)
172 - fmt.Fprintf(buf, "\tblocks sent: %d\n", out.BlocksSent)
173 - fmt.Fprintf(buf, "\tdata received: %d\n", out.DataReceived)
174 - fmt.Fprintf(buf, "\tdata sent: %d\n", out.DataSent)
175 - fmt.Fprintf(buf, "\tdup blocks received: %d\n", out.DupBlksReceived)
176 - fmt.Fprintf(buf, "\tdup data received: %s\n", humanize.Bytes(out.DupDataReceived))
177 - fmt.Fprintf(buf, "\twantlist [%d keys]\n", len(out.Wantlist))
173 +
174 + fmt.Fprintln(w, "bitswap status")
175 + fmt.Fprintf(w, "\tprovides buffer: %d / %d\n", out.ProvideBufLen, bitswap.HasBlockBufferSize)
176 + fmt.Fprintf(w, "\tblocks received: %d\n", out.BlocksReceived)
177 + fmt.Fprintf(w, "\tblocks sent: %d\n", out.BlocksSent)
178 + fmt.Fprintf(w, "\tdata received: %d\n", out.DataReceived)
179 + fmt.Fprintf(w, "\tdata sent: %d\n", out.DataSent)
180 + fmt.Fprintf(w, "\tdup blocks received: %d\n", out.DupBlksReceived)
181 + fmt.Fprintf(w, "\tdup data received: %s\n", humanize.Bytes(out.DupDataReceived))
182 + fmt.Fprintf(w, "\twantlist [%d keys]\n", len(out.Wantlist))
183 for _, k := range out.Wantlist {
179 - fmt.Fprintf(buf, "\t\t%s\n", k.String())
184 + fmt.Fprintf(w, "\t\t%s\n", k.String())
185 }
181 - fmt.Fprintf(buf, "\tpartners [%d]\n", len(out.Peers))
186 + fmt.Fprintf(w, "\tpartners [%d]\n", len(out.Peers))
187 for _, p := range out.Peers {
183 - fmt.Fprintf(buf, "\t\t%s\n", p)
188 + fmt.Fprintf(w, "\t\t%s\n", p)
189 }
185 - return buf, nil
186 - },
190 +
191 + return nil
192 + }),
193 },
194 }
195
190 -var ledgerCmd = &cmds.Command{
191 - Helptext: cmds.HelpText{
196 +var ledgerCmd = &oldcmds.Command{
197 + Helptext: cmdkit.HelpText{
198 Tagline: "Show the current ledger for a peer.",
199 ShortDescription: `
200 The Bitswap decision engine tracks the number of bytes exchanged between IPFS
@@ -196,41 +202,47 @@ nodes, and stores this information as a collection of ledgers. This command
202 prints the ledger associated with a given peer.
203 `,
204 },
199 - Arguments: []cmds.Argument{
200 - cmds.StringArg("peer", true, false, "The PeerID (B58) of the ledger to inspect."),
205 + Arguments: []cmdkit.Argument{
206 + cmdkit.StringArg("peer", true, false, "The PeerID (B58) of the ledger to inspect."),
207 },
208 Type: decision.Receipt{},
203 - Run: func(req cmds.Request, res cmds.Response) {
209 + Run: func(req oldcmds.Request, res oldcmds.Response) {
210 nd, err := req.InvocContext().GetNode()
211 if err != nil {
206 - res.SetError(err, cmds.ErrNormal)
212 + res.SetError(err, cmdkit.ErrNormal)
213 return
214 }
215
216 if !nd.OnlineMode() {
211 - res.SetError(errNotOnline, cmds.ErrClient)
217 + res.SetError(errNotOnline, cmdkit.ErrClient)
218 return
219 }
220
221 bs, ok := nd.Exchange.(*bitswap.Bitswap)
222 if !ok {
217 - res.SetError(u.ErrCast(), cmds.ErrNormal)
223 + res.SetError(e.TypeErr(bs, nd.Exchange), cmdkit.ErrNormal)
224 return
225 }
226
227 partner, err := peer.IDB58Decode(req.Arguments()[0])
228 if err != nil {
223 - res.SetError(err, cmds.ErrClient)
229 + res.SetError(err, cmdkit.ErrClient)
230 return
231 }
232 res.SetOutput(bs.LedgerForPeer(partner))
233 },
228 - Marshalers: cmds.MarshalerMap{
229 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
230 - out, ok := res.Output().(*decision.Receipt)
234 + Marshalers: oldcmds.MarshalerMap{
235 + oldcmds.Text: func(res oldcmds.Response) (io.Reader, error) {
236 + v, err := unwrapOutput(res.Output())
237 + if err != nil {
238 + return nil, err
239 + }
240 +
241 + out, ok := v.(*decision.Receipt)
242 if !ok {
232 - return nil, u.ErrCast()
243 + return nil, e.TypeErr(out, v)
244 }
245 +
246 buf := new(bytes.Buffer)
247 fmt.Fprintf(buf, "Ledger for %s\n"+
248 "Debt ratio:\t%f\n"+
@@ -244,29 +256,31 @@ prints the ledger associated with a given peer.
256 },
257 }
258
247 -var reprovideCmd = &cmds.Command{
248 - Helptext: cmds.HelpText{
259 +var reprovideCmd = &oldcmds.Command{
260 + Helptext: cmdkit.HelpText{
261 Tagline: "Trigger reprovider.",
262 ShortDescription: `
263 Trigger reprovider to announce our data to network.
264 `,
265 },
254 - Run: func(req cmds.Request, res cmds.Response) {
266 + Run: func(req oldcmds.Request, res oldcmds.Response) {
267 nd, err := req.InvocContext().GetNode()
268 if err != nil {
257 - res.SetError(err, cmds.ErrNormal)
269 + res.SetError(err, cmdkit.ErrNormal)
270 return
271 }
272
273 if !nd.OnlineMode() {
262 - res.SetError(errNotOnline, cmds.ErrClient)
274 + res.SetError(errNotOnline, cmdkit.ErrClient)
275 return
276 }
277
278 err = nd.Reprovider.Trigger(req.Context())
279 if err != nil {
268 - res.SetError(err, cmds.ErrNormal)
280 + res.SetError(err, cmdkit.ErrNormal)
281 return
282 }
283 +
284 + res.SetOutput(nil)
285 },
286 }
core/commands/block.go
+92 -66
@@ -5,13 +5,14 @@ import (
5 "fmt"
6 "io"
7 "io/ioutil"
8 - "strings"
8 + "os"
9
10 util "github.com/ipfs/go-ipfs/blocks/blockstore/util"
11 - cmds "github.com/ipfs/go-ipfs/commands"
11 + e "github.com/ipfs/go-ipfs/core/commands/e"
12 + "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
13 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
14
15 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
14 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
16 blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format"
17 mh "gx/ipfs/QmU9a9NV9RdPNwZQDYd5uKsm6N6LJLSvLbywDDYFbaaC6P/go-multihash"
18 )
@@ -26,7 +27,7 @@ func (bs BlockStat) String() string {
27 }
28
29 var BlockCmd = &cmds.Command{
29 - Helptext: cmds.HelpText{
30 + Helptext: cmdkit.HelpText{
31 Tagline: "Interact with raw IPFS blocks.",
32 ShortDescription: `
33 'ipfs block' is a plumbing command used to manipulate raw IPFS blocks.
@@ -44,7 +45,7 @@ multihash.
45 }
46
47 var blockStatCmd = &cmds.Command{
47 - Helptext: cmds.HelpText{
48 + Helptext: cmdkit.HelpText{
49 Tagline: "Print information of a raw IPFS block.",
50 ShortDescription: `
51 'ipfs block stat' is a plumbing command for retrieving information
@@ -56,32 +57,39 @@ on raw IPFS blocks. It outputs the following to stdout:
57 `,
58 },
59
59 - Arguments: []cmds.Argument{
60 - cmds.StringArg("key", true, false, "The base58 multihash of an existing block to stat.").EnableStdin(),
60 + Arguments: []cmdkit.Argument{
61 + cmdkit.StringArg("key", true, false, "The base58 multihash of an existing block to stat.").EnableStdin(),
62 },
62 - Run: func(req cmds.Request, res cmds.Response) {
63 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
64 b, err := getBlockForKey(req, req.Arguments()[0])
65 if err != nil {
65 - res.SetError(err, cmds.ErrNormal)
66 + res.SetError(err, cmdkit.ErrNormal)
67 return
68 }
69
69 - res.SetOutput(&BlockStat{
70 + err = res.Emit(&BlockStat{
71 Key: b.Cid().String(),
72 Size: len(b.RawData()),
73 })
74 + if err != nil {
75 + log.Error(err)
76 + }
77 },
78 Type: BlockStat{},
75 - Marshalers: cmds.MarshalerMap{
76 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
77 - bs := res.Output().(*BlockStat)
78 - return strings.NewReader(bs.String()), nil
79 - },
79 + Encoders: cmds.EncoderMap{
80 + cmds.Text: cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error {
81 + bs, ok := v.(*BlockStat)
82 + if !ok {
83 + return e.TypeErr(bs, v)
84 + }
85 + _, err := fmt.Fprintf(w, "%s", bs)
86 + return err
87 + }),
88 },
89 }
90
91 var blockGetCmd = &cmds.Command{
84 - Helptext: cmds.HelpText{
92 + Helptext: cmdkit.HelpText{
93 Tagline: "Get a raw IPFS block.",
94 ShortDescription: `
95 'ipfs block get' is a plumbing command for retrieving raw IPFS blocks.
@@ -89,22 +97,25 @@ It outputs to stdout, and <key> is a base58 encoded multihash.
97 `,
98 },
99
92 - Arguments: []cmds.Argument{
93 - cmds.StringArg("key", true, false, "The base58 multihash of an existing block to get.").EnableStdin(),
100 + Arguments: []cmdkit.Argument{
101 + cmdkit.StringArg("key", true, false, "The base58 multihash of an existing block to get.").EnableStdin(),
102 },
95 - Run: func(req cmds.Request, res cmds.Response) {
103 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
104 b, err := getBlockForKey(req, req.Arguments()[0])
105 if err != nil {
98 - res.SetError(err, cmds.ErrNormal)
106 + res.SetError(err, cmdkit.ErrNormal)
107 return
108 }
109
102 - res.SetOutput(bytes.NewReader(b.RawData()))
110 + err = res.Emit(bytes.NewReader(b.RawData()))
111 + if err != nil {
112 + log.Error(err)
113 + }
114 },
115 }
116
117 var blockPutCmd = &cmds.Command{
107 - Helptext: cmds.HelpText{
118 + Helptext: cmdkit.HelpText{
119 Tagline: "Store input as an IPFS block.",
120 ShortDescription: `
121 'ipfs block put' is a plumbing command for storing raw IPFS blocks.
@@ -112,36 +123,36 @@ It reads from stdin, and <key> is a base58 encoded multihash.
123 `,
124 },
125
115 - Arguments: []cmds.Argument{
116 - cmds.FileArg("data", true, false, "The data to be stored as an IPFS block.").EnableStdin(),
126 + Arguments: []cmdkit.Argument{
127 + cmdkit.FileArg("data", true, false, "The data to be stored as an IPFS block.").EnableStdin(),
128 },
118 - Options: []cmds.Option{
119 - cmds.StringOption("format", "f", "cid format for blocks to be created with.").Default("v0"),
120 - cmds.StringOption("mhtype", "multihash hash function").Default("sha2-256"),
121 - cmds.IntOption("mhlen", "multihash hash length").Default(-1),
129 + Options: []cmdkit.Option{
130 + cmdkit.StringOption("format", "f", "cid format for blocks to be created with.").Default("v0"),
131 + cmdkit.StringOption("mhtype", "multihash hash function").Default("sha2-256"),
132 + cmdkit.IntOption("mhlen", "multihash hash length").Default(-1),
133 },
123 - Run: func(req cmds.Request, res cmds.Response) {
134 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
135 n, err := req.InvocContext().GetNode()
136 if err != nil {
126 - res.SetError(err, cmds.ErrNormal)
137 + res.SetError(err, cmdkit.ErrNormal)
138 return
139 }
140
141 file, err := req.Files().NextFile()
142 if err != nil {
132 - res.SetError(err, cmds.ErrNormal)
143 + res.SetError(err, cmdkit.ErrNormal)
144 return
145 }
146
147 data, err := ioutil.ReadAll(file)
148 if err != nil {
138 - res.SetError(err, cmds.ErrNormal)
149 + res.SetError(err, cmdkit.ErrNormal)
150 return
151 }
152
153 err = file.Close()
154 if err != nil {
144 - res.SetError(err, cmds.ErrNormal)
155 + res.SetError(err, cmdkit.ErrNormal)
156 return
157 }
158
@@ -151,7 +162,7 @@ It reads from stdin, and <key> is a base58 encoded multihash.
162 format, _, _ := req.Option("format").String()
163 formatval, ok := cid.Codecs[format]
164 if !ok {
154 - res.SetError(fmt.Errorf("unrecognized format: %s", format), cmds.ErrNormal)
165 + res.SetError(fmt.Errorf("unrecognized format: %s", format), cmdkit.ErrNormal)
166 return
167 }
168 if format == "v0" {
@@ -162,47 +173,54 @@ It reads from stdin, and <key> is a base58 encoded multihash.
173 mhtype, _, _ := req.Option("mhtype").String()
174 mhtval, ok := mh.Names[mhtype]
175 if !ok {
165 - res.SetError(fmt.Errorf("unrecognized multihash function: %s", mhtype), cmds.ErrNormal)
176 + err := fmt.Errorf("unrecognized multihash function: %s", mhtype)
177 + res.SetError(err, cmdkit.ErrNormal)
178 return
179 }
180 pref.MhType = mhtval
181
182 mhlen, _, err := req.Option("mhlen").Int()
183 if err != nil {
172 - res.SetError(err, cmds.ErrNormal)
184 + res.SetError(err, cmdkit.ErrNormal)
185 return
186 }
187 pref.MhLength = mhlen
188
189 bcid, err := pref.Sum(data)
190 if err != nil {
179 - res.SetError(err, cmds.ErrNormal)
191 + res.SetError(err, cmdkit.ErrNormal)
192 return
193 }
194
195 b, err := blocks.NewBlockWithCid(data, bcid)
196 if err != nil {
185 - res.SetError(err, cmds.ErrNormal)
197 + res.SetError(err, cmdkit.ErrNormal)
198 return
199 }
188 - log.Debugf("BlockPut key: '%q'", b.Cid())
200
201 k, err := n.Blocks.AddBlock(b)
202 if err != nil {
192 - res.SetError(err, cmds.ErrNormal)
203 + res.SetError(err, cmdkit.ErrNormal)
204 return
205 }
206
196 - res.SetOutput(&BlockStat{
207 + err = res.Emit(&BlockStat{
208 Key: k.String(),
209 Size: len(data),
210 })
211 + if err != nil {
212 + log.Error(err)
213 + }
214 },
201 - Marshalers: cmds.MarshalerMap{
202 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
203 - bs := res.Output().(*BlockStat)
204 - return strings.NewReader(bs.Key + "\n"), nil
205 - },
215 + Encoders: cmds.EncoderMap{
216 + cmds.Text: cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error {
217 + bs, ok := v.(*BlockStat)
218 + if !ok {
219 + return e.TypeErr(bs, v)
220 + }
221 + _, err := fmt.Fprintf(w, "%s\n", bs.Key)
222 + return err
223 + }),
224 },
225 Type: BlockStat{},
226 }
@@ -227,29 +245,28 @@ func getBlockForKey(req cmds.Request, skey string) (blocks.Block, error) {
245 return nil, err
246 }
247
230 - log.Debugf("ipfs block: got block with key: %s", b.Cid())
248 return b, nil
249 }
250
251 var blockRmCmd = &cmds.Command{
235 - Helptext: cmds.HelpText{
252 + Helptext: cmdkit.HelpText{
253 Tagline: "Remove IPFS block(s).",
254 ShortDescription: `
255 'ipfs block rm' is a plumbing command for removing raw ipfs blocks.
256 It takes a list of base58 encoded multihashs to remove.
257 `,
258 },
242 - Arguments: []cmds.Argument{
243 - cmds.StringArg("hash", true, true, "Bash58 encoded multihash of block(s) to remove."),
259 + Arguments: []cmdkit.Argument{
260 + cmdkit.StringArg("hash", true, true, "Bash58 encoded multihash of block(s) to remove."),
261 },
245 - Options: []cmds.Option{
246 - cmds.BoolOption("force", "f", "Ignore nonexistent blocks.").Default(false),
247 - cmds.BoolOption("quiet", "q", "Write minimal output.").Default(false),
262 + Options: []cmdkit.Option{
263 + cmdkit.BoolOption("force", "f", "Ignore nonexistent blocks.").Default(false),
264 + cmdkit.BoolOption("quiet", "q", "Write minimal output.").Default(false),
265 },
249 - Run: func(req cmds.Request, res cmds.Response) {
266 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
267 n, err := req.InvocContext().GetNode()
268 if err != nil {
252 - res.SetError(err, cmds.ErrNormal)
269 + res.SetError(err, cmdkit.ErrNormal)
270 return
271 }
272 hashes := req.Arguments()
@@ -259,7 +276,8 @@ It takes a list of base58 encoded multihashs to remove.
276 for _, hash := range hashes {
277 c, err := cid.Decode(hash)
278 if err != nil {
262 - res.SetError(fmt.Errorf("invalid content id: %s (%s)", hash, err), cmds.ErrNormal)
279 + err = fmt.Errorf("invalid content id: %s (%s)", hash, err)
280 + res.SetError(err, cmdkit.ErrNormal)
281 return
282 }
283
@@ -269,21 +287,29 @@ It takes a list of base58 encoded multihashs to remove.
287 Quiet: quiet,
288 Force: force,
289 })
290 +
291 if err != nil {
273 - res.SetError(err, cmds.ErrNormal)
292 + res.SetError(err, cmdkit.ErrNormal)
293 return
294 }
276 - res.SetOutput(ch)
295 +
296 + err = res.Emit(ch)
297 + if err != nil {
298 + log.Error(err)
299 + }
300 },
278 - Marshalers: cmds.MarshalerMap{
279 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
280 - outChan, ok := res.Output().(<-chan interface{})
281 - if !ok {
282 - return nil, u.ErrCast()
283 - }
301 + PostRun: map[cmds.EncodingType]func(cmds.Request, cmds.ResponseEmitter) cmds.ResponseEmitter{
302 + cmds.CLI: func(req cmds.Request, re cmds.ResponseEmitter) cmds.ResponseEmitter {
303 + reNext, res := cmds.NewChanResponsePair(req)
304 +
305 + go func() {
306 + defer re.Close()
307 +
308 + err := util.ProcRmOutput(res.Next, os.Stdout, os.Stderr)
309 + cmds.HandleError(err, res, re)
310 + }()
311
285 - err := util.ProcRmOutput(outChan, res.Stdout(), res.Stderr())
286 - return nil, err
312 + return reNext
313 },
314 },
315 Type: util.RemovedBlock{},
core/commands/bootstrap.go
+79 -52
@@ -7,10 +7,12 @@ import (
7 "sort"
8
9 cmds "github.com/ipfs/go-ipfs/commands"
10 + e "github.com/ipfs/go-ipfs/core/commands/e"
11 repo "github.com/ipfs/go-ipfs/repo"
12 config "github.com/ipfs/go-ipfs/repo/config"
13 "github.com/ipfs/go-ipfs/repo/fsrepo"
13 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
14 +
15 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
16 )
17
18 type BootstrapOutput struct {
@@ -20,7 +22,7 @@ type BootstrapOutput struct {
22 var peerOptionDesc = "A peer to add to the bootstrap list (in the format '<multiaddr>/<peerID>')"
23
24 var BootstrapCmd = &cmds.Command{
23 - Helptext: cmds.HelpText{
25 + Helptext: cmdkit.HelpText{
26 Tagline: "Show or edit the list of bootstrap peers.",
27 ShortDescription: `
28 Running 'ipfs bootstrap' with no arguments will run 'ipfs bootstrap list'.
@@ -39,19 +41,19 @@ Running 'ipfs bootstrap' with no arguments will run 'ipfs bootstrap list'.
41 }
42
43 var bootstrapAddCmd = &cmds.Command{
42 - Helptext: cmds.HelpText{
44 + Helptext: cmdkit.HelpText{
45 Tagline: "Add peers to the bootstrap list.",
46 ShortDescription: `Outputs a list of peers that were added (that weren't already
47 in the bootstrap list).
48 ` + bootstrapSecurityWarning,
49 },
50
49 - Arguments: []cmds.Argument{
50 - cmds.StringArg("peer", false, true, peerOptionDesc).EnableStdin(),
51 + Arguments: []cmdkit.Argument{
52 + cmdkit.StringArg("peer", false, true, peerOptionDesc).EnableStdin(),
53 },
54
53 - Options: []cmds.Option{
54 - cmds.BoolOption("default", "Add default bootstrap nodes. (Deprecated, use 'default' subcommand instead)"),
55 + Options: []cmdkit.Option{
56 + cmdkit.BoolOption("default", "Add default bootstrap nodes. (Deprecated, use 'default' subcommand instead)"),
57 },
58 Subcommands: map[string]*cmds.Command{
59 "default": bootstrapAddDefaultCmd,
@@ -60,7 +62,7 @@ in the bootstrap list).
62 Run: func(req cmds.Request, res cmds.Response) {
63 deflt, _, err := req.Option("default").Bool()
64 if err != nil {
63 - res.SetError(err, cmds.ErrNormal)
65 + res.SetError(err, cmdkit.ErrNormal)
66 return
67 }
68
@@ -69,7 +71,7 @@ in the bootstrap list).
71 // parse separately for meaningful, correct error.
72 defltPeers, err := config.DefaultBootstrapPeers()
73 if err != nil {
72 - res.SetError(err, cmds.ErrNormal)
74 + res.SetError(err, cmdkit.ErrNormal)
75 return
76 }
77
@@ -77,7 +79,7 @@ in the bootstrap list).
79 } else {
80 parsedPeers, err := config.ParseBootstrapPeers(req.Arguments())
81 if err != nil {
80 - res.SetError(err, cmds.ErrNormal)
82 + res.SetError(err, cmdkit.ErrNormal)
83 return
84 }
85
@@ -85,25 +87,25 @@ in the bootstrap list).
87 }
88
89 if len(inputPeers) == 0 {
88 - res.SetError(errors.New("no bootstrap peers to add"), cmds.ErrClient)
90 + res.SetError(errors.New("no bootstrap peers to add"), cmdkit.ErrClient)
91 return
92 }
93
94 r, err := fsrepo.Open(req.InvocContext().ConfigRoot)
95 if err != nil {
94 - res.SetError(err, cmds.ErrNormal)
96 + res.SetError(err, cmdkit.ErrNormal)
97 return
98 }
99 defer r.Close()
100 cfg, err := r.Config()
101 if err != nil {
100 - res.SetError(err, cmds.ErrNormal)
102 + res.SetError(err, cmdkit.ErrNormal)
103 return
104 }
105
106 added, err := bootstrapAdd(r, cfg, inputPeers)
107 if err != nil {
106 - res.SetError(err, cmds.ErrNormal)
108 + res.SetError(err, cmdkit.ErrNormal)
109 return
110 }
111
@@ -112,13 +114,18 @@ in the bootstrap list).
114 Type: BootstrapOutput{},
115 Marshalers: cmds.MarshalerMap{
116 cmds.Text: func(res cmds.Response) (io.Reader, error) {
115 - v, ok := res.Output().(*BootstrapOutput)
117 + v, err := unwrapOutput(res.Output())
118 + if err != nil {
119 + return nil, err
120 + }
121 +
122 + out, ok := v.(*BootstrapOutput)
123 if !ok {
117 - return nil, u.ErrCast()
124 + return nil, e.TypeErr(out, v)
125 }
126
127 buf := new(bytes.Buffer)
121 - if err := bootstrapWritePeers(buf, "added ", v.Peers); err != nil {
128 + if err := bootstrapWritePeers(buf, "added ", out.Peers); err != nil {
129 return nil, err
130 }
131
@@ -128,7 +135,7 @@ in the bootstrap list).
135 }
136
137 var bootstrapAddDefaultCmd = &cmds.Command{
131 - Helptext: cmds.HelpText{
138 + Helptext: cmdkit.HelpText{
139 Tagline: "Add default peers to the bootstrap list.",
140 ShortDescription: `Outputs a list of peers that were added (that weren't already
141 in the bootstrap list).`,
@@ -136,26 +143,26 @@ in the bootstrap list).`,
143 Run: func(req cmds.Request, res cmds.Response) {
144 defltPeers, err := config.DefaultBootstrapPeers()
145 if err != nil {
139 - res.SetError(err, cmds.ErrNormal)
146 + res.SetError(err, cmdkit.ErrNormal)
147 return
148 }
149
150 r, err := fsrepo.Open(req.InvocContext().ConfigRoot)
151 if err != nil {
145 - res.SetError(err, cmds.ErrNormal)
152 + res.SetError(err, cmdkit.ErrNormal)
153 return
154 }
155
156 defer r.Close()
157 cfg, err := r.Config()
158 if err != nil {
152 - res.SetError(err, cmds.ErrNormal)
159 + res.SetError(err, cmdkit.ErrNormal)
160 return
161 }
162
163 added, err := bootstrapAdd(r, cfg, defltPeers)
164 if err != nil {
158 - res.SetError(err, cmds.ErrNormal)
165 + res.SetError(err, cmdkit.ErrNormal)
166 return
167 }
168
@@ -164,13 +171,18 @@ in the bootstrap list).`,
171 Type: BootstrapOutput{},
172 Marshalers: cmds.MarshalerMap{
173 cmds.Text: func(res cmds.Response) (io.Reader, error) {
167 - v, ok := res.Output().(*BootstrapOutput)
174 + v, err := unwrapOutput(res.Output())
175 + if err != nil {
176 + return nil, err
177 + }
178 +
179 + out, ok := v.(*BootstrapOutput)
180 if !ok {
169 - return nil, u.ErrCast()
181 + return nil, e.TypeErr(out, v)
182 }
183
184 buf := new(bytes.Buffer)
173 - if err := bootstrapWritePeers(buf, "added ", v.Peers); err != nil {
185 + if err := bootstrapWritePeers(buf, "added ", out.Peers); err != nil {
186 return nil, err
187 }
188
@@ -180,17 +192,17 @@ in the bootstrap list).`,
192 }
193
194 var bootstrapRemoveCmd = &cmds.Command{
183 - Helptext: cmds.HelpText{
195 + Helptext: cmdkit.HelpText{
196 Tagline: "Remove peers from the bootstrap list.",
197 ShortDescription: `Outputs the list of peers that were removed.
198 ` + bootstrapSecurityWarning,
199 },
200
189 - Arguments: []cmds.Argument{
190 - cmds.StringArg("peer", false, true, peerOptionDesc).EnableStdin(),
201 + Arguments: []cmdkit.Argument{
202 + cmdkit.StringArg("peer", false, true, peerOptionDesc).EnableStdin(),
203 },
192 - Options: []cmds.Option{
193 - cmds.BoolOption("all", "Remove all bootstrap peers. (Deprecated, use 'all' subcommand)"),
204 + Options: []cmdkit.Option{
205 + cmdkit.BoolOption("all", "Remove all bootstrap peers. (Deprecated, use 'all' subcommand)"),
206 },
207 Subcommands: map[string]*cmds.Command{
208 "all": bootstrapRemoveAllCmd,
@@ -198,19 +210,19 @@ var bootstrapRemoveCmd = &cmds.Command{
210 Run: func(req cmds.Request, res cmds.Response) {
211 all, _, err := req.Option("all").Bool()
212 if err != nil {
201 - res.SetError(err, cmds.ErrNormal)
213 + res.SetError(err, cmdkit.ErrNormal)
214 return
215 }
216
217 r, err := fsrepo.Open(req.InvocContext().ConfigRoot)
218 if err != nil {
207 - res.SetError(err, cmds.ErrNormal)
219 + res.SetError(err, cmdkit.ErrNormal)
220 return
221 }
222 defer r.Close()
223 cfg, err := r.Config()
224 if err != nil {
213 - res.SetError(err, cmds.ErrNormal)
225 + res.SetError(err, cmdkit.ErrNormal)
226 return
227 }
228
@@ -220,14 +232,14 @@ var bootstrapRemoveCmd = &cmds.Command{
232 } else {
233 input, perr := config.ParseBootstrapPeers(req.Arguments())
234 if perr != nil {
223 - res.SetError(perr, cmds.ErrNormal)
235 + res.SetError(perr, cmdkit.ErrNormal)
236 return
237 }
238
239 removed, err = bootstrapRemove(r, cfg, input)
240 }
241 if err != nil {
230 - res.SetError(err, cmds.ErrNormal)
242 + res.SetError(err, cmdkit.ErrNormal)
243 return
244 }
245
@@ -236,20 +248,25 @@ var bootstrapRemoveCmd = &cmds.Command{
248 Type: BootstrapOutput{},
249 Marshalers: cmds.MarshalerMap{
250 cmds.Text: func(res cmds.Response) (io.Reader, error) {
239 - v, ok := res.Output().(*BootstrapOutput)
251 + v, err := unwrapOutput(res.Output())
252 + if err != nil {
253 + return nil, err
254 + }
255 +
256 + out, ok := v.(*BootstrapOutput)
257 if !ok {
241 - return nil, u.ErrCast()
258 + return nil, e.TypeErr(out, v)
259 }
260
261 buf := new(bytes.Buffer)
245 - err := bootstrapWritePeers(buf, "removed ", v.Peers)
262 + err = bootstrapWritePeers(buf, "removed ", out.Peers)
263 return buf, err
264 },
265 },
266 }
267
268 var bootstrapRemoveAllCmd = &cmds.Command{
252 - Helptext: cmds.HelpText{
269 + Helptext: cmdkit.HelpText{
270 Tagline: "Remove all peers from the bootstrap list.",
271 ShortDescription: `Outputs the list of peers that were removed.`,
272 },
@@ -257,19 +274,19 @@ var bootstrapRemoveAllCmd = &cmds.Command{
274 Run: func(req cmds.Request, res cmds.Response) {
275 r, err := fsrepo.Open(req.InvocContext().ConfigRoot)
276 if err != nil {
260 - res.SetError(err, cmds.ErrNormal)
277 + res.SetError(err, cmdkit.ErrNormal)
278 return
279 }
280 defer r.Close()
281 cfg, err := r.Config()
282 if err != nil {
266 - res.SetError(err, cmds.ErrNormal)
283 + res.SetError(err, cmdkit.ErrNormal)
284 return
285 }
286
287 removed, err := bootstrapRemoveAll(r, cfg)
288 if err != nil {
272 - res.SetError(err, cmds.ErrNormal)
289 + res.SetError(err, cmdkit.ErrNormal)
290 return
291 }
292
@@ -278,20 +295,25 @@ var bootstrapRemoveAllCmd = &cmds.Command{
295 Type: BootstrapOutput{},
296 Marshalers: cmds.MarshalerMap{
297 cmds.Text: func(res cmds.Response) (io.Reader, error) {
281 - v, ok := res.Output().(*BootstrapOutput)
298 + v, err := unwrapOutput(res.Output())
299 + if err != nil {
300 + return nil, err
301 + }
302 +
303 + out, ok := v.(*BootstrapOutput)
304 if !ok {
283 - return nil, u.ErrCast()
305 + return nil, e.TypeErr(out, v)
306 }
307
308 buf := new(bytes.Buffer)
287 - err := bootstrapWritePeers(buf, "removed ", v.Peers)
309 + err = bootstrapWritePeers(buf, "removed ", out.Peers)
310 return buf, err
311 },
312 },
313 }
314
315 var bootstrapListCmd = &cmds.Command{
294 - Helptext: cmds.HelpText{
316 + Helptext: cmdkit.HelpText{
317 Tagline: "Show peers in the bootstrap list.",
318 ShortDescription: "Peers are output in the format '<multiaddr>/<peerID>'.",
319 },
@@ -299,19 +321,19 @@ var bootstrapListCmd = &cmds.Command{
321 Run: func(req cmds.Request, res cmds.Response) {
322 r, err := fsrepo.Open(req.InvocContext().ConfigRoot)
323 if err != nil {
302 - res.SetError(err, cmds.ErrNormal)
324 + res.SetError(err, cmdkit.ErrNormal)
325 return
326 }
327 defer r.Close()
328 cfg, err := r.Config()
329 if err != nil {
308 - res.SetError(err, cmds.ErrNormal)
330 + res.SetError(err, cmdkit.ErrNormal)
331 return
332 }
333
334 peers, err := cfg.BootstrapPeers()
335 if err != nil {
314 - res.SetError(err, cmds.ErrNormal)
336 + res.SetError(err, cmdkit.ErrNormal)
337 return
338 }
339 res.SetOutput(&BootstrapOutput{config.BootstrapPeerStrings(peers)})
@@ -323,13 +345,18 @@ var bootstrapListCmd = &cmds.Command{
345 }
346
347 func bootstrapMarshaler(res cmds.Response) (io.Reader, error) {
326 - v, ok := res.Output().(*BootstrapOutput)
348 + v, err := unwrapOutput(res.Output())
349 + if err != nil {
350 + return nil, err
351 + }
352 +
353 + out, ok := v.(*BootstrapOutput)
354 if !ok {
328 - return nil, u.ErrCast()
355 + return nil, e.TypeErr(out, v)
356 }
357
358 buf := new(bytes.Buffer)
332 - err := bootstrapWritePeers(buf, "", v.Peers)
359 + err = bootstrapWritePeers(buf, "", out.Peers)
360 return buf, err
361 }
362
core/commands/cat.go
+57 -19
@@ -1,67 +1,105 @@
1 package commands
2
3 import (
4 + "context"
5 "io"
6 + "os"
7
6 - cmds "github.com/ipfs/go-ipfs/commands"
8 core "github.com/ipfs/go-ipfs/core"
9 coreunix "github.com/ipfs/go-ipfs/core/coreunix"
10
10 - context "context"
11 + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
12 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
13 )
14
15 const progressBarMinSize = 1024 * 1024 * 8 // show progress bar for outputs > 8MiB
16
17 var CatCmd = &cmds.Command{
16 - Helptext: cmds.HelpText{
18 + Helptext: cmdkit.HelpText{
19 Tagline: "Show IPFS object data.",
20 ShortDescription: "Displays the data contained by an IPFS or IPNS object(s) at the given path.",
21 },
22
21 - Arguments: []cmds.Argument{
22 - cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to be outputted.").EnableStdin(),
23 + Arguments: []cmdkit.Argument{
24 + cmdkit.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to be outputted.").EnableStdin(),
25 },
24 - Run: func(req cmds.Request, res cmds.Response) {
26 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
27 node, err := req.InvocContext().GetNode()
28 if err != nil {
27 - res.SetError(err, cmds.ErrNormal)
29 + res.SetError(err, cmdkit.ErrNormal)
30 return
31 }
32
33 if !node.OnlineMode() {
34 if err := node.SetupOfflineRouting(); err != nil {
33 - res.SetError(err, cmds.ErrNormal)
35 + res.SetError(err, cmdkit.ErrNormal)
36 return
37 }
38 }
39
40 readers, length, err := cat(req.Context(), node, req.Arguments())
41 if err != nil {
40 - res.SetError(err, cmds.ErrNormal)
42 + res.SetError(err, cmdkit.ErrNormal)
43 return
44 }
45
46 /*
47 if err := corerepo.ConditionalGC(req.Context(), node, length); err != nil {
46 - res.SetError(err, cmds.ErrNormal)
48 + re.SetError(err, cmdkit.ErrNormal)
49 return
50 }
51 */
52
53 res.SetLength(length)
52 -
54 reader := io.MultiReader(readers...)
54 - res.SetOutput(reader)
55 - },
56 - PostRun: func(req cmds.Request, res cmds.Response) {
57 - if res.Length() < progressBarMinSize {
58 - return
55 +
56 + // Since the reader returns the error that a block is missing, and that error is
57 + // returned from io.Copy inside Emit, we need to take Emit errors and send
58 + // them to the client. Usually we don't do that because it means the connection
59 + // is broken or we supplied an illegal argument etc.
60 + err = res.Emit(reader)
61 + if err != nil {
62 + res.SetError(err, cmdkit.ErrNormal)
63 }
64 + },
65 + PostRun: map[cmds.EncodingType]func(cmds.Request, cmds.ResponseEmitter) cmds.ResponseEmitter{
66 + cmds.CLI: func(req cmds.Request, re cmds.ResponseEmitter) cmds.ResponseEmitter {
67 + reNext, res := cmds.NewChanResponsePair(req)
68 +
69 + go func() {
70 + if res.Length() > 0 && res.Length() < progressBarMinSize {
71 + if err := cmds.Copy(re, res); err != nil {
72 + re.SetError(err, cmdkit.ErrNormal)
73 + }
74 +
75 + return
76 + }
77 +
78 + // Copy closes by itself, so we must not do this before
79 + defer re.Close()
80 + for {
81 + v, err := res.Next()
82 + if !cmds.HandleError(err, res, re) {
83 + break
84 + }
85 +
86 + switch val := v.(type) {
87 + case io.Reader:
88 + bar, reader := progressBarForReader(os.Stderr, val, int64(res.Length()))
89 + bar.Start()
90
61 - bar, reader := progressBarForReader(res.Stderr(), res.Output().(io.Reader), int64(res.Length()))
62 - bar.Start()
91 + err = re.Emit(reader)
92 + if err != nil {
93 + log.Error(err)
94 + }
95 + default:
96 + log.Warningf("cat postrun: received unexpected type %T", val)
97 + }
98 + }
99 + }()
100
64 - res.SetOutput(reader)
101 + return reNext
102 + },
103 },
104 }
105
core/commands/commands.go
+100 -17
@@ -6,18 +6,48 @@
6 package commands
7
8 import (
9 - "bytes"
9 + "fmt"
10 "io"
11 "sort"
12 "strings"
13
14 - cmds "github.com/ipfs/go-ipfs/commands"
14 + oldcmds "github.com/ipfs/go-ipfs/commands"
15 + e "github.com/ipfs/go-ipfs/core/commands/e"
16 +
17 + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
18 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
19 )
20
21 +type commandEncoder struct {
22 + w io.Writer
23 +}
24 +
25 +func (e *commandEncoder) Encode(v interface{}) error {
26 + var (
27 + cmd *Command
28 + ok bool
29 + )
30 +
31 + if cmd, ok = v.(*Command); !ok {
32 + return fmt.Errorf(`core/commands: uenxpected type %T, expected *"core/commands".Command`, v)
33 + }
34 +
35 + for _, s := range cmdPathStrings(cmd, cmd.showOpts) {
36 + _, err := e.w.Write([]byte(s + "\n"))
37 + if err != nil {
38 + return err
39 + }
40 + }
41 +
42 + return nil
43 +}
44 +
45 type Command struct {
46 Name string
47 Subcommands []Command
48 Options []Option
49 +
50 + showOpts bool
51 }
52
53 type Option struct {
@@ -32,26 +62,24 @@ const (
62 // and returns a command that lists the subcommands in that root
63 func CommandsCmd(root *cmds.Command) *cmds.Command {
64 return &cmds.Command{
35 - Helptext: cmds.HelpText{
65 + Helptext: cmdkit.HelpText{
66 Tagline: "List all available commands.",
67 ShortDescription: `Lists all available commands (and subcommands) and exits.`,
68 },
39 - Options: []cmds.Option{
40 - cmds.BoolOption(flagsOptionName, "f", "Show command flags").Default(false),
69 + Options: []cmdkit.Option{
70 + cmdkit.BoolOption(flagsOptionName, "f", "Show command flags").Default(false),
71 },
42 - Run: func(req cmds.Request, res cmds.Response) {
72 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
73 rootCmd := cmd2outputCmd("ipfs", root)
44 - res.SetOutput(&rootCmd)
74 + rootCmd.showOpts, _, _ = req.Option(flagsOptionName).Bool()
75 + err := res.Emit(&rootCmd)
76 + if err != nil {
77 + log.Error(err)
78 + }
79 },
46 - Marshalers: cmds.MarshalerMap{
47 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
48 - v := res.Output().(*Command)
49 - showOptions, _, _ := res.Request().Option(flagsOptionName).Bool()
50 - buf := new(bytes.Buffer)
51 - for _, s := range cmdPathStrings(v, showOptions) {
52 - buf.Write([]byte(s + "\n"))
53 - }
54 - return buf, nil
80 + Encoders: cmds.EncoderMap{
81 + cmds.Text: func(req cmds.Request) func(io.Writer) cmds.Encoder {
82 + return func(w io.Writer) cmds.Encoder { return &commandEncoder{w} }
83 },
84 },
85 Type: Command{},
@@ -66,16 +94,53 @@ func cmd2outputCmd(name string, cmd *cmds.Command) Command {
94
95 output := Command{
96 Name: name,
69 - Subcommands: make([]Command, len(cmd.Subcommands)),
97 + Subcommands: make([]Command, len(cmd.Subcommands)+len(cmd.OldSubcommands)),
98 Options: opts,
99 }
100
101 + // we need to keep track of names because a name *might* be used by both a Subcommand and an OldSubscommand.
102 + names := make(map[string]struct{})
103 +
104 i := 0
105 for name, sub := range cmd.Subcommands {
106 + names[name] = struct{}{}
107 output.Subcommands[i] = cmd2outputCmd(name, sub)
108 i++
109 }
110
111 + for name, sub := range cmd.OldSubcommands {
112 + if _, ok := names[name]; ok {
113 + continue
114 + }
115 +
116 + names[name] = struct{}{}
117 + output.Subcommands[i] = oldCmd2outputCmd(name, sub)
118 + i++
119 + }
120 +
121 + // trucate to the amount of names we actually have
122 + output.Subcommands = output.Subcommands[:len(names)]
123 + return output
124 +}
125 +
126 +func oldCmd2outputCmd(name string, cmd *oldcmds.Command) Command {
127 + opts := make([]Option, len(cmd.Options))
128 + for i, opt := range cmd.Options {
129 + opts[i] = Option{opt.Names()}
130 + }
131 +
132 + output := Command{
133 + Name: name,
134 + Subcommands: make([]Command, len(cmd.Subcommands)),
135 + Options: opts,
136 + }
137 +
138 + i := 0
139 + for name, sub := range cmd.Subcommands {
140 + output.Subcommands[i] = oldCmd2outputCmd(name, sub)
141 + i++
142 + }
143 +
144 return output
145 }
146
@@ -109,3 +174,21 @@ func cmdPathStrings(cmd *Command, showOptions bool) []string {
174 sort.Sort(sort.StringSlice(cmds))
175 return cmds
176 }
177 +
178 +// changes here will also need to be applied at
179 +// - ./dag/dag.go
180 +// - ./object/object.go
181 +// - ./files/files.go
182 +// - ./unixfs/unixfs.go
183 +func unwrapOutput(i interface{}) (interface{}, error) {
184 + var (
185 + ch <-chan interface{}
186 + ok bool
187 + )
188 +
189 + if ch, ok = i.(<-chan interface{}); !ok {
190 + return nil, e.TypeErr(ch, i)
191 + }
192 +
193 + return <-ch, nil
194 +}
core/commands/config.go
+49 -35
@@ -12,11 +12,12 @@ import (
12 "strings"
13
14 cmds "github.com/ipfs/go-ipfs/commands"
15 + e "github.com/ipfs/go-ipfs/core/commands/e"
16 repo "github.com/ipfs/go-ipfs/repo"
17 config "github.com/ipfs/go-ipfs/repo/config"
18 fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
19
19 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
20 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
21 )
22
23 type ConfigField struct {
@@ -25,7 +26,7 @@ type ConfigField struct {
26 }
27
28 var ConfigCmd = &cmds.Command{
28 - Helptext: cmds.HelpText{
29 + Helptext: cmdkit.HelpText{
30 Tagline: "Get and set ipfs config values.",
31 ShortDescription: `
32 'ipfs config' controls configuration variables. It works like 'git config'.
@@ -48,34 +49,41 @@ Set the value of the 'Datastore.Path' key:
49 `,
50 },
51
51 - Arguments: []cmds.Argument{
52 - cmds.StringArg("key", true, false, "The key of the config entry (e.g. \"Addresses.API\")."),
53 - cmds.StringArg("value", false, false, "The value to set the config entry to."),
52 + Arguments: []cmdkit.Argument{
53 + cmdkit.StringArg("key", true, false, "The key of the config entry (e.g. \"Addresses.API\")."),
54 + cmdkit.StringArg("value", false, false, "The value to set the config entry to."),
55 },
55 - Options: []cmds.Option{
56 - cmds.BoolOption("bool", "Set a boolean value.").Default(false),
57 - cmds.BoolOption("json", "Parse stringified JSON.").Default(false),
56 + Options: []cmdkit.Option{
57 + cmdkit.BoolOption("bool", "Set a boolean value.").Default(false),
58 + cmdkit.BoolOption("json", "Parse stringified JSON.").Default(false),
59 },
60 Run: func(req cmds.Request, res cmds.Response) {
61 args := req.Arguments()
62 key := args[0]
63
64 + var output *ConfigField
65 + defer func() {
66 + if output != nil {
67 + res.SetOutput(output)
68 + } else {
69 + res.SetOutput(nil)
70 + }
71 + }()
72 +
73 // This is a temporary fix until we move the private key out of the config file
74 switch strings.ToLower(key) {
75 case "identity", "identity.privkey":
66 - res.SetError(fmt.Errorf("cannot show or change private key through API"), cmds.ErrNormal)
76 + res.SetError(fmt.Errorf("cannot show or change private key through API"), cmdkit.ErrNormal)
77 return
78 default:
79 }
80
81 r, err := fsrepo.Open(req.InvocContext().ConfigRoot)
82 if err != nil {
73 - res.SetError(err, cmds.ErrNormal)
83 + res.SetError(err, cmdkit.ErrNormal)
84 return
85 }
86 defer r.Close()
77 -
78 - var output *ConfigField
87 if len(args) == 2 {
88 value := args[1]
89
@@ -83,7 +91,7 @@ Set the value of the 'Datastore.Path' key:
91 var jsonVal interface{}
92 if err := json.Unmarshal([]byte(value), &jsonVal); err != nil {
93 err = fmt.Errorf("failed to unmarshal json. %s", err)
86 - res.SetError(err, cmds.ErrNormal)
94 + res.SetError(err, cmdkit.ErrNormal)
95 return
96 }
97
@@ -97,10 +105,9 @@ Set the value of the 'Datastore.Path' key:
105 output, err = getConfig(r, key)
106 }
107 if err != nil {
100 - res.SetError(err, cmds.ErrNormal)
108 + res.SetError(err, cmdkit.ErrNormal)
109 return
110 }
103 - res.SetOutput(output)
111 },
112 Marshalers: cmds.MarshalerMap{
113 cmds.Text: func(res cmds.Response) (io.Reader, error) {
@@ -108,14 +115,18 @@ Set the value of the 'Datastore.Path' key:
115 return nil, nil // dont output anything
116 }
117
111 - v := res.Output()
112 - if v == nil {
113 - k := res.Request().Arguments()[0]
114 - return nil, fmt.Errorf("config does not contain key: %s", k)
118 + if res.Error() != nil {
119 + return nil, res.Error()
120 }
121 +
122 + v, err := unwrapOutput(res.Output())
123 + if err != nil {
124 + return nil, err
125 + }
126 +
127 vf, ok := v.(*ConfigField)
128 if !ok {
118 - return nil, u.ErrCast()
129 + return nil, e.TypeErr(vf, v)
130 }
131
132 buf, err := config.HumanOutput(vf.Value)
@@ -135,7 +146,7 @@ Set the value of the 'Datastore.Path' key:
146 }
147
148 var configShowCmd = &cmds.Command{
138 - Helptext: cmds.HelpText{
149 + Helptext: cmdkit.HelpText{
150 Tagline: "Output config file contents.",
151 ShortDescription: `
152 WARNING: Your private key is stored in the config file, and it will be
@@ -146,32 +157,32 @@ included in the output of this command.
157 Run: func(req cmds.Request, res cmds.Response) {
158 fname, err := config.Filename(req.InvocContext().ConfigRoot)
159 if err != nil {
149 - res.SetError(err, cmds.ErrNormal)
160 + res.SetError(err, cmdkit.ErrNormal)
161 return
162 }
163
164 data, err := ioutil.ReadFile(fname)
165 if err != nil {
155 - res.SetError(err, cmds.ErrNormal)
166 + res.SetError(err, cmdkit.ErrNormal)
167 return
168 }
169
170 var cfg map[string]interface{}
171 err = json.Unmarshal(data, &cfg)
172 if err != nil {
162 - res.SetError(err, cmds.ErrNormal)
173 + res.SetError(err, cmdkit.ErrNormal)
174 return
175 }
176
177 err = scrubValue(cfg, []string{config.IdentityTag, config.PrivKeyTag})
178 if err != nil {
168 - res.SetError(err, cmds.ErrNormal)
179 + res.SetError(err, cmdkit.ErrNormal)
180 return
181 }
182
183 output, err := config.HumanOutput(cfg)
184 if err != nil {
174 - res.SetError(err, cmds.ErrNormal)
185 + res.SetError(err, cmdkit.ErrNormal)
186 return
187 }
188
@@ -221,7 +232,7 @@ func scrubValue(m map[string]interface{}, key []string) error {
232 }
233
234 var configEditCmd = &cmds.Command{
224 - Helptext: cmds.HelpText{
235 + Helptext: cmdkit.HelpText{
236 Tagline: "Open the config file for editing in $EDITOR.",
237 ShortDescription: `
238 To use 'ipfs config edit', you must have the $EDITOR environment
@@ -232,19 +243,19 @@ variable set to your preferred text editor.
243 Run: func(req cmds.Request, res cmds.Response) {
244 filename, err := config.Filename(req.InvocContext().ConfigRoot)
245 if err != nil {
235 - res.SetError(err, cmds.ErrNormal)
246 + res.SetError(err, cmdkit.ErrNormal)
247 return
248 }
249
250 err = editConfig(filename)
251 if err != nil {
241 - res.SetError(err, cmds.ErrNormal)
252 + res.SetError(err, cmdkit.ErrNormal)
253 }
254 },
255 }
256
257 var configReplaceCmd = &cmds.Command{
247 - Helptext: cmds.HelpText{
258 + Helptext: cmdkit.HelpText{
259 Tagline: "Replace the config with <file>.",
260 ShortDescription: `
261 Make sure to back up the config file first if necessary, as this operation
@@ -252,27 +263,30 @@ can't be undone.
263 `,
264 },
265
255 - Arguments: []cmds.Argument{
256 - cmds.FileArg("file", true, false, "The file to use as the new config."),
266 + Arguments: []cmdkit.Argument{
267 + cmdkit.FileArg("file", true, false, "The file to use as the new config."),
268 },
269 Run: func(req cmds.Request, res cmds.Response) {
270 + // has to be called
271 + res.SetOutput(nil)
272 +
273 r, err := fsrepo.Open(req.InvocContext().ConfigRoot)
274 if err != nil {
261 - res.SetError(err, cmds.ErrNormal)
275 + res.SetError(err, cmdkit.ErrNormal)
276 return
277 }
278 defer r.Close()
279
280 file, err := req.Files().NextFile()
281 if err != nil {
268 - res.SetError(err, cmds.ErrNormal)
282 + res.SetError(err, cmdkit.ErrNormal)
283 return
284 }
285 defer file.Close()
286
287 err = replaceConfig(r, file)
288 if err != nil {
275 - res.SetError(err, cmds.ErrNormal)
289 + res.SetError(err, cmdkit.ErrNormal)
290 return
291 }
292 },
core/commands/dag/dag.go
+57 -44
@@ -8,18 +8,19 @@ import (
8 "strings"
9
10 cmds "github.com/ipfs/go-ipfs/commands"
11 - files "github.com/ipfs/go-ipfs/commands/files"
11 + e "github.com/ipfs/go-ipfs/core/commands/e"
12 coredag "github.com/ipfs/go-ipfs/core/coredag"
13 path "github.com/ipfs/go-ipfs/path"
14 pin "github.com/ipfs/go-ipfs/pin"
15
16 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
17 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
17 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
18 + files "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files"
19 mh "gx/ipfs/QmU9a9NV9RdPNwZQDYd5uKsm6N6LJLSvLbywDDYFbaaC6P/go-multihash"
20 )
21
22 var DagCmd = &cmds.Command{
22 - Helptext: cmds.HelpText{
23 + Helptext: cmdkit.HelpText{
24 Tagline: "Interact with ipld dag objects.",
25 ShortDescription: `
26 'ipfs dag' is used for creating and manipulating dag objects.
@@ -47,26 +48,26 @@ type ResolveOutput struct {
48 }
49
50 var DagPutCmd = &cmds.Command{
50 - Helptext: cmds.HelpText{
51 + Helptext: cmdkit.HelpText{
52 Tagline: "Add a dag node to ipfs.",
53 ShortDescription: `
54 'ipfs dag put' accepts input from a file or stdin and parses it
55 into an object of the specified format.
56 `,
57 },
57 - Arguments: []cmds.Argument{
58 - cmds.FileArg("object data", true, true, "The object to put").EnableStdin(),
58 + Arguments: []cmdkit.Argument{
59 + cmdkit.FileArg("object data", true, true, "The object to put").EnableStdin(),
60 },
60 - Options: []cmds.Option{
61 - cmds.StringOption("format", "f", "Format that the object will be added as.").Default("cbor"),
62 - cmds.StringOption("input-enc", "Format that the input object will be.").Default("json"),
63 - cmds.BoolOption("pin", "Pin this object when adding.").Default(false),
64 - cmds.StringOption("hash", "Hash function to use").Default(""),
61 + Options: []cmdkit.Option{
62 + cmdkit.StringOption("format", "f", "Format that the object will be added as.").Default("cbor"),
63 + cmdkit.StringOption("input-enc", "Format that the input object will be.").Default("json"),
64 + cmdkit.BoolOption("pin", "Pin this object when adding.").Default(false),
65 + cmdkit.StringOption("hash", "Hash function to use").Default(""),
66 },
67 Run: func(req cmds.Request, res cmds.Response) {
68 n, err := req.InvocContext().GetNode()
69 if err != nil {
69 - res.SetError(err, cmds.ErrNormal)
70 + res.SetError(err, cmdkit.ErrNormal)
71 return
72 }
73
@@ -75,7 +76,7 @@ into an object of the specified format.
76 hash, _, err := req.Option("hash").String()
77 dopin, _, err := req.Option("pin").Bool()
78 if err != nil {
78 - res.SetError(err, cmds.ErrNormal)
79 + res.SetError(err, cmdkit.ErrNormal)
80 return
81 }
82
@@ -87,7 +88,8 @@ into an object of the specified format.
88 var ok bool
89 mhType, ok = mh.Names[hash]
90 if !ok {
90 - res.SetError(fmt.Errorf("%s in not a valid multihash name", hash), cmds.ErrNormal)
91 + res.SetError(fmt.Errorf("%s in not a valid multihash name", hash), cmdkit.ErrNormal)
92 +
93 return
94 }
95 }
@@ -152,7 +154,7 @@ into an object of the specified format.
154 go func() {
155 defer close(outChan)
156 if err := addAllAndPin(req.Files()); err != nil {
155 - res.SetError(err, cmds.ErrNormal)
157 + res.SetError(err, cmdkit.ErrNormal)
158 return
159 }
160 }()
@@ -160,56 +162,48 @@ into an object of the specified format.
162 Type: OutputObject{},
163 Marshalers: cmds.MarshalerMap{
164 cmds.Text: func(res cmds.Response) (io.Reader, error) {
163 - outChan, ok := res.Output().(<-chan interface{})
164 - if !ok {
165 - return nil, u.ErrCast()
165 + v, err := unwrapOutput(res.Output())
166 + if err != nil {
167 + return nil, err
168 }
169
168 - marshal := func(v interface{}) (io.Reader, error) {
169 - obj, ok := v.(*OutputObject)
170 - if !ok {
171 - return nil, u.ErrCast()
172 - }
173 -
174 - return strings.NewReader(obj.Cid.String() + "\n"), nil
170 + oobj, ok := v.(*OutputObject)
171 + if !ok {
172 + return nil, e.TypeErr(oobj, v)
173 }
174
177 - return &cmds.ChannelMarshaler{
178 - Channel: outChan,
179 - Marshaler: marshal,
180 - Res: res,
181 - }, nil
175 + return strings.NewReader(oobj.Cid.String() + "\n"), nil
176 },
177 },
178 }
179
180 var DagGetCmd = &cmds.Command{
187 - Helptext: cmds.HelpText{
181 + Helptext: cmdkit.HelpText{
182 Tagline: "Get a dag node from ipfs.",
183 ShortDescription: `
184 'ipfs dag get' fetches a dag node from ipfs and prints it out in the specifed
185 format.
186 `,
187 },
194 - Arguments: []cmds.Argument{
195 - cmds.StringArg("ref", true, false, "The object to get").EnableStdin(),
188 + Arguments: []cmdkit.Argument{
189 + cmdkit.StringArg("ref", true, false, "The object to get").EnableStdin(),
190 },
191 Run: func(req cmds.Request, res cmds.Response) {
192 n, err := req.InvocContext().GetNode()
193 if err != nil {
200 - res.SetError(err, cmds.ErrNormal)
194 + res.SetError(err, cmdkit.ErrNormal)
195 return
196 }
197
198 p, err := path.ParsePath(req.Arguments()[0])
199 if err != nil {
206 - res.SetError(err, cmds.ErrNormal)
200 + res.SetError(err, cmdkit.ErrNormal)
201 return
202 }
203
204 obj, rem, err := n.Resolver.ResolveToLastNode(req.Context(), p)
205 if err != nil {
212 - res.SetError(err, cmds.ErrNormal)
206 + res.SetError(err, cmdkit.ErrNormal)
207 return
208 }
209
@@ -217,7 +211,7 @@ format.
211 if len(rem) > 0 {
212 final, _, err := obj.Resolve(rem)
213 if err != nil {
220 - res.SetError(err, cmds.ErrNormal)
214 + res.SetError(err, cmdkit.ErrNormal)
215 return
216 }
217 out = final
@@ -229,31 +223,31 @@ format.
223
224 // DagResolveCmd returns address of highest block within a path and a path remainder
225 var DagResolveCmd = &cmds.Command{
232 - Helptext: cmds.HelpText{
226 + Helptext: cmdkit.HelpText{
227 Tagline: "Resolve ipld block",
228 ShortDescription: `
229 'ipfs dag resolve' fetches a dag node from ipfs, prints it's address and remaining path.
230 `,
231 },
238 - Arguments: []cmds.Argument{
239 - cmds.StringArg("ref", true, false, "The path to resolve").EnableStdin(),
232 + Arguments: []cmdkit.Argument{
233 + cmdkit.StringArg("ref", true, false, "The path to resolve").EnableStdin(),
234 },
235 Run: func(req cmds.Request, res cmds.Response) {
236 n, err := req.InvocContext().GetNode()
237 if err != nil {
244 - res.SetError(err, cmds.ErrNormal)
238 + res.SetError(err, cmdkit.ErrNormal)
239 return
240 }
241
242 p, err := path.ParsePath(req.Arguments()[0])
243 if err != nil {
250 - res.SetError(err, cmds.ErrNormal)
244 + res.SetError(err, cmdkit.ErrNormal)
245 return
246 }
247
248 obj, rem, err := n.Resolver.ResolveToLastNode(req.Context(), p)
249 if err != nil {
256 - res.SetError(err, cmds.ErrNormal)
250 + res.SetError(err, cmdkit.ErrNormal)
251 return
252 }
253
@@ -264,7 +258,12 @@ var DagResolveCmd = &cmds.Command{
258 },
259 Marshalers: cmds.MarshalerMap{
260 cmds.Text: func(res cmds.Response) (io.Reader, error) {
267 - output := res.Output().(*ResolveOutput)
261 + v, err := unwrapOutput(res.Output())
262 + if err != nil {
263 + return nil, err
264 + }
265 +
266 + output := v.(*ResolveOutput)
267 buf := new(bytes.Buffer)
268 p := output.Cid.String()
269 if output.RemPath != "" {
@@ -278,3 +277,17 @@ var DagResolveCmd = &cmds.Command{
277 },
278 Type: ResolveOutput{},
279 }
280 +
281 +// copy+pasted from ../commands.go
282 +func unwrapOutput(i interface{}) (interface{}, error) {
283 + var (
284 + ch <-chan interface{}
285 + ok bool
286 + )
287 +
288 + if ch, ok = i.(<-chan interface{}); !ok {
289 + return nil, e.TypeErr(ch, i)
290 + }
291 +
292 + return <-ch, nil
293 +}
core/commands/dht.go
+119 -155
@@ -9,6 +9,7 @@ import (
9 "time"
10
11 cmds "github.com/ipfs/go-ipfs/commands"
12 + e "github.com/ipfs/go-ipfs/core/commands/e"
13 dag "github.com/ipfs/go-ipfs/merkledag"
14 path "github.com/ipfs/go-ipfs/path"
15
@@ -16,7 +17,7 @@ import (
17 routing "gx/ipfs/QmPR2JzfKd9poHx9XBhzoFeBBC31ZM3W5iUPKJZWyaoZZm/go-libp2p-routing"
18 notif "gx/ipfs/QmPR2JzfKd9poHx9XBhzoFeBBC31ZM3W5iUPKJZWyaoZZm/go-libp2p-routing/notifications"
19 pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore"
19 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
20 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
21 b58 "gx/ipfs/QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf/go-base58"
22 ipdht "gx/ipfs/QmWRBYr99v8sjrpbyNWMuGkQekn7b9ELoLSCe8Ny7Nxain/go-libp2p-kad-dht"
23 peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer"
@@ -25,7 +26,7 @@ import (
26 var ErrNotDHT = errors.New("routing service is not a DHT")
27
28 var DhtCmd = &cmds.Command{
28 - Helptext: cmds.HelpText{
29 + Helptext: cmdkit.HelpText{
30 Tagline: "Issue commands directly through the DHT.",
31 ShortDescription: ``,
32 },
@@ -41,27 +42,27 @@ var DhtCmd = &cmds.Command{
42 }
43
44 var queryDhtCmd = &cmds.Command{
44 - Helptext: cmds.HelpText{
45 + Helptext: cmdkit.HelpText{
46 Tagline: "Find the closest Peer IDs to a given Peer ID by querying the DHT.",
47 ShortDescription: "Outputs a list of newline-delimited Peer IDs.",
48 },
49
49 - Arguments: []cmds.Argument{
50 - cmds.StringArg("peerID", true, true, "The peerID to run the query against."),
50 + Arguments: []cmdkit.Argument{
51 + cmdkit.StringArg("peerID", true, true, "The peerID to run the query against."),
52 },
52 - Options: []cmds.Option{
53 - cmds.BoolOption("verbose", "v", "Print extra information.").Default(false),
53 + Options: []cmdkit.Option{
54 + cmdkit.BoolOption("verbose", "v", "Print extra information.").Default(false),
55 },
56 Run: func(req cmds.Request, res cmds.Response) {
57 n, err := req.InvocContext().GetNode()
58 if err != nil {
58 - res.SetError(err, cmds.ErrNormal)
59 + res.SetError(err, cmdkit.ErrNormal)
60 return
61 }
62
63 dht, ok := n.Routing.(*ipdht.IpfsDHT)
64 if !ok {
64 - res.SetError(ErrNotDHT, cmds.ErrNormal)
65 + res.SetError(ErrNotDHT, cmdkit.ErrNormal)
66 return
67 }
68
@@ -72,7 +73,7 @@ var queryDhtCmd = &cmds.Command{
73
74 closestPeers, err := dht.GetClosestPeers(ctx, k)
75 if err != nil {
75 - res.SetError(err, cmds.ErrNormal)
76 + res.SetError(err, cmdkit.ErrNormal)
77 return
78 }
79
@@ -97,12 +98,7 @@ var queryDhtCmd = &cmds.Command{
98 }()
99 },
100 Marshalers: cmds.MarshalerMap{
100 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
101 - outChan, ok := res.Output().(<-chan interface{})
102 - if !ok {
103 - return nil, u.ErrCast()
104 - }
105 -
101 + cmds.Text: func() cmds.Marshaler {
102 pfm := pfuncMap{
103 notif.PeerResponse: func(obj *notif.QueryEvent, out io.Writer, verbose bool) {
104 for _, p := range obj.Responses {
@@ -111,10 +107,15 @@ var queryDhtCmd = &cmds.Command{
107 },
108 }
109
114 - marshal := func(v interface{}) (io.Reader, error) {
110 + return func(res cmds.Response) (io.Reader, error) {
111 + v, err := unwrapOutput(res.Output())
112 + if err != nil {
113 + return nil, err
114 + }
115 +
116 obj, ok := v.(*notif.QueryEvent)
117 if !ok {
117 - return nil, u.ErrCast()
118 + return nil, e.TypeErr(obj, v)
119 }
120
121 verbose, _, _ := res.Request().Option("v").Bool()
@@ -123,50 +124,44 @@ var queryDhtCmd = &cmds.Command{
124 printEvent(obj, buf, verbose, pfm)
125 return buf, nil
126 }
126 -
127 - return &cmds.ChannelMarshaler{
128 - Channel: outChan,
129 - Marshaler: marshal,
130 - Res: res,
131 - }, nil
132 - },
127 + }(),
128 },
129 Type: notif.QueryEvent{},
130 }
131
132 var findProvidersDhtCmd = &cmds.Command{
138 - Helptext: cmds.HelpText{
133 + Helptext: cmdkit.HelpText{
134 Tagline: "Find peers in the DHT that can provide a specific value, given a key.",
135 ShortDescription: "Outputs a list of newline-delimited provider Peer IDs.",
136 },
137
143 - Arguments: []cmds.Argument{
144 - cmds.StringArg("key", true, true, "The key to find providers for."),
138 + Arguments: []cmdkit.Argument{
139 + cmdkit.StringArg("key", true, true, "The key to find providers for."),
140 },
146 - Options: []cmds.Option{
147 - cmds.BoolOption("verbose", "v", "Print extra information.").Default(false),
148 - cmds.IntOption("num-providers", "n", "The number of providers to find.").Default(20),
141 + Options: []cmdkit.Option{
142 + cmdkit.BoolOption("verbose", "v", "Print extra information.").Default(false),
143 + cmdkit.IntOption("num-providers", "n", "The number of providers to find.").Default(20),
144 },
145 Run: func(req cmds.Request, res cmds.Response) {
146 n, err := req.InvocContext().GetNode()
147 if err != nil {
153 - res.SetError(err, cmds.ErrNormal)
148 + res.SetError(err, cmdkit.ErrNormal)
149 return
150 }
151
152 dht, ok := n.Routing.(*ipdht.IpfsDHT)
153 if !ok {
159 - res.SetError(ErrNotDHT, cmds.ErrNormal)
154 + res.SetError(ErrNotDHT, cmdkit.ErrNormal)
155 return
156 }
157
158 numProviders, _, err := res.Request().Option("num-providers").Int()
159 if err != nil {
165 - res.SetError(err, cmds.ErrNormal)
160 + res.SetError(err, cmdkit.ErrNormal)
161 return
162 }
163 if numProviders < 1 {
169 - res.SetError(fmt.Errorf("Number of providers must be greater than 0"), cmds.ErrNormal)
164 + res.SetError(fmt.Errorf("Number of providers must be greater than 0"), cmdkit.ErrNormal)
165 return
166 }
167
@@ -178,7 +173,7 @@ var findProvidersDhtCmd = &cmds.Command{
173
174 c, err := cid.Decode(req.Arguments()[0])
175 if err != nil {
181 - res.SetError(err, cmds.ErrNormal)
176 + res.SetError(err, cmdkit.ErrNormal)
177 return
178 }
179
@@ -202,13 +197,7 @@ var findProvidersDhtCmd = &cmds.Command{
197 }()
198 },
199 Marshalers: cmds.MarshalerMap{
205 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
206 - outChan, ok := res.Output().(<-chan interface{})
207 - if !ok {
208 - return nil, u.ErrCast()
209 - }
210 -
211 - verbose, _, _ := res.Request().Option("v").Bool()
200 + cmds.Text: func() func(cmds.Response) (io.Reader, error) {
201 pfm := pfuncMap{
202 notif.FinalPeer: func(obj *notif.QueryEvent, out io.Writer, verbose bool) {
203 if verbose {
@@ -229,53 +218,53 @@ var findProvidersDhtCmd = &cmds.Command{
218 },
219 }
220
232 - marshal := func(v interface{}) (io.Reader, error) {
221 + return func(res cmds.Response) (io.Reader, error) {
222 + verbose, _, _ := res.Request().Option("v").Bool()
223 + v, err := unwrapOutput(res.Output())
224 + if err != nil {
225 + return nil, err
226 + }
227 +
228 obj, ok := v.(*notif.QueryEvent)
229 if !ok {
235 - return nil, u.ErrCast()
230 + return nil, e.TypeErr(obj, v)
231 }
232
233 buf := new(bytes.Buffer)
234 printEvent(obj, buf, verbose, pfm)
235 return buf, nil
236 }
242 -
243 - return &cmds.ChannelMarshaler{
244 - Channel: outChan,
245 - Marshaler: marshal,
246 - Res: res,
247 - }, nil
248 - },
237 + }(),
238 },
239 Type: notif.QueryEvent{},
240 }
241
242 var provideRefDhtCmd = &cmds.Command{
254 - Helptext: cmds.HelpText{
243 + Helptext: cmdkit.HelpText{
244 Tagline: "Announce to the network that you are providing given values.",
245 },
246
258 - Arguments: []cmds.Argument{
259 - cmds.StringArg("key", true, true, "The key[s] to send provide records for.").EnableStdin(),
247 + Arguments: []cmdkit.Argument{
248 + cmdkit.StringArg("key", true, true, "The key[s] to send provide records for.").EnableStdin(),
249 },
261 - Options: []cmds.Option{
262 - cmds.BoolOption("verbose", "v", "Print extra information.").Default(false),
263 - cmds.BoolOption("recursive", "r", "Recursively provide entire graph.").Default(false),
250 + Options: []cmdkit.Option{
251 + cmdkit.BoolOption("verbose", "v", "Print extra information.").Default(false),
252 + cmdkit.BoolOption("recursive", "r", "Recursively provide entire graph.").Default(false),
253 },
254 Run: func(req cmds.Request, res cmds.Response) {
255 n, err := req.InvocContext().GetNode()
256 if err != nil {
268 - res.SetError(err, cmds.ErrNormal)
257 + res.SetError(err, cmdkit.ErrNormal)
258 return
259 }
260
261 if n.Routing == nil {
273 - res.SetError(errNotOnline, cmds.ErrNormal)
262 + res.SetError(errNotOnline, cmdkit.ErrNormal)
263 return
264 }
265
266 if len(n.PeerHost.Network().Conns()) == 0 {
278 - res.SetError(errors.New("cannot provide, no connected peers"), cmds.ErrNormal)
267 + res.SetError(errors.New("cannot provide, no connected peers"), cmdkit.ErrNormal)
268 return
269 }
270
@@ -285,18 +274,18 @@ var provideRefDhtCmd = &cmds.Command{
274 for _, arg := range req.Arguments() {
275 c, err := cid.Decode(arg)
276 if err != nil {
288 - res.SetError(err, cmds.ErrNormal)
277 + res.SetError(err, cmdkit.ErrNormal)
278 return
279 }
280
281 has, err := n.Blockstore.Has(c)
282 if err != nil {
294 - res.SetError(err, cmds.ErrNormal)
283 + res.SetError(err, cmdkit.ErrNormal)
284 return
285 }
286
287 if !has {
299 - res.SetError(fmt.Errorf("block %s not found locally, cannot provide", c), cmds.ErrNormal)
288 + res.SetError(fmt.Errorf("block %s not found locally, cannot provide", c), cmdkit.ErrNormal)
289 return
290 }
291
@@ -333,13 +322,7 @@ var provideRefDhtCmd = &cmds.Command{
322 }()
323 },
324 Marshalers: cmds.MarshalerMap{
336 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
337 - outChan, ok := res.Output().(<-chan interface{})
338 - if !ok {
339 - return nil, u.ErrCast()
340 - }
341 -
342 - verbose, _, _ := res.Request().Option("v").Bool()
325 + cmds.Text: func() func(res cmds.Response) (io.Reader, error) {
326 pfm := pfuncMap{
327 notif.FinalPeer: func(obj *notif.QueryEvent, out io.Writer, verbose bool) {
328 if verbose {
@@ -348,23 +331,22 @@ var provideRefDhtCmd = &cmds.Command{
331 },
332 }
333
351 - marshal := func(v interface{}) (io.Reader, error) {
334 + return func(res cmds.Response) (io.Reader, error) {
335 + verbose, _, _ := res.Request().Option("v").Bool()
336 + v, err := unwrapOutput(res.Output())
337 + if err != nil {
338 + return nil, err
339 + }
340 obj, ok := v.(*notif.QueryEvent)
341 if !ok {
354 - return nil, u.ErrCast()
342 + return nil, e.TypeErr(obj, v)
343 }
344
345 buf := new(bytes.Buffer)
346 printEvent(obj, buf, verbose, pfm)
347 return buf, nil
348 }
361 -
362 - return &cmds.ChannelMarshaler{
363 - Channel: outChan,
364 - Marshaler: marshal,
365 - Res: res,
366 - }, nil
367 - },
349 + }(),
350 },
351 Type: notif.QueryEvent{},
352 }
@@ -406,33 +388,33 @@ func provideKeysRec(ctx context.Context, r routing.IpfsRouting, dserv dag.DAGSer
388 }
389
390 var findPeerDhtCmd = &cmds.Command{
409 - Helptext: cmds.HelpText{
391 + Helptext: cmdkit.HelpText{
392 Tagline: "Query the DHT for all of the multiaddresses associated with a Peer ID.",
393 ShortDescription: "Outputs a list of newline-delimited multiaddresses.",
394 },
395
414 - Arguments: []cmds.Argument{
415 - cmds.StringArg("peerID", true, true, "The ID of the peer to search for."),
396 + Arguments: []cmdkit.Argument{
397 + cmdkit.StringArg("peerID", true, true, "The ID of the peer to search for."),
398 },
417 - Options: []cmds.Option{
418 - cmds.BoolOption("verbose", "v", "Print extra information.").Default(false),
399 + Options: []cmdkit.Option{
400 + cmdkit.BoolOption("verbose", "v", "Print extra information.").Default(false),
401 },
402 Run: func(req cmds.Request, res cmds.Response) {
403 n, err := req.InvocContext().GetNode()
404 if err != nil {
423 - res.SetError(err, cmds.ErrNormal)
405 + res.SetError(err, cmdkit.ErrNormal)
406 return
407 }
408
409 dht, ok := n.Routing.(*ipdht.IpfsDHT)
410 if !ok {
429 - res.SetError(ErrNotDHT, cmds.ErrNormal)
411 + res.SetError(ErrNotDHT, cmdkit.ErrNormal)
412 return
413 }
414
415 pid, err := peer.IDB58Decode(req.Arguments()[0])
416 if err != nil {
435 - res.SetError(err, cmds.ErrNormal)
417 + res.SetError(err, cmdkit.ErrNormal)
418 return
419 }
420
@@ -467,14 +449,7 @@ var findPeerDhtCmd = &cmds.Command{
449 }()
450 },
451 Marshalers: cmds.MarshalerMap{
470 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
471 - outChan, ok := res.Output().(<-chan interface{})
472 - if !ok {
473 - return nil, u.ErrCast()
474 - }
475 -
476 - verbose, _, _ := res.Request().Option("v").Bool()
477 -
452 + cmds.Text: func() func(cmds.Response) (io.Reader, error) {
453 pfm := pfuncMap{
454 notif.FinalPeer: func(obj *notif.QueryEvent, out io.Writer, verbose bool) {
455 pi := obj.Responses[0]
@@ -483,29 +458,31 @@ var findPeerDhtCmd = &cmds.Command{
458 }
459 },
460 }
486 - marshal := func(v interface{}) (io.Reader, error) {
461 +
462 + return func(res cmds.Response) (io.Reader, error) {
463 + verbose, _, _ := res.Request().Option("v").Bool()
464 + v, err := unwrapOutput(res.Output())
465 + if err != nil {
466 + return nil, err
467 + }
468 +
469 obj, ok := v.(*notif.QueryEvent)
470 if !ok {
489 - return nil, u.ErrCast()
471 + return nil, e.TypeErr(obj, v)
472 }
473
474 buf := new(bytes.Buffer)
475 printEvent(obj, buf, verbose, pfm)
476 +
477 return buf, nil
478 }
496 -
497 - return &cmds.ChannelMarshaler{
498 - Channel: outChan,
499 - Marshaler: marshal,
500 - Res: res,
501 - }, nil
502 - },
479 + }(),
480 },
481 Type: notif.QueryEvent{},
482 }
483
484 var getValueDhtCmd = &cmds.Command{
508 - Helptext: cmds.HelpText{
485 + Helptext: cmdkit.HelpText{
486 Tagline: "Given a key, query the DHT for its best value.",
487 ShortDescription: `
488 Outputs the best value for the given key.
@@ -518,22 +495,22 @@ Different key types can specify other 'best' rules.
495 `,
496 },
497
521 - Arguments: []cmds.Argument{
522 - cmds.StringArg("key", true, true, "The key to find a value for."),
498 + Arguments: []cmdkit.Argument{
499 + cmdkit.StringArg("key", true, true, "The key to find a value for."),
500 },
524 - Options: []cmds.Option{
525 - cmds.BoolOption("verbose", "v", "Print extra information.").Default(false),
501 + Options: []cmdkit.Option{
502 + cmdkit.BoolOption("verbose", "v", "Print extra information.").Default(false),
503 },
504 Run: func(req cmds.Request, res cmds.Response) {
505 n, err := req.InvocContext().GetNode()
506 if err != nil {
530 - res.SetError(err, cmds.ErrNormal)
507 + res.SetError(err, cmdkit.ErrNormal)
508 return
509 }
510
511 dht, ok := n.Routing.(*ipdht.IpfsDHT)
512 if !ok {
536 - res.SetError(ErrNotDHT, cmds.ErrNormal)
513 + res.SetError(ErrNotDHT, cmdkit.ErrNormal)
514 return
515 }
516
@@ -545,7 +522,7 @@ Different key types can specify other 'best' rules.
522
523 dhtkey, err := escapeDhtKey(req.Arguments()[0])
524 if err != nil {
548 - res.SetError(err, cmds.ErrNormal)
525 + res.SetError(err, cmdkit.ErrNormal)
526 return
527 }
528
@@ -573,14 +550,7 @@ Different key types can specify other 'best' rules.
550 }()
551 },
552 Marshalers: cmds.MarshalerMap{
576 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
577 - outChan, ok := res.Output().(<-chan interface{})
578 - if !ok {
579 - return nil, u.ErrCast()
580 - }
581 -
582 - verbose, _, _ := res.Request().Option("v").Bool()
583 -
553 + cmds.Text: func() func(cmds.Response) (io.Reader, error) {
554 pfm := pfuncMap{
555 notif.Value: func(obj *notif.QueryEvent, out io.Writer, verbose bool) {
556 if verbose {
@@ -590,10 +560,17 @@ Different key types can specify other 'best' rules.
560 }
561 },
562 }
593 - marshal := func(v interface{}) (io.Reader, error) {
563 +
564 + return func(res cmds.Response) (io.Reader, error) {
565 + verbose, _, _ := res.Request().Option("v").Bool()
566 + v, err := unwrapOutput(res.Output())
567 + if err != nil {
568 + return nil, err
569 + }
570 +
571 obj, ok := v.(*notif.QueryEvent)
572 if !ok {
596 - return nil, u.ErrCast()
573 + return nil, e.TypeErr(obj, v)
574 }
575
576 buf := new(bytes.Buffer)
@@ -602,19 +579,13 @@ Different key types can specify other 'best' rules.
579
580 return buf, nil
581 }
605 -
606 - return &cmds.ChannelMarshaler{
607 - Channel: outChan,
608 - Marshaler: marshal,
609 - Res: res,
610 - }, nil
611 - },
582 + }(),
583 },
584 Type: notif.QueryEvent{},
585 }
586
587 var putValueDhtCmd = &cmds.Command{
617 - Helptext: cmds.HelpText{
588 + Helptext: cmdkit.HelpText{
589 Tagline: "Write a key/value pair to the DHT.",
590 ShortDescription: `
591 Given a key of the form /foo/bar and a value of any form, this will write that
@@ -635,23 +606,23 @@ NOTE: A value may not exceed 2048 bytes.
606 `,
607 },
608
638 - Arguments: []cmds.Argument{
639 - cmds.StringArg("key", true, false, "The key to store the value at."),
640 - cmds.StringArg("value", true, false, "The value to store.").EnableStdin(),
609 + Arguments: []cmdkit.Argument{
610 + cmdkit.StringArg("key", true, false, "The key to store the value at."),
611 + cmdkit.StringArg("value", true, false, "The value to store.").EnableStdin(),
612 },
642 - Options: []cmds.Option{
643 - cmds.BoolOption("verbose", "v", "Print extra information.").Default(false),
613 + Options: []cmdkit.Option{
614 + cmdkit.BoolOption("verbose", "v", "Print extra information.").Default(false),
615 },
616 Run: func(req cmds.Request, res cmds.Response) {
617 n, err := req.InvocContext().GetNode()
618 if err != nil {
648 - res.SetError(err, cmds.ErrNormal)
619 + res.SetError(err, cmdkit.ErrNormal)
620 return
621 }
622
623 dht, ok := n.Routing.(*ipdht.IpfsDHT)
624 if !ok {
654 - res.SetError(ErrNotDHT, cmds.ErrNormal)
625 + res.SetError(ErrNotDHT, cmdkit.ErrNormal)
626 return
627 }
628
@@ -663,7 +634,7 @@ NOTE: A value may not exceed 2048 bytes.
634
635 key, err := escapeDhtKey(req.Arguments()[0])
636 if err != nil {
666 - res.SetError(err, cmds.ErrNormal)
637 + res.SetError(err, cmdkit.ErrNormal)
638 return
639 }
640
@@ -688,13 +659,7 @@ NOTE: A value may not exceed 2048 bytes.
659 }()
660 },
661 Marshalers: cmds.MarshalerMap{
691 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
692 - outChan, ok := res.Output().(<-chan interface{})
693 - if !ok {
694 - return nil, u.ErrCast()
695 - }
696 -
697 - verbose, _, _ := res.Request().Option("v").Bool()
662 + cmds.Text: func() func(cmds.Response) (io.Reader, error) {
663 pfm := pfuncMap{
664 notif.FinalPeer: func(obj *notif.QueryEvent, out io.Writer, verbose bool) {
665 if verbose {
@@ -706,10 +671,15 @@ NOTE: A value may not exceed 2048 bytes.
671 },
672 }
673
709 - marshal := func(v interface{}) (io.Reader, error) {
674 + return func(res cmds.Response) (io.Reader, error) {
675 + verbose, _, _ := res.Request().Option("v").Bool()
676 + v, err := unwrapOutput(res.Output())
677 + if err != nil {
678 + return nil, err
679 + }
680 obj, ok := v.(*notif.QueryEvent)
681 if !ok {
712 - return nil, u.ErrCast()
682 + return nil, e.TypeErr(obj, v)
683 }
684
685 buf := new(bytes.Buffer)
@@ -717,13 +687,7 @@ NOTE: A value may not exceed 2048 bytes.
687
688 return buf, nil
689 }
720 -
721 - return &cmds.ChannelMarshaler{
722 - Channel: outChan,
723 - Marshaler: marshal,
724 - Res: res,
725 - }, nil
726 - },
690 + }(),
691 },
692 Type: notif.QueryEvent{},
693 }
core/commands/diag.go
+6 -2
@@ -1,9 +1,13 @@
1 package commands
2
3 -import cmds "github.com/ipfs/go-ipfs/commands"
3 +import (
4 + cmds "github.com/ipfs/go-ipfs/commands"
5 +
6 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
7 +)
8
9 var DiagCmd = &cmds.Command{
6 - Helptext: cmds.HelpText{
10 + Helptext: cmdkit.HelpText{
11 Tagline: "Generate diagnostic reports.",
12 },
13
core/commands/dns.go
+17 -10
@@ -5,12 +5,14 @@ import (
5 "strings"
6
7 cmds "github.com/ipfs/go-ipfs/commands"
8 + e "github.com/ipfs/go-ipfs/core/commands/e"
9 namesys "github.com/ipfs/go-ipfs/namesys"
9 - util "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
10 +
11 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
12 )
13
14 var DNSCmd = &cmds.Command{
13 - Helptext: cmds.HelpText{
15 + Helptext: cmdkit.HelpText{
16 Tagline: "Resolve DNS links.",
17 ShortDescription: `
18 Multihashes are hard to remember, but domain names are usually easy to
@@ -43,11 +45,11 @@ The resolver can recursively resolve:
45 `,
46 },
47
46 - Arguments: []cmds.Argument{
47 - cmds.StringArg("domain-name", true, false, "The domain-name name to resolve.").EnableStdin(),
48 + Arguments: []cmdkit.Argument{
49 + cmdkit.StringArg("domain-name", true, false, "The domain-name name to resolve.").EnableStdin(),
50 },
49 - Options: []cmds.Option{
50 - cmds.BoolOption("recursive", "r", "Resolve until the result is not a DNS link.").Default(false),
51 + Options: []cmdkit.Option{
52 + cmdkit.BoolOption("recursive", "r", "Resolve until the result is not a DNS link.").Default(false),
53 },
54 Run: func(req cmds.Request, res cmds.Response) {
55
@@ -61,20 +63,25 @@ The resolver can recursively resolve:
63 }
64 output, err := resolver.ResolveN(req.Context(), name, depth)
65 if err == namesys.ErrResolveFailed {
64 - res.SetError(err, cmds.ErrNotFound)
66 + res.SetError(err, cmdkit.ErrNotFound)
67 return
68 }
69 if err != nil {
68 - res.SetError(err, cmds.ErrNormal)
70 + res.SetError(err, cmdkit.ErrNormal)
71 return
72 }
73 res.SetOutput(&ResolvedPath{output})
74 },
75 Marshalers: cmds.MarshalerMap{
76 cmds.Text: func(res cmds.Response) (io.Reader, error) {
75 - output, ok := res.Output().(*ResolvedPath)
77 + v, err := unwrapOutput(res.Output())
78 + if err != nil {
79 + return nil, err
80 + }
81 +
82 + output, ok := v.(*ResolvedPath)
83 if !ok {
77 - return nil, util.ErrCast()
84 + return nil, e.TypeErr(output, v)
85 }
86 return strings.NewReader(output.Path.String() + "\n"), nil
87 },
core/commands/e/error.go new
+30
@@ -0,0 +1,30 @@
1 +package e
2 +
3 +import (
4 + "fmt"
5 + "runtime/debug"
6 +)
7 +
8 +// TypeErr returns an error with a string that explains what error was expected and what was received.
9 +func TypeErr(expected, actual interface{}) error {
10 + return fmt.Errorf("expected type %T, got %T", expected, actual)
11 +}
12 +
13 +// compile time type check that HandlerError is an error
14 +var _ error = New(nil)
15 +
16 +// HandlerError is adds a stack trace to an error
17 +type HandlerError struct {
18 + Err error
19 + Stack []byte
20 +}
21 +
22 +// Error makes HandlerError implement error
23 +func (err HandlerError) Error() string {
24 + return fmt.Sprintf("%s in:\n%s", err.Err.Error(), err.Stack)
25 +}
26 +
27 +// New returns a new HandlerError
28 +func New(err error) HandlerError {
29 + return HandlerError{Err: err, Stack: debug.Stack()}
30 +}
core/commands/external.go
+7 -5
@@ -9,12 +9,14 @@ import (
9 "strings"
10
11 cmds "github.com/ipfs/go-ipfs/commands"
12 +
13 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
14 )
15
16 func ExternalBinary() *cmds.Command {
17 return &cmds.Command{
16 - Arguments: []cmds.Argument{
17 - cmds.StringArg("args", false, true, "Arguments for subcommand."),
18 + Arguments: []cmdkit.Argument{
19 + cmdkit.StringArg("args", false, true, "Arguments for subcommand."),
20 },
21 External: true,
22 Run: func(req cmds.Request, res cmds.Response) {
@@ -33,7 +35,7 @@ func ExternalBinary() *cmds.Command {
35 }
36 }
37
36 - res.SetError(fmt.Errorf("%s not installed.", binname), cmds.ErrNormal)
38 + res.SetError(fmt.Errorf("%s not installed", binname), cmdkit.ErrNormal)
39 return
40 }
41
@@ -59,7 +61,7 @@ func ExternalBinary() *cmds.Command {
61
62 err = cmd.Start()
63 if err != nil {
62 - res.SetError(fmt.Errorf("failed to start subcommand: %s", err), cmds.ErrNormal)
64 + res.SetError(fmt.Errorf("failed to start subcommand: %s", err), cmdkit.ErrNormal)
65 return
66 }
67
@@ -68,7 +70,7 @@ func ExternalBinary() *cmds.Command {
70 go func() {
71 err = cmd.Wait()
72 if err != nil {
71 - res.SetError(err, cmds.ErrNormal)
73 + res.SetError(err, cmdkit.ErrNormal)
74 }
75
76 w.Close()
core/commands/files/files.go
+169 -129
@@ -12,11 +12,13 @@ import (
12
13 cmds "github.com/ipfs/go-ipfs/commands"
14 core "github.com/ipfs/go-ipfs/core"
15 + e "github.com/ipfs/go-ipfs/core/commands/e"
16 dag "github.com/ipfs/go-ipfs/merkledag"
17 mfs "github.com/ipfs/go-ipfs/mfs"
18 path "github.com/ipfs/go-ipfs/path"
19 ft "github.com/ipfs/go-ipfs/unixfs"
20 uio "github.com/ipfs/go-ipfs/unixfs/io"
21 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
22
23 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
24 node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format"
@@ -27,7 +29,7 @@ import (
29 var log = logging.Logger("cmds/files")
30
31 var FilesCmd = &cmds.Command{
30 - Helptext: cmds.HelpText{
32 + Helptext: cmdkit.HelpText{
33 Tagline: "Interact with unixfs files.",
34 ShortDescription: `
35 Files is an API for manipulating IPFS objects as if they were a unix
@@ -43,8 +45,8 @@ applies to running 'ipfs repo gc' concurrently with '--flush=false'
45 operations.
46 `,
47 },
46 - Options: []cmds.Option{
47 - cmds.BoolOption("f", "flush", "Flush target and ancestors after write.").Default(true),
48 + Options: []cmdkit.Option{
49 + cmdkit.BoolOption("f", "flush", "Flush target and ancestors after write.").Default(true),
50 },
51 Subcommands: map[string]*cmds.Command{
52 "read": FilesReadCmd,
@@ -60,58 +62,58 @@ operations.
62 },
63 }
64
63 -var cidVersionOption = cmds.IntOption("cid-version", "cid-ver", "Cid version to use. (experimental)")
64 -var hashOption = cmds.StringOption("hash", "Hash function to use. Will set Cid version to 1 if used. (experimental)")
65 +var cidVersionOption = cmdkit.IntOption("cid-version", "cid-ver", "Cid version to use. (experimental)")
66 +var hashOption = cmdkit.StringOption("hash", "Hash function to use. Will set Cid version to 1 if used. (experimental)")
67
68 var formatError = errors.New("Format was set by multiple options. Only one format option is allowed")
69
70 var FilesStatCmd = &cmds.Command{
69 - Helptext: cmds.HelpText{
71 + Helptext: cmdkit.HelpText{
72 Tagline: "Display file status.",
73 },
74
73 - Arguments: []cmds.Argument{
74 - cmds.StringArg("path", true, false, "Path to node to stat."),
75 + Arguments: []cmdkit.Argument{
76 + cmdkit.StringArg("path", true, false, "Path to node to stat."),
77 },
76 - Options: []cmds.Option{
77 - cmds.StringOption("format", "Print statistics in given format. Allowed tokens: "+
78 + Options: []cmdkit.Option{
79 + cmdkit.StringOption("format", "Print statistics in given format. Allowed tokens: "+
80 "<hash> <size> <cumulsize> <type> <childs>. Conflicts with other format options.").Default(
81 `<hash>
82 Size: <size>
83 CumulativeSize: <cumulsize>
84 ChildBlocks: <childs>
85 Type: <type>`),
84 - cmds.BoolOption("hash", "Print only hash. Implies '--format=<hash>'. Conflicts with other format options.").Default(false),
85 - cmds.BoolOption("size", "Print only size. Implies '--format=<cumulsize>'. Conflicts with other format options.").Default(false),
86 + cmdkit.BoolOption("hash", "Print only hash. Implies '--format=<hash>'. Conflicts with other format options.").Default(false),
87 + cmdkit.BoolOption("size", "Print only size. Implies '--format=<cumulsize>'. Conflicts with other format options.").Default(false),
88 },
89 Run: func(req cmds.Request, res cmds.Response) {
90
91 _, err := statGetFormatOptions(req)
92 if err != nil {
91 - res.SetError(err, cmds.ErrClient)
93 + res.SetError(err, cmdkit.ErrClient)
94 }
95
96 node, err := req.InvocContext().GetNode()
97 if err != nil {
96 - res.SetError(err, cmds.ErrNormal)
98 + res.SetError(err, cmdkit.ErrNormal)
99 return
100 }
101
102 path, err := checkPath(req.Arguments()[0])
103 if err != nil {
102 - res.SetError(err, cmds.ErrNormal)
104 + res.SetError(err, cmdkit.ErrNormal)
105 return
106 }
107
108 fsn, err := mfs.Lookup(node.FilesRoot, path)
109 if err != nil {
108 - res.SetError(err, cmds.ErrNormal)
110 + res.SetError(err, cmdkit.ErrNormal)
111 return
112 }
113
114 o, err := statNode(node.DAG, fsn)
115 if err != nil {
114 - res.SetError(err, cmds.ErrNormal)
116 + res.SetError(err, cmdkit.ErrNormal)
117 return
118 }
119
@@ -119,8 +121,15 @@ Type: <type>`),
121 },
122 Marshalers: cmds.MarshalerMap{
123 cmds.Text: func(res cmds.Response) (io.Reader, error) {
124 + v, err := unwrapOutput(res.Output())
125 + if err != nil {
126 + return nil, err
127 + }
128
123 - out := res.Output().(*Object)
129 + out, ok := v.(*Object)
130 + if !ok {
131 + return nil, e.TypeErr(out, v)
132 + }
133 buf := new(bytes.Buffer)
134
135 s, _ := statGetFormatOptions(res.Request())
@@ -211,17 +220,17 @@ func statNode(ds dag.DAGService, fsn mfs.FSNode) (*Object, error) {
220 }
221
222 var FilesCpCmd = &cmds.Command{
214 - Helptext: cmds.HelpText{
223 + Helptext: cmdkit.HelpText{
224 Tagline: "Copy files into mfs.",
225 },
217 - Arguments: []cmds.Argument{
218 - cmds.StringArg("source", true, false, "Source object to copy."),
219 - cmds.StringArg("dest", true, false, "Destination to copy object to."),
226 + Arguments: []cmdkit.Argument{
227 + cmdkit.StringArg("source", true, false, "Source object to copy."),
228 + cmdkit.StringArg("dest", true, false, "Destination to copy object to."),
229 },
230 Run: func(req cmds.Request, res cmds.Response) {
231 node, err := req.InvocContext().GetNode()
232 if err != nil {
224 - res.SetError(err, cmds.ErrNormal)
233 + res.SetError(err, cmdkit.ErrNormal)
234 return
235 }
236
@@ -229,14 +238,14 @@ var FilesCpCmd = &cmds.Command{
238
239 src, err := checkPath(req.Arguments()[0])
240 if err != nil {
232 - res.SetError(err, cmds.ErrNormal)
241 + res.SetError(err, cmdkit.ErrNormal)
242 return
243 }
244 src = strings.TrimRight(src, "/")
245
246 dst, err := checkPath(req.Arguments()[1])
247 if err != nil {
239 - res.SetError(err, cmds.ErrNormal)
248 + res.SetError(err, cmdkit.ErrNormal)
249 return
250 }
251
@@ -246,23 +255,25 @@ var FilesCpCmd = &cmds.Command{
255
256 nd, err := getNodeFromPath(req.Context(), node, src)
257 if err != nil {
249 - res.SetError(err, cmds.ErrNormal)
258 + res.SetError(err, cmdkit.ErrNormal)
259 return
260 }
261
262 err = mfs.PutNode(node.FilesRoot, dst, nd)
263 if err != nil {
255 - res.SetError(err, cmds.ErrNormal)
264 + res.SetError(err, cmdkit.ErrNormal)
265 return
266 }
267
268 if flush {
269 err := mfs.FlushPath(node.FilesRoot, dst)
270 if err != nil {
262 - res.SetError(err, cmds.ErrNormal)
271 + res.SetError(err, cmdkit.ErrNormal)
272 return
273 }
274 }
275 +
276 + res.SetOutput(nil)
277 },
278 }
279
@@ -303,7 +314,7 @@ type FilesLsOutput struct {
314 }
315
316 var FilesLsCmd = &cmds.Command{
306 - Helptext: cmds.HelpText{
317 + Helptext: cmdkit.HelpText{
318 Tagline: "List directories in the local mutable namespace.",
319 ShortDescription: `
320 List directories in the local mutable namespace.
@@ -323,11 +334,11 @@ Examples:
334 bar
335 `,
336 },
326 - Arguments: []cmds.Argument{
327 - cmds.StringArg("path", false, false, "Path to show listing for. Defaults to '/'."),
337 + Arguments: []cmdkit.Argument{
338 + cmdkit.StringArg("path", false, false, "Path to show listing for. Defaults to '/'."),
339 },
329 - Options: []cmds.Option{
330 - cmds.BoolOption("l", "Use long listing format."),
340 + Options: []cmdkit.Option{
341 + cmdkit.BoolOption("l", "Use long listing format."),
342 },
343 Run: func(req cmds.Request, res cmds.Response) {
344 var arg string
@@ -340,19 +351,19 @@ Examples:
351
352 path, err := checkPath(arg)
353 if err != nil {
343 - res.SetError(err, cmds.ErrNormal)
354 + res.SetError(err, cmdkit.ErrNormal)
355 return
356 }
357
358 nd, err := req.InvocContext().GetNode()
359 if err != nil {
349 - res.SetError(err, cmds.ErrNormal)
360 + res.SetError(err, cmdkit.ErrNormal)
361 return
362 }
363
364 fsn, err := mfs.Lookup(nd.FilesRoot, path)
365 if err != nil {
355 - res.SetError(err, cmds.ErrNormal)
366 + res.SetError(err, cmdkit.ErrNormal)
367 return
368 }
369
@@ -364,7 +375,7 @@ Examples:
375 var output []mfs.NodeListing
376 names, err := fsn.ListNames(req.Context())
377 if err != nil {
367 - res.SetError(err, cmds.ErrNormal)
378 + res.SetError(err, cmdkit.ErrNormal)
379 return
380 }
381
@@ -377,7 +388,7 @@ Examples:
388 } else {
389 listing, err := fsn.List(req.Context())
390 if err != nil {
380 - res.SetError(err, cmds.ErrNormal)
391 + res.SetError(err, cmdkit.ErrNormal)
392 return
393 }
394 res.SetOutput(&FilesLsOutput{listing})
@@ -389,12 +400,21 @@ Examples:
400 res.SetOutput(out)
401 return
402 default:
392 - res.SetError(errors.New("unrecognized type"), cmds.ErrNormal)
403 + res.SetError(errors.New("unrecognized type"), cmdkit.ErrNormal)
404 }
405 },
406 Marshalers: cmds.MarshalerMap{
407 cmds.Text: func(res cmds.Response) (io.Reader, error) {
397 - out := res.Output().(*FilesLsOutput)
408 + v, err := unwrapOutput(res.Output())
409 + if err != nil {
410 + return nil, err
411 + }
412 +
413 + out, ok := v.(*FilesLsOutput)
414 + if !ok {
415 + return nil, e.TypeErr(out, v)
416 + }
417 +
418 buf := new(bytes.Buffer)
419 long, _, _ := res.Request().Option("l").Bool()
420
@@ -412,7 +432,7 @@ Examples:
432 }
433
434 var FilesReadCmd = &cmds.Command{
415 - Helptext: cmds.HelpText{
435 + Helptext: cmdkit.HelpText{
436 Tagline: "Read a file in a given mfs.",
437 ShortDescription: `
438 Read a specified number of bytes from a file at a given offset. By default,
@@ -425,41 +445,41 @@ Examples:
445 `,
446 },
447
428 - Arguments: []cmds.Argument{
429 - cmds.StringArg("path", true, false, "Path to file to be read."),
448 + Arguments: []cmdkit.Argument{
449 + cmdkit.StringArg("path", true, false, "Path to file to be read."),
450 },
431 - Options: []cmds.Option{
432 - cmds.IntOption("offset", "o", "Byte offset to begin reading from."),
433 - cmds.IntOption("count", "n", "Maximum number of bytes to read."),
451 + Options: []cmdkit.Option{
452 + cmdkit.IntOption("offset", "o", "Byte offset to begin reading from."),
453 + cmdkit.IntOption("count", "n", "Maximum number of bytes to read."),
454 },
455 Run: func(req cmds.Request, res cmds.Response) {
456 n, err := req.InvocContext().GetNode()
457 if err != nil {
438 - res.SetError(err, cmds.ErrNormal)
458 + res.SetError(err, cmdkit.ErrNormal)
459 return
460 }
461
462 path, err := checkPath(req.Arguments()[0])
463 if err != nil {
444 - res.SetError(err, cmds.ErrNormal)
464 + res.SetError(err, cmdkit.ErrNormal)
465 return
466 }
467
468 fsn, err := mfs.Lookup(n.FilesRoot, path)
469 if err != nil {
450 - res.SetError(err, cmds.ErrNormal)
470 + res.SetError(err, cmdkit.ErrNormal)
471 return
472 }
473
474 fi, ok := fsn.(*mfs.File)
475 if !ok {
456 - res.SetError(fmt.Errorf("%s was not a file.", path), cmds.ErrNormal)
476 + res.SetError(fmt.Errorf("%s was not a file.", path), cmdkit.ErrNormal)
477 return
478 }
479
480 rfd, err := fi.Open(mfs.OpenReadOnly, false)
481 if err != nil {
462 - res.SetError(err, cmds.ErrNormal)
482 + res.SetError(err, cmdkit.ErrNormal)
483 return
484 }
485
@@ -467,40 +487,40 @@ Examples:
487
488 offset, _, err := req.Option("offset").Int()
489 if err != nil {
470 - res.SetError(err, cmds.ErrNormal)
490 + res.SetError(err, cmdkit.ErrNormal)
491 return
492 }
493 if offset < 0 {
474 - res.SetError(fmt.Errorf("Cannot specify negative offset."), cmds.ErrNormal)
494 + res.SetError(fmt.Errorf("Cannot specify negative offset."), cmdkit.ErrNormal)
495 return
496 }
497
498 filen, err := rfd.Size()
499 if err != nil {
480 - res.SetError(err, cmds.ErrNormal)
500 + res.SetError(err, cmdkit.ErrNormal)
501 return
502 }
503
504 if int64(offset) > filen {
485 - res.SetError(fmt.Errorf("Offset was past end of file (%d > %d).", offset, filen), cmds.ErrNormal)
505 + res.SetError(fmt.Errorf("Offset was past end of file (%d > %d).", offset, filen), cmdkit.ErrNormal)
506 return
507 }
508
509 _, err = rfd.Seek(int64(offset), io.SeekStart)
510 if err != nil {
491 - res.SetError(err, cmds.ErrNormal)
511 + res.SetError(err, cmdkit.ErrNormal)
512 return
513 }
514
515 var r io.Reader = &contextReaderWrapper{R: rfd, ctx: req.Context()}
516 count, found, err := req.Option("count").Int()
517 if err != nil {
498 - res.SetError(err, cmds.ErrNormal)
518 + res.SetError(err, cmdkit.ErrNormal)
519 return
520 }
521 if found {
522 if count < 0 {
503 - res.SetError(fmt.Errorf("Cannot specify negative 'count'."), cmds.ErrNormal)
523 + res.SetError(fmt.Errorf("Cannot specify negative 'count'."), cmdkit.ErrNormal)
524 return
525 }
526 r = io.LimitReader(r, int64(count))
@@ -524,7 +544,7 @@ func (crw *contextReaderWrapper) Read(b []byte) (int, error) {
544 }
545
546 var FilesMvCmd = &cmds.Command{
527 - Helptext: cmds.HelpText{
547 + Helptext: cmdkit.HelpText{
548 Tagline: "Move files.",
549 ShortDescription: `
550 Move files around. Just like traditional unix mv.
@@ -536,38 +556,40 @@ Example:
556 `,
557 },
558
539 - Arguments: []cmds.Argument{
540 - cmds.StringArg("source", true, false, "Source file to move."),
541 - cmds.StringArg("dest", true, false, "Destination path for file to be moved to."),
559 + Arguments: []cmdkit.Argument{
560 + cmdkit.StringArg("source", true, false, "Source file to move."),
561 + cmdkit.StringArg("dest", true, false, "Destination path for file to be moved to."),
562 },
563 Run: func(req cmds.Request, res cmds.Response) {
564 n, err := req.InvocContext().GetNode()
565 if err != nil {
546 - res.SetError(err, cmds.ErrNormal)
566 + res.SetError(err, cmdkit.ErrNormal)
567 return
568 }
569
570 src, err := checkPath(req.Arguments()[0])
571 if err != nil {
552 - res.SetError(err, cmds.ErrNormal)
572 + res.SetError(err, cmdkit.ErrNormal)
573 return
574 }
575 dst, err := checkPath(req.Arguments()[1])
576 if err != nil {
557 - res.SetError(err, cmds.ErrNormal)
577 + res.SetError(err, cmdkit.ErrNormal)
578 return
579 }
580
581 err = mfs.Mv(n.FilesRoot, src, dst)
582 if err != nil {
563 - res.SetError(err, cmds.ErrNormal)
583 + res.SetError(err, cmdkit.ErrNormal)
584 return
585 }
586 +
587 + res.SetOutput(nil)
588 },
589 }
590
591 var FilesWriteCmd = &cmds.Command{
570 - Helptext: cmds.HelpText{
592 + Helptext: cmdkit.HelpText{
593 Tagline: "Write to a mutable file in a given filesystem.",
594 ShortDescription: `
595 Write data to a file in a given filesystem. This command allows you to specify
@@ -600,23 +622,23 @@ the tree has been flushed. This can be accomplished by running 'ipfs files
622 stat' on the file or any of its ancestors.
623 `,
624 },
603 - Arguments: []cmds.Argument{
604 - cmds.StringArg("path", true, false, "Path to write to."),
605 - cmds.FileArg("data", true, false, "Data to write.").EnableStdin(),
625 + Arguments: []cmdkit.Argument{
626 + cmdkit.StringArg("path", true, false, "Path to write to."),
627 + cmdkit.FileArg("data", true, false, "Data to write.").EnableStdin(),
628 },
607 - Options: []cmds.Option{
608 - cmds.IntOption("offset", "o", "Byte offset to begin writing at."),
609 - cmds.BoolOption("create", "e", "Create the file if it does not exist."),
610 - cmds.BoolOption("truncate", "t", "Truncate the file to size zero before writing."),
611 - cmds.IntOption("count", "n", "Maximum number of bytes to read."),
612 - cmds.BoolOption("raw-leaves", "Use raw blocks for newly created leaf nodes. (experimental)"),
629 + Options: []cmdkit.Option{
630 + cmdkit.IntOption("offset", "o", "Byte offset to begin writing at."),
631 + cmdkit.BoolOption("create", "e", "Create the file if it does not exist."),
632 + cmdkit.BoolOption("truncate", "t", "Truncate the file to size zero before writing."),
633 + cmdkit.IntOption("count", "n", "Maximum number of bytes to read."),
634 + cmdkit.BoolOption("raw-leaves", "Use raw blocks for newly created leaf nodes. (experimental)"),
635 cidVersionOption,
636 hashOption,
637 },
638 Run: func(req cmds.Request, res cmds.Response) {
639 path, err := checkPath(req.Arguments()[0])
640 if err != nil {
619 - res.SetError(err, cmds.ErrNormal)
641 + res.SetError(err, cmdkit.ErrNormal)
642 return
643 }
644
@@ -627,29 +649,29 @@ stat' on the file or any of its ancestors.
649
650 prefix, err := getPrefix(req)
651 if err != nil {
630 - res.SetError(err, cmds.ErrNormal)
652 + res.SetError(err, cmdkit.ErrNormal)
653 return
654 }
655
656 nd, err := req.InvocContext().GetNode()
657 if err != nil {
636 - res.SetError(err, cmds.ErrNormal)
658 + res.SetError(err, cmdkit.ErrNormal)
659 return
660 }
661
662 offset, _, err := req.Option("offset").Int()
663 if err != nil {
642 - res.SetError(err, cmds.ErrNormal)
664 + res.SetError(err, cmdkit.ErrNormal)
665 return
666 }
667 if offset < 0 {
646 - res.SetError(fmt.Errorf("cannot have negative write offset"), cmds.ErrNormal)
668 + res.SetError(fmt.Errorf("cannot have negative write offset"), cmdkit.ErrNormal)
669 return
670 }
671
672 fi, err := getFileHandle(nd.FilesRoot, path, create, prefix)
673 if err != nil {
652 - res.SetError(err, cmds.ErrNormal)
674 + res.SetError(err, cmdkit.ErrNormal)
675 return
676 }
677 if rawLeavesDef {
@@ -658,44 +680,44 @@ stat' on the file or any of its ancestors.
680
681 wfd, err := fi.Open(mfs.OpenWriteOnly, flush)
682 if err != nil {
661 - res.SetError(err, cmds.ErrNormal)
683 + res.SetError(err, cmdkit.ErrNormal)
684 return
685 }
686
687 defer func() {
688 err := wfd.Close()
689 if err != nil {
668 - res.SetError(err, cmds.ErrNormal)
690 + res.SetError(err, cmdkit.ErrNormal)
691 }
692 }()
693
694 if trunc {
695 if err := wfd.Truncate(0); err != nil {
674 - res.SetError(err, cmds.ErrNormal)
696 + res.SetError(err, cmdkit.ErrNormal)
697 return
698 }
699 }
700
701 count, countfound, err := req.Option("count").Int()
702 if err != nil {
681 - res.SetError(err, cmds.ErrNormal)
703 + res.SetError(err, cmdkit.ErrNormal)
704 return
705 }
706 if countfound && count < 0 {
685 - res.SetError(fmt.Errorf("cannot have negative byte count"), cmds.ErrNormal)
707 + res.SetError(fmt.Errorf("cannot have negative byte count"), cmdkit.ErrNormal)
708 return
709 }
710
711 _, err = wfd.Seek(int64(offset), io.SeekStart)
712 if err != nil {
713 log.Error("seekfail: ", err)
692 - res.SetError(err, cmds.ErrNormal)
714 + res.SetError(err, cmdkit.ErrNormal)
715 return
716 }
717
718 input, err := req.Files().NextFile()
719 if err != nil {
698 - res.SetError(err, cmds.ErrNormal)
720 + res.SetError(err, cmdkit.ErrNormal)
721 return
722 }
723
@@ -704,18 +726,18 @@ stat' on the file or any of its ancestors.
726 r = io.LimitReader(r, int64(count))
727 }
728
707 - n, err := io.Copy(wfd, r)
729 + _, err = io.Copy(wfd, r)
730 if err != nil {
709 - res.SetError(err, cmds.ErrNormal)
731 + res.SetError(err, cmdkit.ErrNormal)
732 return
733 }
734
713 - log.Debugf("wrote %d bytes to %s", n, path)
735 + res.SetOutput(nil)
736 },
737 }
738
739 var FilesMkdirCmd = &cmds.Command{
718 - Helptext: cmds.HelpText{
740 + Helptext: cmdkit.HelpText{
741 Tagline: "Make directories.",
742 ShortDescription: `
743 Create the directory if it does not already exist.
@@ -732,25 +754,25 @@ Examples:
754 `,
755 },
756
735 - Arguments: []cmds.Argument{
736 - cmds.StringArg("path", true, false, "Path to dir to make."),
757 + Arguments: []cmdkit.Argument{
758 + cmdkit.StringArg("path", true, false, "Path to dir to make."),
759 },
738 - Options: []cmds.Option{
739 - cmds.BoolOption("parents", "p", "No error if existing, make parent directories as needed."),
760 + Options: []cmdkit.Option{
761 + cmdkit.BoolOption("parents", "p", "No error if existing, make parent directories as needed."),
762 cidVersionOption,
763 hashOption,
764 },
765 Run: func(req cmds.Request, res cmds.Response) {
766 n, err := req.InvocContext().GetNode()
767 if err != nil {
746 - res.SetError(err, cmds.ErrNormal)
768 + res.SetError(err, cmdkit.ErrNormal)
769 return
770 }
771
772 dashp, _, _ := req.Option("parents").Bool()
773 dirtomake, err := checkPath(req.Arguments()[0])
774 if err != nil {
753 - res.SetError(err, cmds.ErrNormal)
775 + res.SetError(err, cmdkit.ErrNormal)
776 return
777 }
778
@@ -758,7 +780,7 @@ Examples:
780
781 prefix, err := getPrefix(req)
782 if err != nil {
761 - res.SetError(err, cmds.ErrNormal)
783 + res.SetError(err, cmdkit.ErrNormal)
784 return
785 }
786 root := n.FilesRoot
@@ -769,28 +791,28 @@ Examples:
791 Prefix: prefix,
792 })
793 if err != nil {
772 - res.SetError(err, cmds.ErrNormal)
794 + res.SetError(err, cmdkit.ErrNormal)
795 return
796 }
775 -
797 + res.SetOutput(nil)
798 },
799 }
800
801 var FilesFlushCmd = &cmds.Command{
780 - Helptext: cmds.HelpText{
802 + Helptext: cmdkit.HelpText{
803 Tagline: "Flush a given path's data to disk.",
804 ShortDescription: `
805 Flush a given path to disk. This is only useful when other commands
806 are run with the '--flush=false'.
807 `,
808 },
787 - Arguments: []cmds.Argument{
788 - cmds.StringArg("path", false, false, "Path to flush. Default: '/'."),
809 + Arguments: []cmdkit.Argument{
810 + cmdkit.StringArg("path", false, false, "Path to flush. Default: '/'."),
811 },
812 Run: func(req cmds.Request, res cmds.Response) {
813 nd, err := req.InvocContext().GetNode()
814 if err != nil {
793 - res.SetError(err, cmds.ErrNormal)
815 + res.SetError(err, cmdkit.ErrNormal)
816 return
817 }
818
@@ -801,30 +823,32 @@ are run with the '--flush=false'.
823
824 err = mfs.FlushPath(nd.FilesRoot, path)
825 if err != nil {
804 - res.SetError(err, cmds.ErrNormal)
826 + res.SetError(err, cmdkit.ErrNormal)
827 return
828 }
829 +
830 + res.SetOutput(nil)
831 },
832 }
833
834 var FilesChcidCmd = &cmds.Command{
811 - Helptext: cmds.HelpText{
835 + Helptext: cmdkit.HelpText{
836 Tagline: "Change the cid version or hash function of the root node of a given path.",
837 ShortDescription: `
838 Change the cid version or hash function of the root node of a given path.
839 `,
840 },
817 - Arguments: []cmds.Argument{
818 - cmds.StringArg("path", false, false, "Path to change. Default: '/'."),
841 + Arguments: []cmdkit.Argument{
842 + cmdkit.StringArg("path", false, false, "Path to change. Default: '/'."),
843 },
820 - Options: []cmds.Option{
844 + Options: []cmdkit.Option{
845 cidVersionOption,
846 hashOption,
847 },
848 Run: func(req cmds.Request, res cmds.Response) {
849 nd, err := req.InvocContext().GetNode()
850 if err != nil {
827 - res.SetError(err, cmds.ErrNormal)
851 + res.SetError(err, cmdkit.ErrNormal)
852 return
853 }
854
@@ -837,13 +861,13 @@ Change the cid version or hash function of the root node of a given path.
861
862 prefix, err := getPrefix(req)
863 if err != nil {
840 - res.SetError(err, cmds.ErrNormal)
864 + res.SetError(err, cmdkit.ErrNormal)
865 return
866 }
867
868 err = updatePath(nd.FilesRoot, path, prefix, flush)
869 if err != nil {
846 - res.SetError(err, cmds.ErrNormal)
870 + res.SetError(err, cmdkit.ErrNormal)
871 return
872 }
873 },
@@ -874,7 +898,7 @@ func updatePath(rt *mfs.Root, pth string, prefix *cid.Prefix, flush bool) error
898 }
899
900 var FilesRmCmd = &cmds.Command{
877 - Helptext: cmds.HelpText{
901 + Helptext: cmdkit.HelpText{
902 Tagline: "Remove a file.",
903 ShortDescription: `
904 Remove files or directories.
@@ -888,27 +912,29 @@ Remove files or directories.
912 `,
913 },
914
891 - Arguments: []cmds.Argument{
892 - cmds.StringArg("path", true, true, "File to remove."),
915 + Arguments: []cmdkit.Argument{
916 + cmdkit.StringArg("path", true, true, "File to remove."),
917 },
894 - Options: []cmds.Option{
895 - cmds.BoolOption("recursive", "r", "Recursively remove directories."),
918 + Options: []cmdkit.Option{
919 + cmdkit.BoolOption("recursive", "r", "Recursively remove directories."),
920 },
921 Run: func(req cmds.Request, res cmds.Response) {
922 + defer res.SetOutput(nil)
923 +
924 nd, err := req.InvocContext().GetNode()
925 if err != nil {
900 - res.SetError(err, cmds.ErrNormal)
926 + res.SetError(err, cmdkit.ErrNormal)
927 return
928 }
929
930 path, err := checkPath(req.Arguments()[0])
931 if err != nil {
906 - res.SetError(err, cmds.ErrNormal)
932 + res.SetError(err, cmdkit.ErrNormal)
933 return
934 }
935
936 if path == "/" {
911 - res.SetError(fmt.Errorf("cannot delete root"), cmds.ErrNormal)
937 + res.SetError(fmt.Errorf("cannot delete root"), cmdkit.ErrNormal)
938 return
939 }
940
@@ -920,13 +946,13 @@ Remove files or directories.
946 dir, name := gopath.Split(path)
947 parent, err := mfs.Lookup(nd.FilesRoot, dir)
948 if err != nil {
923 - res.SetError(fmt.Errorf("parent lookup: %s", err), cmds.ErrNormal)
949 + res.SetError(fmt.Errorf("parent lookup: %s", err), cmdkit.ErrNormal)
950 return
951 }
952
953 pdir, ok := parent.(*mfs.Directory)
954 if !ok {
929 - res.SetError(fmt.Errorf("No such file or directory: %s", path), cmds.ErrNormal)
955 + res.SetError(fmt.Errorf("No such file or directory: %s", path), cmdkit.ErrNormal)
956 return
957 }
958
@@ -937,7 +963,7 @@ Remove files or directories.
963 if success {
964 err := pdir.Flush()
965 if err != nil {
940 - res.SetError(err, cmds.ErrNormal)
966 + res.SetError(err, cmdkit.ErrNormal)
967 return
968 }
969 }
@@ -947,7 +973,7 @@ Remove files or directories.
973 if dashr {
974 err := pdir.Unlink(name)
975 if err != nil {
950 - res.SetError(err, cmds.ErrNormal)
976 + res.SetError(err, cmdkit.ErrNormal)
977 return
978 }
979
@@ -957,18 +983,18 @@ Remove files or directories.
983
984 childi, err := pdir.Child(name)
985 if err != nil {
960 - res.SetError(err, cmds.ErrNormal)
986 + res.SetError(err, cmdkit.ErrNormal)
987 return
988 }
989
990 switch childi.(type) {
991 case *mfs.Directory:
966 - res.SetError(fmt.Errorf("%s is a directory, use -r to remove directories", path), cmds.ErrNormal)
992 + res.SetError(fmt.Errorf("%s is a directory, use -r to remove directories", path), cmdkit.ErrNormal)
993 return
994 default:
995 err := pdir.Unlink(name)
996 if err != nil {
971 - res.SetError(err, cmds.ErrNormal)
997 + res.SetError(err, cmdkit.ErrNormal)
998 return
999 }
1000
@@ -1074,3 +1100,17 @@ func checkPath(p string) (string, error) {
1100 }
1101 return cleaned, nil
1102 }
1103 +
1104 +// copy+pasted from ../commands.go
1105 +func unwrapOutput(i interface{}) (interface{}, error) {
1106 + var (
1107 + ch <-chan interface{}
1108 + ok bool
1109 + )
1110 +
1111 + if ch, ok = i.(<-chan interface{}); !ok {
1112 + return nil, e.TypeErr(ch, i)
1113 + }
1114 +
1115 + return <-ch, nil
1116 +}
core/commands/filestore.go
+110 -71
@@ -4,27 +4,38 @@ import (
4 "context"
5 "fmt"
6 "io"
7 + "os"
8
8 - cmds "github.com/ipfs/go-ipfs/commands"
9 + oldCmds "github.com/ipfs/go-ipfs/commands"
10 "github.com/ipfs/go-ipfs/core"
11 + e "github.com/ipfs/go-ipfs/core/commands/e"
12 "github.com/ipfs/go-ipfs/filestore"
13 +
14 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
12 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
15 + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
16 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
17 )
18
19 var FileStoreCmd = &cmds.Command{
16 - Helptext: cmds.HelpText{
20 + Helptext: cmdkit.HelpText{
21 Tagline: "Interact with filestore objects.",
22 },
23 Subcommands: map[string]*cmds.Command{
20 - "ls": lsFileStore,
24 + "ls": lsFileStore,
25 + },
26 + OldSubcommands: map[string]*oldCmds.Command{
27 "verify": verifyFileStore,
28 "dups": dupsFileStore,
29 },
30 }
31
32 +type lsEncoder struct {
33 + errors bool
34 + w io.Writer
35 +}
36 +
37 var lsFileStore = &cmds.Command{
27 - Helptext: cmds.HelpText{
38 + Helptext: cmdkit.HelpText{
39 Tagline: "List objects in filestore.",
40 LongDescription: `
41 List objects in the filestore.
@@ -37,62 +48,84 @@ The output is:
48 <hash> <size> <path> <offset>
49 `,
50 },
40 - Arguments: []cmds.Argument{
41 - cmds.StringArg("obj", false, true, "Cid of objects to list."),
51 + Arguments: []cmdkit.Argument{
52 + cmdkit.StringArg("obj", false, true, "Cid of objects to list."),
53 },
43 - Options: []cmds.Option{
44 - cmds.BoolOption("file-order", "sort the results based on the path of the backing file"),
54 + Options: []cmdkit.Option{
55 + cmdkit.BoolOption("file-order", "sort the results based on the path of the backing file"),
56 },
46 - Run: func(req cmds.Request, res cmds.Response) {
47 - _, fs, err := getFilestore(req)
57 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
58 + _, fs, err := getFilestore(req.InvocContext())
59 if err != nil {
49 - res.SetError(err, cmds.ErrNormal)
60 + res.SetError(err, cmdkit.ErrNormal)
61 return
62 }
63 args := req.Arguments()
64 if len(args) > 0 {
54 - out := perKeyActionToChan(args, func(c *cid.Cid) *filestore.ListRes {
65 + out := perKeyActionToChan(req.Context(), args, func(c *cid.Cid) *filestore.ListRes {
66 return filestore.List(fs, c)
56 - }, req.Context())
57 - res.SetOutput(out)
67 + })
68 +
69 + err = res.Emit(out)
70 + if err != nil {
71 + log.Error(err)
72 + }
73 } else {
74 fileOrder, _, _ := req.Option("file-order").Bool()
75 next, err := filestore.ListAll(fs, fileOrder)
76 if err != nil {
62 - res.SetError(err, cmds.ErrNormal)
77 + res.SetError(err, cmdkit.ErrNormal)
78 return
79 }
65 - out := listResToChan(next, req.Context())
66 - res.SetOutput(out)
80 +
81 + out := listResToChan(req.Context(), next)
82 + err = res.Emit(out)
83 + if err != nil {
84 + log.Error(err)
85 + }
86 }
87 },
69 - Marshalers: cmds.MarshalerMap{
70 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
71 - outChan, ok := res.Output().(<-chan interface{})
72 - if !ok {
73 - return nil, u.ErrCast()
74 - }
75 - errors := false
76 - for r0 := range outChan {
77 - r := r0.(*filestore.ListRes)
78 - if r.ErrorMsg != "" {
79 - errors = true
80 - fmt.Fprintf(res.Stderr(), "%s\n", r.ErrorMsg)
81 - } else {
82 - fmt.Fprintf(res.Stdout(), "%s\n", r.FormatLong())
88 + PostRun: cmds.PostRunMap{
89 + cmds.CLI: func(req cmds.Request, re cmds.ResponseEmitter) cmds.ResponseEmitter {
90 + reNext, res := cmds.NewChanResponsePair(req)
91 +
92 + go func() {
93 + defer re.Close()
94 +
95 + var errors bool
96 + for {
97 + v, err := res.Next()
98 + if !cmds.HandleError(err, res, re) {
99 + break
100 + }
101 +
102 + r, ok := v.(*filestore.ListRes)
103 + if !ok {
104 + log.Error(e.New(e.TypeErr(r, v)))
105 + return
106 + }
107 +
108 + if r.ErrorMsg != "" {
109 + errors = true
110 + fmt.Fprintf(os.Stderr, "%s\n", r.ErrorMsg)
111 + } else {
112 + fmt.Fprintf(os.Stdout, "%s\n", r.FormatLong())
113 + }
114 }
84 - }
85 - if errors {
86 - return nil, fmt.Errorf("errors while displaying some entries")
87 - }
88 - return nil, nil
115 +
116 + if errors {
117 + re.SetError("errors while displaying some entries", cmdkit.ErrNormal)
118 + }
119 + }()
120 +
121 + return reNext
122 },
123 },
124 Type: filestore.ListRes{},
125 }
126
94 -var verifyFileStore = &cmds.Command{
95 - Helptext: cmds.HelpText{
127 +var verifyFileStore = &oldCmds.Command{
128 + Helptext: cmdkit.HelpText{
129 Tagline: "Verify objects in filestore.",
130 LongDescription: `
131 Verify objects in the filestore.
@@ -115,68 +148,70 @@ ERROR: internal error, most likely due to a corrupt database
148 For ERROR entries the error will also be printed to stderr.
149 `,
150 },
118 - Arguments: []cmds.Argument{
119 - cmds.StringArg("obj", false, true, "Cid of objects to verify."),
151 + Arguments: []cmdkit.Argument{
152 + cmdkit.StringArg("obj", false, true, "Cid of objects to verify."),
153 },
121 - Options: []cmds.Option{
122 - cmds.BoolOption("file-order", "verify the objects based on the order of the backing file"),
154 + Options: []cmdkit.Option{
155 + cmdkit.BoolOption("file-order", "verify the objects based on the order of the backing file"),
156 },
124 - Run: func(req cmds.Request, res cmds.Response) {
125 - _, fs, err := getFilestore(req)
157 + Run: func(req oldCmds.Request, res oldCmds.Response) {
158 + _, fs, err := getFilestore(req.InvocContext())
159 if err != nil {
127 - res.SetError(err, cmds.ErrNormal)
160 + res.SetError(err, cmdkit.ErrNormal)
161 return
162 }
163 args := req.Arguments()
164 if len(args) > 0 {
132 - out := perKeyActionToChan(args, func(c *cid.Cid) *filestore.ListRes {
165 + out := perKeyActionToChan(req.Context(), args, func(c *cid.Cid) *filestore.ListRes {
166 return filestore.Verify(fs, c)
134 - }, req.Context())
167 + })
168 res.SetOutput(out)
169 } else {
170 fileOrder, _, _ := req.Option("file-order").Bool()
171 next, err := filestore.VerifyAll(fs, fileOrder)
172 if err != nil {
140 - res.SetError(err, cmds.ErrNormal)
173 + res.SetError(err, cmdkit.ErrNormal)
174 return
175 }
143 - out := listResToChan(next, req.Context())
176 + out := listResToChan(req.Context(), next)
177 res.SetOutput(out)
178 }
179 },
147 - Marshalers: cmds.MarshalerMap{
148 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
149 - outChan, ok := res.Output().(<-chan interface{})
180 + Marshalers: oldCmds.MarshalerMap{
181 + oldCmds.Text: func(res oldCmds.Response) (io.Reader, error) {
182 + v, err := unwrapOutput(res.Output())
183 + if err != nil {
184 + return nil, err
185 + }
186 +
187 + r, ok := v.(*filestore.ListRes)
188 if !ok {
151 - return nil, u.ErrCast()
189 + return nil, e.TypeErr(r, v)
190 }
153 - res.SetOutput(nil)
154 - for r0 := range outChan {
155 - r := r0.(*filestore.ListRes)
156 - if r.Status == filestore.StatusOtherError {
157 - fmt.Fprintf(res.Stderr(), "%s\n", r.ErrorMsg)
158 - }
159 - fmt.Fprintf(res.Stdout(), "%s %s\n", r.Status.Format(), r.FormatLong())
191 +
192 + if r.Status == filestore.StatusOtherError {
193 + fmt.Fprintf(res.Stderr(), "%s\n", r.ErrorMsg)
194 }
195 + fmt.Fprintf(res.Stdout(), "%s %s\n", r.Status.Format(), r.FormatLong())
196 return nil, nil
197 },
198 },
199 Type: filestore.ListRes{},
200 }
201
167 -var dupsFileStore = &cmds.Command{
168 - Helptext: cmds.HelpText{
202 +var dupsFileStore = &oldCmds.Command{
203 + Helptext: cmdkit.HelpText{
204 Tagline: "List blocks that are both in the filestore and standard block storage.",
205 },
171 - Run: func(req cmds.Request, res cmds.Response) {
172 - _, fs, err := getFilestore(req)
206 + Run: func(req oldCmds.Request, res oldCmds.Response) {
207 + _, fs, err := getFilestore(req.InvocContext())
208 if err != nil {
174 - res.SetError(err, cmds.ErrNormal)
209 + res.SetError(err, cmdkit.ErrNormal)
210 return
211 }
212 ch, err := fs.FileManager().AllKeysChan(req.Context())
213 if err != nil {
179 - res.SetError(err, cmds.ErrNormal)
214 + res.SetError(err, cmdkit.ErrNormal)
215 return
216 }
217
@@ -201,8 +236,12 @@ var dupsFileStore = &cmds.Command{
236 Type: RefWrapper{},
237 }
238
204 -func getFilestore(req cmds.Request) (*core.IpfsNode, *filestore.Filestore, error) {
205 - n, err := req.InvocContext().GetNode()
239 +type getNoder interface {
240 + GetNode() (*core.IpfsNode, error)
241 +}
242 +
243 +func getFilestore(g getNoder) (*core.IpfsNode, *filestore.Filestore, error) {
244 + n, err := g.GetNode()
245 if err != nil {
246 return nil, nil, err
247 }
@@ -213,7 +252,7 @@ func getFilestore(req cmds.Request) (*core.IpfsNode, *filestore.Filestore, error
252 return n, fs, err
253 }
254
216 -func listResToChan(next func() *filestore.ListRes, ctx context.Context) <-chan interface{} {
255 +func listResToChan(ctx context.Context, next func() *filestore.ListRes) <-chan interface{} {
256 out := make(chan interface{}, 128)
257 go func() {
258 defer close(out)
@@ -232,7 +271,7 @@ func listResToChan(next func() *filestore.ListRes, ctx context.Context) <-chan i
271 return out
272 }
273
235 -func perKeyActionToChan(args []string, action func(*cid.Cid) *filestore.ListRes, ctx context.Context) <-chan interface{} {
274 +func perKeyActionToChan(ctx context.Context, args []string, action func(*cid.Cid) *filestore.ListRes) <-chan interface{} {
275 out := make(chan interface{}, 128)
276 go func() {
277 defer close(out)
core/commands/get.go
+71 -54
@@ -9,20 +9,22 @@ import (
9 gopath "path"
10 "strings"
11
12 - "gx/ipfs/QmeWjRodbcZFKe5tMN7poEx3izym6osrLSnTLf9UjJZBbs/pb"
13 -
14 - cmds "github.com/ipfs/go-ipfs/commands"
12 core "github.com/ipfs/go-ipfs/core"
13 + e "github.com/ipfs/go-ipfs/core/commands/e"
14 dag "github.com/ipfs/go-ipfs/merkledag"
15 path "github.com/ipfs/go-ipfs/path"
16 tar "github.com/ipfs/go-ipfs/thirdparty/tar"
17 uarchive "github.com/ipfs/go-ipfs/unixfs/archive"
18 +
19 + "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
20 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
21 + "gx/ipfs/QmeWjRodbcZFKe5tMN7poEx3izym6osrLSnTLf9UjJZBbs/pb"
22 )
23
24 var ErrInvalidCompressionLevel = errors.New("Compression level must be between 1 and 9")
25
26 var GetCmd = &cmds.Command{
25 - Helptext: cmds.HelpText{
27 + Helptext: cmdkit.HelpText{
28 Tagline: "Download IPFS objects.",
29 ShortDescription: `
30 Stores to disk the data contained an IPFS or IPNS object(s) at the given path.
@@ -37,41 +39,40 @@ may also specify the level of compression by specifying '-l=<1-9>'.
39 `,
40 },
41
40 - Arguments: []cmds.Argument{
41 - cmds.StringArg("ipfs-path", true, false, "The path to the IPFS object(s) to be outputted.").EnableStdin(),
42 + Arguments: []cmdkit.Argument{
43 + cmdkit.StringArg("ipfs-path", true, false, "The path to the IPFS object(s) to be outputted.").EnableStdin(),
44 },
43 - Options: []cmds.Option{
44 - cmds.StringOption("output", "o", "The path where the output should be stored."),
45 - cmds.BoolOption("archive", "a", "Output a TAR archive.").Default(false),
46 - cmds.BoolOption("compress", "C", "Compress the output with GZIP compression.").Default(false),
47 - cmds.IntOption("compression-level", "l", "The level of compression (1-9).").Default(-1),
45 + Options: []cmdkit.Option{
46 + cmdkit.StringOption("output", "o", "The path where the output should be stored."),
47 + cmdkit.BoolOption("archive", "a", "Output a TAR archive.").Default(false),
48 + cmdkit.BoolOption("compress", "C", "Compress the output with GZIP compression.").Default(false),
49 + cmdkit.IntOption("compression-level", "l", "The level of compression (1-9).").Default(-1),
50 },
51 PreRun: func(req cmds.Request) error {
52 _, err := getCompressOptions(req)
53 return err
54 },
53 - Run: func(req cmds.Request, res cmds.Response) {
55 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
56 if len(req.Arguments()) == 0 {
55 - res.SetError(errors.New("not enough arugments provided"), cmds.ErrClient)
57 + res.SetError(errors.New("not enough arugments provided"), cmdkit.ErrClient)
58 return
59 }
58 -
60 cmplvl, err := getCompressOptions(req)
61 if err != nil {
61 - res.SetError(err, cmds.ErrClient)
62 + res.SetError(err, cmdkit.ErrNormal)
63 return
64 }
65
66 node, err := req.InvocContext().GetNode()
67 if err != nil {
67 - res.SetError(err, cmds.ErrNormal)
68 + res.SetError(err, cmdkit.ErrNormal)
69 return
70 }
71 p := path.Path(req.Arguments()[0])
72 ctx := req.Context()
73 dn, err := core.Resolve(ctx, node.Namesys, node.Resolver, p)
74 if err != nil {
74 - res.SetError(err, cmds.ErrNormal)
75 + res.SetError(err, cmdkit.ErrNormal)
76 return
77 }
78
@@ -79,7 +80,7 @@ may also specify the level of compression by specifying '-l=<1-9>'.
80 case *dag.ProtoNode:
81 size, err := dn.Size()
82 if err != nil {
82 - res.SetError(err, cmds.ErrNormal)
83 + res.SetError(err, cmdkit.ErrNormal)
84 return
85 }
86
@@ -87,51 +88,67 @@ may also specify the level of compression by specifying '-l=<1-9>'.
88 case *dag.RawNode:
89 res.SetLength(uint64(len(dn.RawData())))
90 default:
90 - res.SetError(fmt.Errorf("'ipfs get' only supports unixfs nodes"), cmds.ErrNormal)
91 + res.SetError(err, cmdkit.ErrNormal)
92 return
93 }
94
95 archive, _, _ := req.Option("archive").Bool()
96 reader, err := uarchive.DagArchive(ctx, dn, p.String(), node.DAG, archive, cmplvl)
97 if err != nil {
97 - res.SetError(err, cmds.ErrNormal)
98 - return
99 - }
100 - res.SetOutput(reader)
101 - },
102 - PostRun: func(req cmds.Request, res cmds.Response) {
103 - if res.Output() == nil {
104 - return
105 - }
106 - outReader := res.Output().(io.Reader)
107 - res.SetOutput(nil)
108 -
109 - outPath, _, _ := req.Option("output").String()
110 - if len(outPath) == 0 {
111 - _, outPath = gopath.Split(req.Arguments()[0])
112 - outPath = gopath.Clean(outPath)
113 - }
114 -
115 - cmplvl, err := getCompressOptions(req)
116 - if err != nil {
117 - res.SetError(err, cmds.ErrClient)
98 + res.SetError(err, cmdkit.ErrNormal)
99 return
100 }
101
121 - archive, _, _ := req.Option("archive").Bool()
122 -
123 - gw := getWriter{
124 - Out: os.Stdout,
125 - Err: os.Stderr,
126 - Archive: archive,
127 - Compression: cmplvl,
128 - Size: int64(res.Length()),
129 - }
130 -
131 - if err := gw.Write(outReader, outPath); err != nil {
132 - res.SetError(err, cmds.ErrNormal)
133 - return
134 - }
102 + res.Emit(reader)
103 + },
104 + PostRun: map[cmds.EncodingType]func(cmds.Request, cmds.ResponseEmitter) cmds.ResponseEmitter{
105 + cmds.CLI: func(req cmds.Request, re cmds.ResponseEmitter) cmds.ResponseEmitter {
106 + reNext, res := cmds.NewChanResponsePair(req)
107 +
108 + go func() {
109 + defer re.Close()
110 +
111 + v, err := res.Next()
112 + if err != nil {
113 + log.Error(e.New(err))
114 + return
115 + }
116 +
117 + outReader, ok := v.(io.Reader)
118 + if !ok {
119 + log.Error(e.New(e.TypeErr(outReader, v)))
120 + return
121 + }
122 +
123 + outPath, _, _ := req.Option("output").String()
124 + if len(outPath) == 0 {
125 + _, outPath = gopath.Split(req.Arguments()[0])
126 + outPath = gopath.Clean(outPath)
127 + }
128 +
129 + cmplvl, err := getCompressOptions(req)
130 + if err != nil {
131 + re.SetError(err, cmdkit.ErrNormal)
132 + return
133 + }
134 +
135 + archive, _, _ := req.Option("archive").Bool()
136 +
137 + gw := getWriter{
138 + Out: os.Stdout,
139 + Err: os.Stderr,
140 + Archive: archive,
141 + Compression: cmplvl,
142 + Size: int64(res.Length()),
143 + }
144 +
145 + if err := gw.Write(outReader, outPath); err != nil {
146 + re.SetError(err, cmdkit.ErrNormal)
147 + }
148 + }()
149 +
150 + return reNext
151 + },
152 },
153 }
154
core/commands/helptext_test.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "strings"
5 "testing"
6
7 - cmds "github.com/ipfs/go-ipfs/commands"
7 + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
8 )
9
10 func checkHelptextRecursive(t *testing.T, name []string, c *cmds.Command) {
core/commands/id.go
+23 -18
@@ -8,14 +8,14 @@ import (
8 "io"
9 "strings"
10
11 - b58 "gx/ipfs/QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf/go-base58"
12 -
11 cmds "github.com/ipfs/go-ipfs/commands"
12 core "github.com/ipfs/go-ipfs/core"
15 - kb "gx/ipfs/QmSAFA8v42u4gpJNy1tb7vW3JiiXiaYDC2b845c2RnNSJL/go-libp2p-kbucket"
13 + e "github.com/ipfs/go-ipfs/core/commands/e"
14
15 pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore"
18 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
16 + kb "gx/ipfs/QmSAFA8v42u4gpJNy1tb7vW3JiiXiaYDC2b845c2RnNSJL/go-libp2p-kbucket"
17 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
18 + b58 "gx/ipfs/QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf/go-base58"
19 "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer"
20 ic "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto"
21 identify "gx/ipfs/QmefgzMbKZYsmHFkLqxgaTBG9ypeEjrdWRD5WXH4j1cWDL/go-libp2p/p2p/protocol/identify"
@@ -39,7 +39,7 @@ type IdOutput struct {
39 }
40
41 var IDCmd = &cmds.Command{
42 - Helptext: cmds.HelpText{
42 + Helptext: cmdkit.HelpText{
43 Tagline: "Show ipfs node id info.",
44 ShortDescription: `
45 Prints out information about the specified peer.
@@ -57,16 +57,16 @@ EXAMPLE:
57 ipfs id Qmece2RkXhsKe5CRooNisBTh4SK119KrXXGmoK6V3kb8aH -f="<addrs>\n"
58 `,
59 },
60 - Arguments: []cmds.Argument{
61 - cmds.StringArg("peerid", false, false, "Peer.ID of node to look up."),
60 + Arguments: []cmdkit.Argument{
61 + cmdkit.StringArg("peerid", false, false, "Peer.ID of node to look up."),
62 },
63 - Options: []cmds.Option{
64 - cmds.StringOption("format", "f", "Optional output format."),
63 + Options: []cmdkit.Option{
64 + cmdkit.StringOption("format", "f", "Optional output format."),
65 },
66 Run: func(req cmds.Request, res cmds.Response) {
67 node, err := req.InvocContext().GetNode()
68 if err != nil {
69 - res.SetError(err, cmds.ErrNormal)
69 + res.SetError(err, cmdkit.ErrNormal)
70 return
71 }
72
@@ -74,7 +74,7 @@ EXAMPLE:
74 if len(req.Arguments()) > 0 {
75 id = peer.ID(b58.Decode(req.Arguments()[0]))
76 if len(id) == 0 {
77 - res.SetError(cmds.ClientError("Invalid peer id"), cmds.ErrClient)
77 + res.SetError(cmds.ClientError("Invalid peer id"), cmdkit.ErrClient)
78 return
79 }
80 } else {
@@ -84,7 +84,7 @@ EXAMPLE:
84 if id == node.Identity {
85 output, err := printSelf(node)
86 if err != nil {
87 - res.SetError(err, cmds.ErrNormal)
87 + res.SetError(err, cmdkit.ErrNormal)
88 return
89 }
90 res.SetOutput(output)
@@ -93,32 +93,37 @@ EXAMPLE:
93
94 // TODO handle offline mode with polymorphism instead of conditionals
95 if !node.OnlineMode() {
96 - res.SetError(errors.New(offlineIdErrorMessage), cmds.ErrClient)
96 + res.SetError(errors.New(offlineIdErrorMessage), cmdkit.ErrClient)
97 return
98 }
99
100 p, err := node.Routing.FindPeer(req.Context(), id)
101 if err == kb.ErrLookupFailure {
102 - res.SetError(errors.New(offlineIdErrorMessage), cmds.ErrClient)
102 + res.SetError(errors.New(offlineIdErrorMessage), cmdkit.ErrClient)
103 return
104 }
105 if err != nil {
106 - res.SetError(err, cmds.ErrNormal)
106 + res.SetError(err, cmdkit.ErrNormal)
107 return
108 }
109
110 output, err := printPeer(node.Peerstore, p.ID)
111 if err != nil {
112 - res.SetError(err, cmds.ErrNormal)
112 + res.SetError(err, cmdkit.ErrNormal)
113 return
114 }
115 res.SetOutput(output)
116 },
117 Marshalers: cmds.MarshalerMap{
118 cmds.Text: func(res cmds.Response) (io.Reader, error) {
119 - val, ok := res.Output().(*IdOutput)
119 + v, err := unwrapOutput(res.Output())
120 + if err != nil {
121 + return nil, err
122 + }
123 +
124 + val, ok := v.(*IdOutput)
125 if !ok {
121 - return nil, u.ErrCast()
126 + return nil, e.TypeErr(val, v)
127 }
128
129 format, found, err := res.Request().Option("format").String()
core/commands/ipns.go
+21 -14
@@ -6,13 +6,15 @@ import (
6 "strings"
7
8 cmds "github.com/ipfs/go-ipfs/commands"
9 + e "github.com/ipfs/go-ipfs/core/commands/e"
10 namesys "github.com/ipfs/go-ipfs/namesys"
11 offline "github.com/ipfs/go-ipfs/routing/offline"
11 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
12 +
13 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
14 )
15
16 var IpnsCmd = &cmds.Command{
15 - Helptext: cmds.HelpText{
17 + Helptext: cmdkit.HelpText{
18 Tagline: "Resolve IPNS names.",
19 ShortDescription: `
20 IPNS is a PKI namespace, where names are the hashes of public keys, and
@@ -49,25 +51,25 @@ Resolve the value of a dnslink:
51 `,
52 },
53
52 - Arguments: []cmds.Argument{
53 - cmds.StringArg("name", false, false, "The IPNS name to resolve. Defaults to your node's peerID."),
54 + Arguments: []cmdkit.Argument{
55 + cmdkit.StringArg("name", false, false, "The IPNS name to resolve. Defaults to your node's peerID."),
56 },
55 - Options: []cmds.Option{
56 - cmds.BoolOption("recursive", "r", "Resolve until the result is not an IPNS name.").Default(false),
57 - cmds.BoolOption("nocache", "n", "Do not use cached entries.").Default(false),
57 + Options: []cmdkit.Option{
58 + cmdkit.BoolOption("recursive", "r", "Resolve until the result is not an IPNS name.").Default(false),
59 + cmdkit.BoolOption("nocache", "n", "Do not use cached entries.").Default(false),
60 },
61 Run: func(req cmds.Request, res cmds.Response) {
62
63 n, err := req.InvocContext().GetNode()
64 if err != nil {
63 - res.SetError(err, cmds.ErrNormal)
65 + res.SetError(err, cmdkit.ErrNormal)
66 return
67 }
68
69 if !n.OnlineMode() {
70 err := n.SetupOfflineRouting()
71 if err != nil {
70 - res.SetError(err, cmds.ErrNormal)
72 + res.SetError(err, cmdkit.ErrNormal)
73 return
74 }
75 }
@@ -79,7 +81,7 @@ Resolve the value of a dnslink:
81 var resolver namesys.Resolver = n.Namesys
82
83 if local && nocache {
82 - res.SetError(errors.New("cannot specify both local and nocache"), cmds.ErrNormal)
84 + res.SetError(errors.New("cannot specify both local and nocache"), cmdkit.ErrNormal)
85 return
86 }
87
@@ -95,7 +97,7 @@ Resolve the value of a dnslink:
97 var name string
98 if len(req.Arguments()) == 0 {
99 if n.Identity == "" {
98 - res.SetError(errors.New("identity not loaded"), cmds.ErrNormal)
100 + res.SetError(errors.New("identity not loaded"), cmdkit.ErrNormal)
101 return
102 }
103 name = n.Identity.Pretty()
@@ -116,7 +118,7 @@ Resolve the value of a dnslink:
118
119 output, err := resolver.ResolveN(req.Context(), name, depth)
120 if err != nil {
119 - res.SetError(err, cmds.ErrNormal)
121 + res.SetError(err, cmdkit.ErrNormal)
122 return
123 }
124
@@ -126,9 +128,14 @@ Resolve the value of a dnslink:
128 },
129 Marshalers: cmds.MarshalerMap{
130 cmds.Text: func(res cmds.Response) (io.Reader, error) {
129 - output, ok := res.Output().(*ResolvedPath)
131 + v, err := unwrapOutput(res.Output())
132 + if err != nil {
133 + return nil, err
134 + }
135 +
136 + output, ok := v.(*ResolvedPath)
137 if !ok {
131 - return nil, u.ErrCast()
138 + return nil, e.TypeErr(output, v)
139 }
140 return strings.NewReader(output.Path.String() + "\n"), nil
141 },
core/commands/keystore.go
+65 -55
@@ -3,7 +3,6 @@ package commands
3 import (
4 "bytes"
5 "crypto/rand"
6 - "errors"
6 "fmt"
7 "io"
8 "sort"
@@ -11,13 +10,15 @@ import (
10 "text/tabwriter"
11
12 cmds "github.com/ipfs/go-ipfs/commands"
13 + e "github.com/ipfs/go-ipfs/core/commands/e"
14
15 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
16 peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer"
17 ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto"
18 )
19
20 var KeyCmd = &cmds.Command{
20 - Helptext: cmds.HelpText{
21 + Helptext: cmdkit.HelpText{
22 Tagline: "Create and list IPNS name keypairs",
23 ShortDescription: `
24 'ipfs key gen' generates a new keypair for usage with IPNS and 'ipfs name
@@ -59,43 +60,43 @@ type KeyRenameOutput struct {
60 }
61
62 var keyGenCmd = &cmds.Command{
62 - Helptext: cmds.HelpText{
63 + Helptext: cmdkit.HelpText{
64 Tagline: "Create a new keypair",
65 },
65 - Options: []cmds.Option{
66 - cmds.StringOption("type", "t", "type of the key to create [rsa, ed25519]"),
67 - cmds.IntOption("size", "s", "size of the key to generate"),
66 + Options: []cmdkit.Option{
67 + cmdkit.StringOption("type", "t", "type of the key to create [rsa, ed25519]"),
68 + cmdkit.IntOption("size", "s", "size of the key to generate"),
69 },
69 - Arguments: []cmds.Argument{
70 - cmds.StringArg("name", true, false, "name of key to create"),
70 + Arguments: []cmdkit.Argument{
71 + cmdkit.StringArg("name", true, false, "name of key to create"),
72 },
73 Run: func(req cmds.Request, res cmds.Response) {
74 n, err := req.InvocContext().GetNode()
75 if err != nil {
75 - res.SetError(err, cmds.ErrNormal)
76 + res.SetError(err, cmdkit.ErrNormal)
77 return
78 }
79
80 typ, f, err := req.Option("type").String()
81 if err != nil {
81 - res.SetError(err, cmds.ErrNormal)
82 + res.SetError(err, cmdkit.ErrNormal)
83 return
84 }
85
86 if !f {
86 - res.SetError(fmt.Errorf("please specify a key type with --type"), cmds.ErrNormal)
87 + res.SetError(fmt.Errorf("please specify a key type with --type"), cmdkit.ErrNormal)
88 return
89 }
90
91 size, sizefound, err := req.Option("size").Int()
92 if err != nil {
92 - res.SetError(err, cmds.ErrNormal)
93 + res.SetError(err, cmdkit.ErrNormal)
94 return
95 }
96
97 name := req.Arguments()[0]
98 if name == "self" {
98 - res.SetError(fmt.Errorf("cannot create key with name 'self'"), cmds.ErrNormal)
99 + res.SetError(fmt.Errorf("cannot create key with name 'self'"), cmdkit.ErrNormal)
100 return
101 }
102
@@ -105,13 +106,13 @@ var keyGenCmd = &cmds.Command{
106 switch typ {
107 case "rsa":
108 if !sizefound {
108 - res.SetError(fmt.Errorf("please specify a key size with --size"), cmds.ErrNormal)
109 + res.SetError(fmt.Errorf("please specify a key size with --size"), cmdkit.ErrNormal)
110 return
111 }
112
113 priv, pub, err := ci.GenerateKeyPairWithReader(ci.RSA, size, rand.Reader)
114 if err != nil {
114 - res.SetError(err, cmds.ErrNormal)
115 + res.SetError(err, cmdkit.ErrNormal)
116 return
117 }
118
@@ -120,26 +121,26 @@ var keyGenCmd = &cmds.Command{
121 case "ed25519":
122 priv, pub, err := ci.GenerateEd25519Key(rand.Reader)
123 if err != nil {
123 - res.SetError(err, cmds.ErrNormal)
124 + res.SetError(err, cmdkit.ErrNormal)
125 return
126 }
127
128 sk = priv
129 pk = pub
130 default:
130 - res.SetError(fmt.Errorf("unrecognized key type: %s", typ), cmds.ErrNormal)
131 + res.SetError(fmt.Errorf("unrecognized key type: %s", typ), cmdkit.ErrNormal)
132 return
133 }
134
135 err = n.Repo.Keystore().Put(name, sk)
136 if err != nil {
136 - res.SetError(err, cmds.ErrNormal)
137 + res.SetError(err, cmdkit.ErrNormal)
138 return
139 }
140
141 pid, err := peer.IDFromPublicKey(pk)
142 if err != nil {
142 - res.SetError(err, cmds.ErrNormal)
143 + res.SetError(err, cmdkit.ErrNormal)
144 return
145 }
146
@@ -150,9 +151,14 @@ var keyGenCmd = &cmds.Command{
151 },
152 Marshalers: cmds.MarshalerMap{
153 cmds.Text: func(res cmds.Response) (io.Reader, error) {
153 - k, ok := res.Output().(*KeyOutput)
154 + v, err := unwrapOutput(res.Output())
155 + if err != nil {
156 + return nil, err
157 + }
158 +
159 + k, ok := v.(*KeyOutput)
160 if !ok {
155 - return nil, fmt.Errorf("expected a KeyOutput as command result")
161 + return nil, e.TypeErr(k, v)
162 }
163
164 return strings.NewReader(k.Id + "\n"), nil
@@ -162,22 +168,22 @@ var keyGenCmd = &cmds.Command{
168 }
169
170 var keyListCmd = &cmds.Command{
165 - Helptext: cmds.HelpText{
171 + Helptext: cmdkit.HelpText{
172 Tagline: "List all local keypairs",
173 },
168 - Options: []cmds.Option{
169 - cmds.BoolOption("l", "Show extra information about keys."),
174 + Options: []cmdkit.Option{
175 + cmdkit.BoolOption("l", "Show extra information about keys."),
176 },
177 Run: func(req cmds.Request, res cmds.Response) {
178 n, err := req.InvocContext().GetNode()
179 if err != nil {
174 - res.SetError(err, cmds.ErrNormal)
180 + res.SetError(err, cmdkit.ErrNormal)
181 return
182 }
183
184 keys, err := n.Repo.Keystore().List()
185 if err != nil {
180 - res.SetError(err, cmds.ErrNormal)
186 + res.SetError(err, cmdkit.ErrNormal)
187 return
188 }
189
@@ -190,7 +196,7 @@ var keyListCmd = &cmds.Command{
196 for _, key := range keys {
197 privKey, err := n.Repo.Keystore().Get(key)
198 if err != nil {
193 - res.SetError(err, cmds.ErrNormal)
199 + res.SetError(err, cmdkit.ErrNormal)
200 return
201 }
202
@@ -198,7 +204,7 @@ var keyListCmd = &cmds.Command{
204
205 pid, err := peer.IDFromPublicKey(pubKey)
206 if err != nil {
201 - res.SetError(err, cmds.ErrNormal)
207 + res.SetError(err, cmdkit.ErrNormal)
208 return
209 }
210
@@ -214,20 +220,20 @@ var keyListCmd = &cmds.Command{
220 }
221
222 var keyRenameCmd = &cmds.Command{
217 - Helptext: cmds.HelpText{
223 + Helptext: cmdkit.HelpText{
224 Tagline: "Rename a keypair",
225 },
220 - Arguments: []cmds.Argument{
221 - cmds.StringArg("name", true, false, "name of key to rename"),
222 - cmds.StringArg("newName", true, false, "new name of the key"),
226 + Arguments: []cmdkit.Argument{
227 + cmdkit.StringArg("name", true, false, "name of key to rename"),
228 + cmdkit.StringArg("newName", true, false, "new name of the key"),
229 },
224 - Options: []cmds.Option{
225 - cmds.BoolOption("force", "f", "Allow to overwrite an existing key."),
230 + Options: []cmdkit.Option{
231 + cmdkit.BoolOption("force", "f", "Allow to overwrite an existing key."),
232 },
233 Run: func(req cmds.Request, res cmds.Response) {
234 n, err := req.InvocContext().GetNode()
235 if err != nil {
230 - res.SetError(err, cmds.ErrNormal)
236 + res.SetError(err, cmdkit.ErrNormal)
237 return
238 }
239
@@ -237,18 +243,18 @@ var keyRenameCmd = &cmds.Command{
243 newName := req.Arguments()[1]
244
245 if name == "self" {
240 - res.SetError(fmt.Errorf("cannot rename key with name 'self'"), cmds.ErrNormal)
246 + res.SetError(fmt.Errorf("cannot rename key with name 'self'"), cmdkit.ErrNormal)
247 return
248 }
249
250 if newName == "self" {
245 - res.SetError(fmt.Errorf("cannot overwrite key with name 'self'"), cmds.ErrNormal)
251 + res.SetError(fmt.Errorf("cannot overwrite key with name 'self'"), cmdkit.ErrNormal)
252 return
253 }
254
255 oldKey, err := ks.Get(name)
256 if err != nil {
251 - res.SetError(fmt.Errorf("no key named %s was found", name), cmds.ErrNormal)
257 + res.SetError(fmt.Errorf("no key named %s was found", name), cmdkit.ErrNormal)
258 return
259 }
260
@@ -256,7 +262,7 @@ var keyRenameCmd = &cmds.Command{
262
263 pid, err := peer.IDFromPublicKey(pubKey)
264 if err != nil {
259 - res.SetError(err, cmds.ErrNormal)
265 + res.SetError(err, cmdkit.ErrNormal)
266 return
267 }
268
@@ -265,7 +271,7 @@ var keyRenameCmd = &cmds.Command{
271 if force {
272 exist, err := ks.Has(newName)
273 if err != nil {
268 - res.SetError(err, cmds.ErrNormal)
274 + res.SetError(err, cmdkit.ErrNormal)
275 return
276 }
277
@@ -273,7 +279,7 @@ var keyRenameCmd = &cmds.Command{
279 overwrite = true
280 err := ks.Delete(newName)
281 if err != nil {
276 - res.SetError(err, cmds.ErrNormal)
282 + res.SetError(err, cmdkit.ErrNormal)
283 return
284 }
285 }
@@ -281,13 +287,13 @@ var keyRenameCmd = &cmds.Command{
287
288 err = ks.Put(newName, oldKey)
289 if err != nil {
284 - res.SetError(err, cmds.ErrNormal)
290 + res.SetError(err, cmdkit.ErrNormal)
291 return
292 }
293
294 err = ks.Delete(name)
295 if err != nil {
290 - res.SetError(err, cmds.ErrNormal)
296 + res.SetError(err, cmdkit.ErrNormal)
297 return
298 }
299
@@ -319,19 +325,19 @@ var keyRenameCmd = &cmds.Command{
325 }
326
327 var keyRmCmd = &cmds.Command{
322 - Helptext: cmds.HelpText{
328 + Helptext: cmdkit.HelpText{
329 Tagline: "Remove a keypair",
330 },
325 - Arguments: []cmds.Argument{
326 - cmds.StringArg("name", true, true, "names of keys to remove").EnableStdin(),
331 + Arguments: []cmdkit.Argument{
332 + cmdkit.StringArg("name", true, true, "names of keys to remove").EnableStdin(),
333 },
328 - Options: []cmds.Option{
329 - cmds.BoolOption("l", "Show extra information about keys."),
334 + Options: []cmdkit.Option{
335 + cmdkit.BoolOption("l", "Show extra information about keys."),
336 },
337 Run: func(req cmds.Request, res cmds.Response) {
338 n, err := req.InvocContext().GetNode()
339 if err != nil {
334 - res.SetError(err, cmds.ErrNormal)
340 + res.SetError(err, cmdkit.ErrNormal)
341 return
342 }
343
@@ -340,13 +346,13 @@ var keyRmCmd = &cmds.Command{
346 list := make([]KeyOutput, 0, len(names))
347 for _, name := range names {
348 if name == "self" {
343 - res.SetError(fmt.Errorf("cannot remove key with name 'self'"), cmds.ErrNormal)
349 + res.SetError(fmt.Errorf("cannot remove key with name 'self'"), cmdkit.ErrNormal)
350 return
351 }
352
353 removed, err := n.Repo.Keystore().Get(name)
354 if err != nil {
349 - res.SetError(fmt.Errorf("no key named %s was found", name), cmds.ErrNormal)
355 + res.SetError(fmt.Errorf("no key named %s was found", name), cmdkit.ErrNormal)
356 return
357 }
358
@@ -354,7 +360,7 @@ var keyRmCmd = &cmds.Command{
360
361 pid, err := peer.IDFromPublicKey(pubKey)
362 if err != nil {
357 - res.SetError(err, cmds.ErrNormal)
363 + res.SetError(err, cmdkit.ErrNormal)
364 return
365 }
366
@@ -364,7 +370,7 @@ var keyRmCmd = &cmds.Command{
370 for _, name := range names {
371 err = n.Repo.Keystore().Delete(name)
372 if err != nil {
367 - res.SetError(err, cmds.ErrNormal)
373 + res.SetError(err, cmdkit.ErrNormal)
374 return
375 }
376 }
@@ -380,9 +386,13 @@ var keyRmCmd = &cmds.Command{
386 func keyOutputListMarshaler(res cmds.Response) (io.Reader, error) {
387 withId, _, _ := res.Request().Option("l").Bool()
388
383 - list, ok := res.Output().(*KeyOutputList)
389 + v, err := unwrapOutput(res.Output())
390 + if err != nil {
391 + return nil, err
392 + }
393 + list, ok := v.(*KeyOutputList)
394 if !ok {
385 - return nil, errors.New("failed to cast []KeyOutput")
395 + return nil, e.TypeErr(list, v)
396 }
397
398 buf := new(bytes.Buffer)
core/commands/log.go
+11 -10
@@ -4,9 +4,10 @@ import (
4 "fmt"
5 "io"
6
7 - logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
8 -
7 cmds "github.com/ipfs/go-ipfs/commands"
8 +
9 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
10 + logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
11 )
12
13 // Golang os.Args overrides * and replaces the character argument with
@@ -16,7 +17,7 @@ import (
17 var logAllKeyword = "all"
18
19 var LogCmd = &cmds.Command{
19 - Helptext: cmds.HelpText{
20 + Helptext: cmdkit.HelpText{
21 Tagline: "Interact with the daemon log output.",
22 ShortDescription: `
23 'ipfs log' contains utility commands to affect or read the logging
@@ -32,7 +33,7 @@ output of a running daemon.
33 }
34
35 var logLevelCmd = &cmds.Command{
35 - Helptext: cmds.HelpText{
36 + Helptext: cmdkit.HelpText{
37 Tagline: "Change the logging level.",
38 ShortDescription: `
39 Change the verbosity of one or all subsystems log output. This does not affect
@@ -40,11 +41,11 @@ the event log.
41 `,
42 },
43
43 - Arguments: []cmds.Argument{
44 + Arguments: []cmdkit.Argument{
45 // TODO use a different keyword for 'all' because all can theoretically
46 // clash with a subsystem name
46 - cmds.StringArg("subsystem", true, false, fmt.Sprintf("The subsystem logging identifier. Use '%s' for all subsystems.", logAllKeyword)),
47 - cmds.StringArg("level", true, false, `The log level, with 'debug' the most verbose and 'critical' the least verbose.
47 + cmdkit.StringArg("subsystem", true, false, fmt.Sprintf("The subsystem logging identifier. Use '%s' for all subsystems.", logAllKeyword)),
48 + cmdkit.StringArg("level", true, false, `The log level, with 'debug' the most verbose and 'critical' the least verbose.
49 One of: debug, info, warning, error, critical.
50 `),
51 },
@@ -58,7 +59,7 @@ the event log.
59 }
60
61 if err := logging.SetLogLevel(subsystem, level); err != nil {
61 - res.SetError(err, cmds.ErrNormal)
62 + res.SetError(err, cmdkit.ErrNormal)
63 return
64 }
65
@@ -73,7 +74,7 @@ the event log.
74 }
75
76 var logLsCmd = &cmds.Command{
76 - Helptext: cmds.HelpText{
77 + Helptext: cmdkit.HelpText{
78 Tagline: "List the logging subsystems.",
79 ShortDescription: `
80 'ipfs log ls' is a utility command used to list the logging
@@ -90,7 +91,7 @@ subsystems of a running daemon.
91 }
92
93 var logTailCmd = &cmds.Command{
93 - Helptext: cmds.HelpText{
94 + Helptext: cmdkit.HelpText{
95 Tagline: "Read the event log.",
96 ShortDescription: `
97 Outputs event log messages (not other log messages) as they are generated.
core/commands/ls.go
+28 -16
@@ -9,6 +9,7 @@ import (
9 blockservice "github.com/ipfs/go-ipfs/blockservice"
10 cmds "github.com/ipfs/go-ipfs/commands"
11 core "github.com/ipfs/go-ipfs/core"
12 + e "github.com/ipfs/go-ipfs/core/commands/e"
13 offline "github.com/ipfs/go-ipfs/exchange/offline"
14 merkledag "github.com/ipfs/go-ipfs/merkledag"
15 path "github.com/ipfs/go-ipfs/path"
@@ -17,6 +18,7 @@ import (
18 unixfspb "github.com/ipfs/go-ipfs/unixfs/pb"
19
20 node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format"
21 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
22 )
23
24 type LsLink struct {
@@ -35,7 +37,7 @@ type LsOutput struct {
37 }
38
39 var LsCmd = &cmds.Command{
38 - Helptext: cmds.HelpText{
40 + Helptext: cmdkit.HelpText{
41 Tagline: "List directory contents for Unix filesystem objects.",
42 ShortDescription: `
43 Displays the contents of an IPFS or IPNS object(s) at the given path, with
@@ -47,29 +49,29 @@ The JSON output contains type information.
49 `,
50 },
51
50 - Arguments: []cmds.Argument{
51 - cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to list links from.").EnableStdin(),
52 + Arguments: []cmdkit.Argument{
53 + cmdkit.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to list links from.").EnableStdin(),
54 },
53 - Options: []cmds.Option{
54 - cmds.BoolOption("headers", "v", "Print table headers (Hash, Size, Name).").Default(false),
55 - cmds.BoolOption("resolve-type", "Resolve linked objects to find out their types.").Default(true),
55 + Options: []cmdkit.Option{
56 + cmdkit.BoolOption("headers", "v", "Print table headers (Hash, Size, Name).").Default(false),
57 + cmdkit.BoolOption("resolve-type", "Resolve linked objects to find out their types.").Default(true),
58 },
59 Run: func(req cmds.Request, res cmds.Response) {
60 nd, err := req.InvocContext().GetNode()
61 if err != nil {
60 - res.SetError(err, cmds.ErrNormal)
62 + res.SetError(err, cmdkit.ErrNormal)
63 return
64 }
65
66 // get options early -> exit early in case of error
67 if _, _, err := req.Option("headers").Bool(); err != nil {
66 - res.SetError(err, cmds.ErrNormal)
68 + res.SetError(err, cmdkit.ErrNormal)
69 return
70 }
71
72 resolve, _, err := req.Option("resolve-type").Bool()
73 if err != nil {
72 - res.SetError(err, cmds.ErrNormal)
74 + res.SetError(err, cmdkit.ErrNormal)
75 return
76 }
77
@@ -86,7 +88,7 @@ The JSON output contains type information.
88 for _, fpath := range paths {
89 p, err := path.ParsePath(fpath)
90 if err != nil {
89 - res.SetError(err, cmds.ErrNormal)
91 + res.SetError(err, cmdkit.ErrNormal)
92 return
93 }
94
@@ -97,17 +99,18 @@ The JSON output contains type information.
99
100 dagnode, err := core.Resolve(req.Context(), nd.Namesys, r, p)
101 if err != nil {
100 - res.SetError(err, cmds.ErrNormal)
102 + res.SetError(err, cmdkit.ErrNormal)
103 return
104 }
105 dagnodes = append(dagnodes, dagnode)
106 }
107
108 output := make([]LsObject, len(req.Arguments()))
109 +
110 for i, dagnode := range dagnodes {
111 dir, err := uio.NewDirectoryFromNode(nd.DAG, dagnode)
112 if err != nil && err != uio.ErrNotADir {
110 - res.SetError(err, cmds.ErrNormal)
113 + res.SetError(err, cmdkit.ErrNormal)
114 return
115 }
116
@@ -117,7 +120,7 @@ The JSON output contains type information.
120 } else {
121 links, err = dir.Links(req.Context())
122 if err != nil {
120 - res.SetError(err, cmds.ErrNormal)
123 + res.SetError(err, cmdkit.ErrNormal)
124 return
125 }
126 }
@@ -135,14 +138,14 @@ The JSON output contains type information.
138 // not an error
139 linkNode = nil
140 } else if err != nil {
138 - res.SetError(err, cmds.ErrNormal)
141 + res.SetError(err, cmdkit.ErrNormal)
142 return
143 }
144
145 if pn, ok := linkNode.(*merkledag.ProtoNode); ok {
146 d, err := unixfs.FromBytes(pn.Data())
147 if err != nil {
145 - res.SetError(err, cmds.ErrNormal)
148 + res.SetError(err, cmdkit.ErrNormal)
149 return
150 }
151
@@ -162,8 +165,17 @@ The JSON output contains type information.
165 Marshalers: cmds.MarshalerMap{
166 cmds.Text: func(res cmds.Response) (io.Reader, error) {
167
168 + v, err := unwrapOutput(res.Output())
169 + if err != nil {
170 + return nil, err
171 + }
172 +
173 headers, _, _ := res.Request().Option("headers").Bool()
166 - output := res.Output().(*LsOutput)
174 + output, ok := v.(*LsOutput)
175 + if !ok {
176 + return nil, e.TypeErr(output, v)
177 + }
178 +
179 buf := new(bytes.Buffer)
180 w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0)
181 for _, object := range output.Objects {
core/commands/mount_nofuse.go
+3 -1
@@ -5,10 +5,12 @@ package commands
5
6 import (
7 cmds "github.com/ipfs/go-ipfs/commands"
8 +
9 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
10 )
11
12 var MountCmd = &cmds.Command{
11 - Helptext: cmds.HelpText{
13 + Helptext: cmdkit.HelpText{
14 Tagline: "Mounts ipfs to the filesystem (disabled).",
15 ShortDescription: `
16 This version of ipfs is compiled without fuse support, which is required
core/commands/mount_unix.go
+25 -13
@@ -9,12 +9,15 @@ import (
9 "strings"
10
11 cmds "github.com/ipfs/go-ipfs/commands"
12 + e "github.com/ipfs/go-ipfs/core/commands/e"
13 nodeMount "github.com/ipfs/go-ipfs/fuse/node"
14 config "github.com/ipfs/go-ipfs/repo/config"
15 +
16 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
17 )
18
19 var MountCmd = &cmds.Command{
17 - Helptext: cmds.HelpText{
20 + Helptext: cmdkit.HelpText{
21 Tagline: "Mounts IPFS to the filesystem (read-only).",
22 ShortDescription: `
23 Mount IPFS at a read-only mountpoint on the OS (default: /ipfs and /ipns).
@@ -70,32 +73,32 @@ baz
73 baz
74 `,
75 },
73 - Options: []cmds.Option{
74 - cmds.StringOption("ipfs-path", "f", "The path where IPFS should be mounted."),
75 - cmds.StringOption("ipns-path", "n", "The path where IPNS should be mounted."),
76 + Options: []cmdkit.Option{
77 + cmdkit.StringOption("ipfs-path", "f", "The path where IPFS should be mounted."),
78 + cmdkit.StringOption("ipns-path", "n", "The path where IPNS should be mounted."),
79 },
80 Run: func(req cmds.Request, res cmds.Response) {
81 cfg, err := req.InvocContext().GetConfig()
82 if err != nil {
80 - res.SetError(err, cmds.ErrNormal)
83 + res.SetError(err, cmdkit.ErrNormal)
84 return
85 }
86
87 node, err := req.InvocContext().GetNode()
88 if err != nil {
86 - res.SetError(err, cmds.ErrNormal)
89 + res.SetError(err, cmdkit.ErrNormal)
90 return
91 }
92
93 // error if we aren't running node in online mode
94 if node.LocalMode() {
92 - res.SetError(errNotOnline, cmds.ErrClient)
95 + res.SetError(errNotOnline, cmdkit.ErrClient)
96 return
97 }
98
99 fsdir, found, err := req.Option("f").String()
100 if err != nil {
98 - res.SetError(err, cmds.ErrNormal)
101 + res.SetError(err, cmdkit.ErrNormal)
102 return
103 }
104 if !found {
@@ -105,7 +108,7 @@ baz
108 // get default mount points
109 nsdir, found, err := req.Option("n").String()
110 if err != nil {
108 - res.SetError(err, cmds.ErrNormal)
111 + res.SetError(err, cmdkit.ErrNormal)
112 return
113 }
114 if !found {
@@ -114,7 +117,7 @@ baz
117
118 err = nodeMount.Mount(node, fsdir, nsdir)
119 if err != nil {
117 - res.SetError(err, cmds.ErrNormal)
120 + res.SetError(err, cmdkit.ErrNormal)
121 return
122 }
123
@@ -126,9 +129,18 @@ baz
129 Type: config.Mounts{},
130 Marshalers: cmds.MarshalerMap{
131 cmds.Text: func(res cmds.Response) (io.Reader, error) {
129 - v := res.Output().(*config.Mounts)
130 - s := fmt.Sprintf("IPFS mounted at: %s\n", v.IPFS)
131 - s += fmt.Sprintf("IPNS mounted at: %s\n", v.IPNS)
132 + v, err := unwrapOutput(res.Output())
133 + if err != nil {
134 + return nil, err
135 + }
136 +
137 + mnts, ok := v.(*config.Mounts)
138 + if !ok {
139 + return nil, e.TypeErr(mnts, v)
140 + }
141 +
142 + s := fmt.Sprintf("IPFS mounted at: %s\n", mnts.IPFS)
143 + s += fmt.Sprintf("IPNS mounted at: %s\n", mnts.IPNS)
144 return strings.NewReader(s), nil
145 },
146 },
core/commands/mount_windows.go
+4 -2
@@ -3,16 +3,18 @@ package commands
3 import (
4 "errors"
5
6 + "gx/ipfs/QmadYQbq2fJpaRE3XhpMLH68NNxmWMwfMQy1ntr1cKf7eo/go-ipfs-cmdkit"
7 +
8 cmds "github.com/ipfs/go-ipfs/commands"
9 )
10
11 var MountCmd = &cmds.Command{
10 - Helptext: cmds.HelpText{
12 + Helptext: cmdkit.HelpText{
13 Tagline: "Not yet implemented on Windows.",
14 ShortDescription: "Not yet implemented on Windows. :(",
15 },
16
17 Run: func(req cmds.Request, res cmds.Response) {
16 - res.SetError(errors.New("Mount isn't compatible with Windows yet"), cmds.ErrNormal)
18 + res.SetError(errors.New("Mount isn't compatible with Windows yet"), cmdkit.ErrNormal)
19 },
20 }
core/commands/name.go
+6 -2
@@ -1,6 +1,10 @@
1 package commands
2
3 -import cmds "github.com/ipfs/go-ipfs/commands"
3 +import (
4 + cmds "github.com/ipfs/go-ipfs/commands"
5 +
6 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
7 +)
8
9 type IpnsEntry struct {
10 Name string
@@ -8,7 +12,7 @@ type IpnsEntry struct {
12 }
13
14 var NameCmd = &cmds.Command{
11 - Helptext: cmds.HelpText{
15 + Helptext: cmdkit.HelpText{
16 Tagline: "Publish and resolve IPNS names.",
17 ShortDescription: `
18 IPNS is a PKI namespace, where names are the hashes of public keys, and
core/commands/object/diff.go
+24 -13
@@ -7,8 +7,10 @@ import (
7
8 cmds "github.com/ipfs/go-ipfs/commands"
9 core "github.com/ipfs/go-ipfs/core"
10 + e "github.com/ipfs/go-ipfs/core/commands/e"
11 dagutils "github.com/ipfs/go-ipfs/merkledag/utils"
12 path "github.com/ipfs/go-ipfs/path"
13 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
14 )
15
16 type Changes struct {
@@ -16,7 +18,7 @@ type Changes struct {
18 }
19
20 var ObjectDiffCmd = &cmds.Command{
19 - Helptext: cmds.HelpText{
21 + Helptext: cmdkit.HelpText{
22 Tagline: "Display the diff between two ipfs objects.",
23 ShortDescription: `
24 'ipfs object diff' is a command used to show the differences between
@@ -42,17 +44,17 @@ Example:
44 Changed "bar" from QmNgd5cz2jNftnAHBhcRUGdtiaMzb5Rhjqd4etondHHST8 to QmRfFVsjSXkhFxrfWnLpMae2M4GBVsry6VAuYYcji5MiZb.
45 `,
46 },
45 - Arguments: []cmds.Argument{
46 - cmds.StringArg("obj_a", true, false, "Object to diff against."),
47 - cmds.StringArg("obj_b", true, false, "Object to diff."),
47 + Arguments: []cmdkit.Argument{
48 + cmdkit.StringArg("obj_a", true, false, "Object to diff against."),
49 + cmdkit.StringArg("obj_b", true, false, "Object to diff."),
50 },
49 - Options: []cmds.Option{
50 - cmds.BoolOption("verbose", "v", "Print extra information."),
51 + Options: []cmdkit.Option{
52 + cmdkit.BoolOption("verbose", "v", "Print extra information."),
53 },
54 Run: func(req cmds.Request, res cmds.Response) {
55 node, err := req.InvocContext().GetNode()
56 if err != nil {
55 - res.SetError(err, cmds.ErrNormal)
57 + res.SetError(err, cmdkit.ErrNormal)
58 return
59 }
60
@@ -61,13 +63,13 @@ Example:
63
64 pa, err := path.ParsePath(a)
65 if err != nil {
64 - res.SetError(err, cmds.ErrNormal)
66 + res.SetError(err, cmdkit.ErrNormal)
67 return
68 }
69
70 pb, err := path.ParsePath(b)
71 if err != nil {
70 - res.SetError(err, cmds.ErrNormal)
72 + res.SetError(err, cmdkit.ErrNormal)
73 return
74 }
75
@@ -75,19 +77,19 @@ Example:
77
78 obj_a, err := core.Resolve(ctx, node.Namesys, node.Resolver, pa)
79 if err != nil {
78 - res.SetError(err, cmds.ErrNormal)
80 + res.SetError(err, cmdkit.ErrNormal)
81 return
82 }
83
84 obj_b, err := core.Resolve(ctx, node.Namesys, node.Resolver, pb)
85 if err != nil {
84 - res.SetError(err, cmds.ErrNormal)
86 + res.SetError(err, cmdkit.ErrNormal)
87 return
88 }
89
90 changes, err := dagutils.Diff(ctx, node.DAG, obj_a, obj_b)
91 if err != nil {
90 - res.SetError(err, cmds.ErrNormal)
92 + res.SetError(err, cmdkit.ErrNormal)
93 return
94 }
95
@@ -96,8 +98,17 @@ Example:
98 Type: Changes{},
99 Marshalers: cmds.MarshalerMap{
100 cmds.Text: func(res cmds.Response) (io.Reader, error) {
101 + v, err := unwrapOutput(res.Output())
102 + if err != nil {
103 + return nil, err
104 + }
105 +
106 verbose, _, _ := res.Request().Option("v").Bool()
100 - changes := res.Output().(*Changes)
107 + changes, ok := v.(*Changes)
108 + if !ok {
109 + return nil, e.TypeErr(changes, v)
110 + }
111 +
112 buf := new(bytes.Buffer)
113 for _, change := range changes.Changes {
114 if verbose {
core/commands/object/object.go
+116 -57
@@ -14,10 +14,12 @@ import (
14
15 cmds "github.com/ipfs/go-ipfs/commands"
16 core "github.com/ipfs/go-ipfs/core"
17 + e "github.com/ipfs/go-ipfs/core/commands/e"
18 dag "github.com/ipfs/go-ipfs/merkledag"
19 path "github.com/ipfs/go-ipfs/path"
20 pin "github.com/ipfs/go-ipfs/pin"
21 ft "github.com/ipfs/go-ipfs/unixfs"
22 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
23
24 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
25 node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format"
@@ -44,7 +46,7 @@ type Object struct {
46 }
47
48 var ObjectCmd = &cmds.Command{
47 - Helptext: cmds.HelpText{
49 + Helptext: cmdkit.HelpText{
50 Tagline: "Interact with IPFS objects.",
51 ShortDescription: `
52 'ipfs object' is a plumbing command used to manipulate DAG objects
@@ -64,7 +66,7 @@ directly.`,
66 }
67
68 var ObjectDataCmd = &cmds.Command{
67 - Helptext: cmds.HelpText{
69 + Helptext: cmdkit.HelpText{
70 Tagline: "Output the raw bytes of an IPFS object.",
71 ShortDescription: `
72 'ipfs object data' is a plumbing command for retrieving the raw bytes stored
@@ -79,31 +81,31 @@ is the raw data of the object.
81 `,
82 },
83
82 - Arguments: []cmds.Argument{
83 - cmds.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(),
84 + Arguments: []cmdkit.Argument{
85 + cmdkit.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(),
86 },
87 Run: func(req cmds.Request, res cmds.Response) {
88 n, err := req.InvocContext().GetNode()
89 if err != nil {
88 - res.SetError(err, cmds.ErrNormal)
90 + res.SetError(err, cmdkit.ErrNormal)
91 return
92 }
93
94 fpath, err := path.ParsePath(req.Arguments()[0])
95 if err != nil {
94 - res.SetError(err, cmds.ErrNormal)
96 + res.SetError(err, cmdkit.ErrNormal)
97 return
98 }
99
100 node, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, fpath)
101 if err != nil {
100 - res.SetError(err, cmds.ErrNormal)
102 + res.SetError(err, cmdkit.ErrNormal)
103 return
104 }
105
106 pbnode, ok := node.(*dag.ProtoNode)
107 if !ok {
106 - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal)
108 + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal)
109 return
110 }
111
@@ -112,7 +114,7 @@ is the raw data of the object.
114 }
115
116 var ObjectLinksCmd = &cmds.Command{
115 - Helptext: cmds.HelpText{
117 + Helptext: cmdkit.HelpText{
118 Tagline: "Output the links pointed to by the specified object.",
119 ShortDescription: `
120 'ipfs object links' is a plumbing command for retrieving the links from
@@ -121,42 +123,51 @@ multihash.
123 `,
124 },
125
124 - Arguments: []cmds.Argument{
125 - cmds.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(),
126 + Arguments: []cmdkit.Argument{
127 + cmdkit.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(),
128 },
127 - Options: []cmds.Option{
128 - cmds.BoolOption("headers", "v", "Print table headers (Hash, Size, Name).").Default(false),
129 + Options: []cmdkit.Option{
130 + cmdkit.BoolOption("headers", "v", "Print table headers (Hash, Size, Name).").Default(false),
131 },
132 Run: func(req cmds.Request, res cmds.Response) {
133 n, err := req.InvocContext().GetNode()
134 if err != nil {
133 - res.SetError(err, cmds.ErrNormal)
135 + res.SetError(err, cmdkit.ErrNormal)
136 return
137 }
138
139 // get options early -> exit early in case of error
140 if _, _, err := req.Option("headers").Bool(); err != nil {
139 - res.SetError(err, cmds.ErrNormal)
141 + res.SetError(err, cmdkit.ErrNormal)
142 return
143 }
144
145 fpath := path.Path(req.Arguments()[0])
146 node, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, fpath)
147 if err != nil {
146 - res.SetError(err, cmds.ErrNormal)
148 + res.SetError(err, cmdkit.ErrNormal)
149 return
150 }
151
152 output, err := getOutput(node)
153 if err != nil {
152 - res.SetError(err, cmds.ErrNormal)
154 + res.SetError(err, cmdkit.ErrNormal)
155 return
156 }
157 res.SetOutput(output)
158 },
159 Marshalers: cmds.MarshalerMap{
160 cmds.Text: func(res cmds.Response) (io.Reader, error) {
159 - object := res.Output().(*Object)
161 + v, err := unwrapOutput(res.Output())
162 + if err != nil {
163 + return nil, err
164 + }
165 +
166 + object, ok := v.(*Object)
167 + if !ok {
168 + return nil, e.TypeErr(object, v)
169 + }
170 +
171 buf := new(bytes.Buffer)
172 w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0)
173 headers, _, _ := res.Request().Option("headers").Bool()
@@ -174,7 +185,7 @@ multihash.
185 }
186
187 var ObjectGetCmd = &cmds.Command{
177 - Helptext: cmds.HelpText{
188 + Helptext: cmdkit.HelpText{
189 Tagline: "Get and serialize the DAG node named by <key>.",
190 ShortDescription: `
191 'ipfs object get' is a plumbing command for retrieving DAG nodes.
@@ -193,13 +204,13 @@ This command outputs data in the following encodings:
204 (Specified by the "--encoding" or "--enc" flag)`,
205 },
206
196 - Arguments: []cmds.Argument{
197 - cmds.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(),
207 + Arguments: []cmdkit.Argument{
208 + cmdkit.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(),
209 },
210 Run: func(req cmds.Request, res cmds.Response) {
211 n, err := req.InvocContext().GetNode()
212 if err != nil {
202 - res.SetError(err, cmds.ErrNormal)
213 + res.SetError(err, cmdkit.ErrNormal)
214 return
215 }
216
@@ -207,13 +218,13 @@ This command outputs data in the following encodings:
218
219 object, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, fpath)
220 if err != nil {
210 - res.SetError(err, cmds.ErrNormal)
221 + res.SetError(err, cmdkit.ErrNormal)
222 return
223 }
224
225 pbo, ok := object.(*dag.ProtoNode)
226 if !ok {
216 - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal)
227 + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal)
228 return
229 }
230
@@ -235,7 +246,16 @@ This command outputs data in the following encodings:
246 Type: Node{},
247 Marshalers: cmds.MarshalerMap{
248 cmds.Protobuf: func(res cmds.Response) (io.Reader, error) {
238 - node := res.Output().(*Node)
249 + v, err := unwrapOutput(res.Output())
250 + if err != nil {
251 + return nil, err
252 + }
253 +
254 + node, ok := v.(*Node)
255 + if !ok {
256 + return nil, e.TypeErr(node, v)
257 + }
258 +
259 // deserialize the Data field as text as this was the standard behaviour
260 object, err := deserializeNode(node, "text")
261 if err != nil {
@@ -252,7 +272,7 @@ This command outputs data in the following encodings:
272 }
273
274 var ObjectStatCmd = &cmds.Command{
255 - Helptext: cmds.HelpText{
275 + Helptext: cmdkit.HelpText{
276 Tagline: "Get stats for the DAG node named by <key>.",
277 ShortDescription: `
278 'ipfs object stat' is a plumbing command to print DAG node statistics.
@@ -266,13 +286,13 @@ var ObjectStatCmd = &cmds.Command{
286 `,
287 },
288
269 - Arguments: []cmds.Argument{
270 - cmds.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(),
289 + Arguments: []cmdkit.Argument{
290 + cmdkit.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(),
291 },
292 Run: func(req cmds.Request, res cmds.Response) {
293 n, err := req.InvocContext().GetNode()
294 if err != nil {
275 - res.SetError(err, cmds.ErrNormal)
295 + res.SetError(err, cmdkit.ErrNormal)
296 return
297 }
298
@@ -280,13 +300,13 @@ var ObjectStatCmd = &cmds.Command{
300
301 object, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, fpath)
302 if err != nil {
283 - res.SetError(err, cmds.ErrNormal)
303 + res.SetError(err, cmdkit.ErrNormal)
304 return
305 }
306
307 ns, err := object.Stat()
308 if err != nil {
289 - res.SetError(err, cmds.ErrNormal)
309 + res.SetError(err, cmdkit.ErrNormal)
310 return
311 }
312
@@ -295,7 +315,15 @@ var ObjectStatCmd = &cmds.Command{
315 Type: node.NodeStat{},
316 Marshalers: cmds.MarshalerMap{
317 cmds.Text: func(res cmds.Response) (io.Reader, error) {
298 - ns := res.Output().(*node.NodeStat)
318 + v, err := unwrapOutput(res.Output())
319 + if err != nil {
320 + return nil, err
321 + }
322 +
323 + ns, ok := v.(*node.NodeStat)
324 + if !ok {
325 + return nil, e.TypeErr(ns, v)
326 + }
327
328 buf := new(bytes.Buffer)
329 w := func(s string, n int) {
@@ -313,7 +341,7 @@ var ObjectStatCmd = &cmds.Command{
341 }
342
343 var ObjectPutCmd = &cmds.Command{
316 - Helptext: cmds.HelpText{
344 + Helptext: cmdkit.HelpText{
345 Tagline: "Store input as a DAG object, print its key.",
346 ShortDescription: `
347 'ipfs object put' is a plumbing command for storing DAG nodes.
@@ -350,42 +378,42 @@ And then run:
378 `,
379 },
380
353 - Arguments: []cmds.Argument{
354 - cmds.FileArg("data", true, false, "Data to be stored as a DAG object.").EnableStdin(),
381 + Arguments: []cmdkit.Argument{
382 + cmdkit.FileArg("data", true, false, "Data to be stored as a DAG object.").EnableStdin(),
383 },
356 - Options: []cmds.Option{
357 - cmds.StringOption("inputenc", "Encoding type of input data. One of: {\"protobuf\", \"json\"}.").Default("json"),
358 - cmds.StringOption("datafieldenc", "Encoding type of the data field, either \"text\" or \"base64\".").Default("text"),
359 - cmds.BoolOption("pin", "Pin this object when adding.").Default(false),
384 + Options: []cmdkit.Option{
385 + cmdkit.StringOption("inputenc", "Encoding type of input data. One of: {\"protobuf\", \"json\"}.").Default("json"),
386 + cmdkit.StringOption("datafieldenc", "Encoding type of the data field, either \"text\" or \"base64\".").Default("text"),
387 + cmdkit.BoolOption("pin", "Pin this object when adding.").Default(false),
388 },
389 Run: func(req cmds.Request, res cmds.Response) {
390 n, err := req.InvocContext().GetNode()
391 if err != nil {
364 - res.SetError(err, cmds.ErrNormal)
392 + res.SetError(err, cmdkit.ErrNormal)
393 return
394 }
395
396 input, err := req.Files().NextFile()
397 if err != nil && err != io.EOF {
370 - res.SetError(err, cmds.ErrNormal)
398 + res.SetError(err, cmdkit.ErrNormal)
399 return
400 }
401
402 inputenc, _, err := req.Option("inputenc").String()
403 if err != nil {
376 - res.SetError(err, cmds.ErrNormal)
404 + res.SetError(err, cmdkit.ErrNormal)
405 return
406 }
407
408 datafieldenc, _, err := req.Option("datafieldenc").String()
409 if err != nil {
382 - res.SetError(err, cmds.ErrNormal)
410 + res.SetError(err, cmdkit.ErrNormal)
411 return
412 }
413
414 dopin, _, err := req.Option("pin").Bool()
415 if err != nil {
388 - res.SetError(err, cmds.ErrNormal)
416 + res.SetError(err, cmdkit.ErrNormal)
417 return
418 }
419
@@ -395,9 +423,9 @@ And then run:
423
424 objectCid, err := objectPut(n, input, inputenc, datafieldenc)
425 if err != nil {
398 - errType := cmds.ErrNormal
426 + errType := cmdkit.ErrNormal
427 if err == ErrUnknownObjectEnc {
400 - errType = cmds.ErrClient
428 + errType = cmdkit.ErrClient
429 }
430 res.SetError(err, errType)
431 return
@@ -407,7 +435,7 @@ And then run:
435 n.Pinning.PinWithMode(objectCid, pin.Recursive)
436 err = n.Pinning.Flush()
437 if err != nil {
410 - res.SetError(err, cmds.ErrNormal)
438 + res.SetError(err, cmdkit.ErrNormal)
439 return
440 }
441 }
@@ -416,15 +444,23 @@ And then run:
444 },
445 Marshalers: cmds.MarshalerMap{
446 cmds.Text: func(res cmds.Response) (io.Reader, error) {
419 - object := res.Output().(*Object)
420 - return strings.NewReader("added " + object.Hash + "\n"), nil
447 + v, err := unwrapOutput(res.Output())
448 + if err != nil {
449 + return nil, err
450 + }
451 + obj, ok := v.(*Object)
452 + if !ok {
453 + return nil, e.TypeErr(obj, v)
454 + }
455 +
456 + return strings.NewReader("added " + obj.Hash + "\n"), nil
457 },
458 },
459 Type: Object{},
460 }
461
462 var ObjectNewCmd = &cmds.Command{
427 - Helptext: cmds.HelpText{
463 + Helptext: cmdkit.HelpText{
464 Tagline: "Create a new object from an ipfs template.",
465 ShortDescription: `
466 'ipfs object new' is a plumbing command for creating new DAG nodes.
@@ -439,13 +475,13 @@ Available templates:
475 * unixfs-dir
476 `,
477 },
442 - Arguments: []cmds.Argument{
443 - cmds.StringArg("template", false, false, "Template to use. Optional."),
478 + Arguments: []cmdkit.Argument{
479 + cmdkit.StringArg("template", false, false, "Template to use. Optional."),
480 },
481 Run: func(req cmds.Request, res cmds.Response) {
482 n, err := req.InvocContext().GetNode()
483 if err != nil {
448 - res.SetError(err, cmds.ErrNormal)
484 + res.SetError(err, cmdkit.ErrNormal)
485 return
486 }
487
@@ -455,22 +491,31 @@ Available templates:
491 var err error
492 node, err = nodeFromTemplate(template)
493 if err != nil {
458 - res.SetError(err, cmds.ErrNormal)
494 + res.SetError(err, cmdkit.ErrNormal)
495 return
496 }
497 }
498
499 k, err := n.DAG.Add(node)
500 if err != nil {
465 - res.SetError(err, cmds.ErrNormal)
501 + res.SetError(err, cmdkit.ErrNormal)
502 return
503 }
504 res.SetOutput(&Object{Hash: k.String()})
505 },
506 Marshalers: cmds.MarshalerMap{
507 cmds.Text: func(res cmds.Response) (io.Reader, error) {
472 - object := res.Output().(*Object)
473 - return strings.NewReader(object.Hash + "\n"), nil
508 + v, err := unwrapOutput(res.Output())
509 + if err != nil {
510 + return nil, err
511 + }
512 +
513 + obj, ok := v.(*Object)
514 + if !ok {
515 + return nil, e.TypeErr(obj, v)
516 + }
517 +
518 + return strings.NewReader(obj.Hash + "\n"), nil
519 },
520 },
521 Type: Object{},
@@ -628,3 +673,17 @@ func deserializeNode(nd *Node, dataFieldEncoding string) (*dag.ProtoNode, error)
673 func NodeEmpty(node *Node) bool {
674 return (node.Data == "" && len(node.Links) == 0)
675 }
676 +
677 +// copy+pasted from ../commands.go
678 +func unwrapOutput(i interface{}) (interface{}, error) {
679 + var (
680 + ch <-chan interface{}
681 + ok bool
682 + )
683 +
684 + if ch, ok = i.(<-chan interface{}); !ok {
685 + return nil, e.TypeErr(ch, i)
686 + }
687 +
688 + return <-ch, nil
689 +}
core/commands/object/patch.go
+61 -54
@@ -7,15 +7,17 @@ import (
7
8 cmds "github.com/ipfs/go-ipfs/commands"
9 core "github.com/ipfs/go-ipfs/core"
10 + e "github.com/ipfs/go-ipfs/core/commands/e"
11 dag "github.com/ipfs/go-ipfs/merkledag"
12 dagutils "github.com/ipfs/go-ipfs/merkledag/utils"
13 path "github.com/ipfs/go-ipfs/path"
14 ft "github.com/ipfs/go-ipfs/unixfs"
14 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
15 +
16 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
17 )
18
19 var ObjectPatchCmd = &cmds.Command{
18 - Helptext: cmds.HelpText{
20 + Helptext: cmdkit.HelpText{
21 Tagline: "Create a new merkledag object based on an existing one.",
22 ShortDescription: `
23 'ipfs object patch <root> <cmd> <args>' is a plumbing command used to
@@ -23,7 +25,7 @@ build custom DAG objects. It mutates objects, creating new objects as a
25 result. This is the Merkle-DAG version of modifying an object.
26 `,
27 },
26 - Arguments: []cmds.Argument{},
28 + Arguments: []cmdkit.Argument{},
29 Subcommands: map[string]*cmds.Command{
30 "append-data": patchAppendDataCmd,
31 "add-link": patchAddLinkCmd,
@@ -33,16 +35,21 @@ result. This is the Merkle-DAG version of modifying an object.
35 }
36
37 func objectMarshaler(res cmds.Response) (io.Reader, error) {
36 - o, ok := res.Output().(*Object)
38 + v, err := unwrapOutput(res.Output())
39 + if err != nil {
40 + return nil, err
41 + }
42 +
43 + o, ok := v.(*Object)
44 if !ok {
38 - return nil, u.ErrCast()
45 + return nil, e.TypeErr(o, v)
46 }
47
48 return strings.NewReader(o.Hash + "\n"), nil
49 }
50
51 var patchAppendDataCmd = &cmds.Command{
45 - Helptext: cmds.HelpText{
52 + Helptext: cmdkit.HelpText{
53 Tagline: "Append data to the data segment of a dag node.",
54 ShortDescription: `
55 Append data to what already exists in the data segment in the given object.
@@ -56,44 +63,44 @@ data within an object. Objects have a max size of 1MB and objects larger than
63 the limit will not be respected by the network.
64 `,
65 },
59 - Arguments: []cmds.Argument{
60 - cmds.StringArg("root", true, false, "The hash of the node to modify."),
61 - cmds.FileArg("data", true, false, "Data to append.").EnableStdin(),
66 + Arguments: []cmdkit.Argument{
67 + cmdkit.StringArg("root", true, false, "The hash of the node to modify."),
68 + cmdkit.FileArg("data", true, false, "Data to append.").EnableStdin(),
69 },
70 Run: func(req cmds.Request, res cmds.Response) {
71 nd, err := req.InvocContext().GetNode()
72 if err != nil {
66 - res.SetError(err, cmds.ErrNormal)
73 + res.SetError(err, cmdkit.ErrNormal)
74 return
75 }
76
77 root, err := path.ParsePath(req.Arguments()[0])
78 if err != nil {
72 - res.SetError(err, cmds.ErrNormal)
79 + res.SetError(err, cmdkit.ErrNormal)
80 return
81 }
82
83 rootnd, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, root)
84 if err != nil {
78 - res.SetError(err, cmds.ErrNormal)
85 + res.SetError(err, cmdkit.ErrNormal)
86 return
87 }
88
89 rtpb, ok := rootnd.(*dag.ProtoNode)
90 if !ok {
84 - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal)
91 + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal)
92 return
93 }
94
95 fi, err := req.Files().NextFile()
96 if err != nil {
90 - res.SetError(err, cmds.ErrNormal)
97 + res.SetError(err, cmdkit.ErrNormal)
98 return
99 }
100
101 data, err := ioutil.ReadAll(fi)
102 if err != nil {
96 - res.SetError(err, cmds.ErrNormal)
103 + res.SetError(err, cmdkit.ErrNormal)
104 return
105 }
106
@@ -101,7 +108,7 @@ the limit will not be respected by the network.
108
109 newkey, err := nd.DAG.Add(rtpb)
110 if err != nil {
104 - res.SetError(err, cmds.ErrNormal)
111 + res.SetError(err, cmdkit.ErrNormal)
112 return
113 }
114
@@ -114,7 +121,7 @@ the limit will not be respected by the network.
121 }
122
123 var patchSetDataCmd = &cmds.Command{
117 - Helptext: cmds.HelpText{
124 + Helptext: cmdkit.HelpText{
125 Tagline: "Set the data field of an IPFS object.",
126 ShortDescription: `
127 Set the data of an IPFS object from stdin or with the contents of a file.
@@ -124,44 +131,44 @@ Example:
131 $ echo "my data" | ipfs object patch $MYHASH set-data
132 `,
133 },
127 - Arguments: []cmds.Argument{
128 - cmds.StringArg("root", true, false, "The hash of the node to modify."),
129 - cmds.FileArg("data", true, false, "The data to set the object to.").EnableStdin(),
134 + Arguments: []cmdkit.Argument{
135 + cmdkit.StringArg("root", true, false, "The hash of the node to modify."),
136 + cmdkit.FileArg("data", true, false, "The data to set the object to.").EnableStdin(),
137 },
138 Run: func(req cmds.Request, res cmds.Response) {
139 nd, err := req.InvocContext().GetNode()
140 if err != nil {
134 - res.SetError(err, cmds.ErrNormal)
141 + res.SetError(err, cmdkit.ErrNormal)
142 return
143 }
144
145 rp, err := path.ParsePath(req.Arguments()[0])
146 if err != nil {
140 - res.SetError(err, cmds.ErrNormal)
147 + res.SetError(err, cmdkit.ErrNormal)
148 return
149 }
150
151 root, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, rp)
152 if err != nil {
146 - res.SetError(err, cmds.ErrNormal)
153 + res.SetError(err, cmdkit.ErrNormal)
154 return
155 }
156
157 rtpb, ok := root.(*dag.ProtoNode)
158 if !ok {
152 - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal)
159 + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal)
160 return
161 }
162
163 fi, err := req.Files().NextFile()
164 if err != nil {
158 - res.SetError(err, cmds.ErrNormal)
165 + res.SetError(err, cmdkit.ErrNormal)
166 return
167 }
168
169 data, err := ioutil.ReadAll(fi)
170 if err != nil {
164 - res.SetError(err, cmds.ErrNormal)
171 + res.SetError(err, cmdkit.ErrNormal)
172 return
173 }
174
@@ -169,7 +176,7 @@ Example:
176
177 newkey, err := nd.DAG.Add(rtpb)
178 if err != nil {
172 - res.SetError(err, cmds.ErrNormal)
179 + res.SetError(err, cmdkit.ErrNormal)
180 return
181 }
182
@@ -182,38 +189,38 @@ Example:
189 }
190
191 var patchRmLinkCmd = &cmds.Command{
185 - Helptext: cmds.HelpText{
192 + Helptext: cmdkit.HelpText{
193 Tagline: "Remove a link from an object.",
194 ShortDescription: `
195 Removes a link by the given name from root.
196 `,
197 },
191 - Arguments: []cmds.Argument{
192 - cmds.StringArg("root", true, false, "The hash of the node to modify."),
193 - cmds.StringArg("link", true, false, "Name of the link to remove."),
198 + Arguments: []cmdkit.Argument{
199 + cmdkit.StringArg("root", true, false, "The hash of the node to modify."),
200 + cmdkit.StringArg("link", true, false, "Name of the link to remove."),
201 },
202 Run: func(req cmds.Request, res cmds.Response) {
203 nd, err := req.InvocContext().GetNode()
204 if err != nil {
198 - res.SetError(err, cmds.ErrNormal)
205 + res.SetError(err, cmdkit.ErrNormal)
206 return
207 }
208
209 rootp, err := path.ParsePath(req.Arguments()[0])
210 if err != nil {
204 - res.SetError(err, cmds.ErrNormal)
211 + res.SetError(err, cmdkit.ErrNormal)
212 return
213 }
214
215 root, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, rootp)
216 if err != nil {
210 - res.SetError(err, cmds.ErrNormal)
217 + res.SetError(err, cmdkit.ErrNormal)
218 return
219 }
220
221 rtpb, ok := root.(*dag.ProtoNode)
222 if !ok {
216 - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal)
223 + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal)
224 return
225 }
226
@@ -223,13 +230,13 @@ Removes a link by the given name from root.
230
231 err = e.RmLink(req.Context(), path)
232 if err != nil {
226 - res.SetError(err, cmds.ErrNormal)
233 + res.SetError(err, cmdkit.ErrNormal)
234 return
235 }
236
237 nnode, err := e.Finalize(nd.DAG)
238 if err != nil {
232 - res.SetError(err, cmds.ErrNormal)
239 + res.SetError(err, cmdkit.ErrNormal)
240 return
241 }
242
@@ -244,7 +251,7 @@ Removes a link by the given name from root.
251 }
252
253 var patchAddLinkCmd = &cmds.Command{
247 - Helptext: cmds.HelpText{
254 + Helptext: cmdkit.HelpText{
255 Tagline: "Add a link to a given object.",
256 ShortDescription: `
257 Add a Merkle-link to the given object and return the hash of the result.
@@ -259,49 +266,49 @@ This takes an empty directory, and adds a link named 'foo' under it, pointing
266 to a file containing 'bar', and returns the hash of the new object.
267 `,
268 },
262 - Arguments: []cmds.Argument{
263 - cmds.StringArg("root", true, false, "The hash of the node to modify."),
264 - cmds.StringArg("name", true, false, "Name of link to create."),
265 - cmds.StringArg("ref", true, false, "IPFS object to add link to."),
269 + Arguments: []cmdkit.Argument{
270 + cmdkit.StringArg("root", true, false, "The hash of the node to modify."),
271 + cmdkit.StringArg("name", true, false, "Name of link to create."),
272 + cmdkit.StringArg("ref", true, false, "IPFS object to add link to."),
273 },
267 - Options: []cmds.Option{
268 - cmds.BoolOption("create", "p", "Create intermediary nodes.").Default(false),
274 + Options: []cmdkit.Option{
275 + cmdkit.BoolOption("create", "p", "Create intermediary nodes.").Default(false),
276 },
277 Run: func(req cmds.Request, res cmds.Response) {
278 nd, err := req.InvocContext().GetNode()
279 if err != nil {
273 - res.SetError(err, cmds.ErrNormal)
280 + res.SetError(err, cmdkit.ErrNormal)
281 return
282 }
283
284 rootp, err := path.ParsePath(req.Arguments()[0])
285 if err != nil {
279 - res.SetError(err, cmds.ErrNormal)
286 + res.SetError(err, cmdkit.ErrNormal)
287 return
288 }
289
290 root, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, rootp)
291 if err != nil {
285 - res.SetError(err, cmds.ErrNormal)
292 + res.SetError(err, cmdkit.ErrNormal)
293 return
294 }
295
296 rtpb, ok := root.(*dag.ProtoNode)
297 if !ok {
291 - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal)
298 + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal)
299 return
300 }
301
302 npath := req.Arguments()[1]
303 childp, err := path.ParsePath(req.Arguments()[2])
304 if err != nil {
298 - res.SetError(err, cmds.ErrNormal)
305 + res.SetError(err, cmdkit.ErrNormal)
306 return
307 }
308
309 create, _, err := req.Option("create").Bool()
310 if err != nil {
304 - res.SetError(err, cmds.ErrNormal)
311 + res.SetError(err, cmdkit.ErrNormal)
312 return
313 }
314
@@ -314,25 +321,25 @@ to a file containing 'bar', and returns the hash of the new object.
321
322 childnd, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, childp)
323 if err != nil {
317 - res.SetError(err, cmds.ErrNormal)
324 + res.SetError(err, cmdkit.ErrNormal)
325 return
326 }
327
328 chpb, ok := childnd.(*dag.ProtoNode)
329 if !ok {
323 - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal)
330 + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal)
331 return
332 }
333
334 err = e.InsertNodeAtPath(req.Context(), npath, chpb, createfunc)
335 if err != nil {
329 - res.SetError(err, cmds.ErrNormal)
336 + res.SetError(err, cmdkit.ErrNormal)
337 return
338 }
339
340 nnode, err := e.Finalize(nd.DAG)
341 if err != nil {
335 - res.SetError(err, cmds.ErrNormal)
342 + res.SetError(err, cmdkit.ErrNormal)
343 return
344 }
345
core/commands/p2p.go
+60 -45
@@ -11,6 +11,7 @@ import (
11 cmds "github.com/ipfs/go-ipfs/commands"
12 core "github.com/ipfs/go-ipfs/core"
13
14 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
15 ma "gx/ipfs/QmXY77cVe7rVRQXZZQRioukUM7aRW3BTcAgJe12MCtb3Ji/go-multiaddr"
16 )
17
@@ -42,7 +43,7 @@ type P2PStreamsOutput struct {
43
44 // P2PCmd is the 'ipfs p2p' command
45 var P2PCmd = &cmds.Command{
45 - Helptext: cmds.HelpText{
46 + Helptext: cmdkit.HelpText{
47 Tagline: "Libp2p stream mounting.",
48 ShortDescription: `
49 Create and use tunnels to remote peers over libp2p
@@ -59,7 +60,7 @@ are refined`,
60
61 // p2pListenerCmd is the 'ipfs p2p listener' command
62 var p2pListenerCmd = &cmds.Command{
62 - Helptext: cmds.HelpText{
63 + Helptext: cmdkit.HelpText{
64 Tagline: "P2P listener management.",
65 ShortDescription: "Create and manage listener p2p endpoints",
66 },
@@ -73,7 +74,7 @@ var p2pListenerCmd = &cmds.Command{
74
75 // p2pStreamCmd is the 'ipfs p2p stream' command
76 var p2pStreamCmd = &cmds.Command{
76 - Helptext: cmds.HelpText{
77 + Helptext: cmdkit.HelpText{
78 Tagline: "P2P stream management.",
79 ShortDescription: "Create and manage p2p streams",
80 },
@@ -86,17 +87,17 @@ var p2pStreamCmd = &cmds.Command{
87 }
88
89 var p2pListenerLsCmd = &cmds.Command{
89 - Helptext: cmds.HelpText{
90 + Helptext: cmdkit.HelpText{
91 Tagline: "List active p2p listeners.",
92 },
92 - Options: []cmds.Option{
93 - cmds.BoolOption("headers", "v", "Print table headers (HandlerID, Protocol, Local, Remote).").Default(false),
93 + Options: []cmdkit.Option{
94 + cmdkit.BoolOption("headers", "v", "Print table headers (HandlerID, Protocol, Local, Remote).").Default(false),
95 },
96 Run: func(req cmds.Request, res cmds.Response) {
97
98 n, err := getNode(req)
99 if err != nil {
99 - res.SetError(err, cmds.ErrNormal)
100 + res.SetError(err, cmdkit.ErrNormal)
101 return
102 }
103
@@ -114,8 +115,13 @@ var p2pListenerLsCmd = &cmds.Command{
115 Type: P2PLsOutput{},
116 Marshalers: cmds.MarshalerMap{
117 cmds.Text: func(res cmds.Response) (io.Reader, error) {
118 + v, err := unwrapOutput(res.Output())
119 + if err != nil {
120 + return nil, err
121 + }
122 +
123 headers, _, _ := res.Request().Option("headers").Bool()
118 - list, _ := res.Output().(*P2PLsOutput)
124 + list := v.(*P2PLsOutput)
125 buf := new(bytes.Buffer)
126 w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0)
127 for _, listener := range list.Listeners {
@@ -133,16 +139,16 @@ var p2pListenerLsCmd = &cmds.Command{
139 }
140
141 var p2pStreamLsCmd = &cmds.Command{
136 - Helptext: cmds.HelpText{
142 + Helptext: cmdkit.HelpText{
143 Tagline: "List active p2p streams.",
144 },
139 - Options: []cmds.Option{
140 - cmds.BoolOption("headers", "v", "Print table headers (HagndlerID, Protocol, Local, Remote).").Default(false),
145 + Options: []cmdkit.Option{
146 + cmdkit.BoolOption("headers", "v", "Print table headers (HagndlerID, Protocol, Local, Remote).").Default(false),
147 },
148 Run: func(req cmds.Request, res cmds.Response) {
149 n, err := getNode(req)
150 if err != nil {
145 - res.SetError(err, cmds.ErrNormal)
151 + res.SetError(err, cmdkit.ErrNormal)
152 return
153 }
154
@@ -167,8 +173,13 @@ var p2pStreamLsCmd = &cmds.Command{
173 Type: P2PStreamsOutput{},
174 Marshalers: cmds.MarshalerMap{
175 cmds.Text: func(res cmds.Response) (io.Reader, error) {
176 + v, err := unwrapOutput(res.Output())
177 + if err != nil {
178 + return nil, err
179 + }
180 +
181 headers, _, _ := res.Request().Option("headers").Bool()
171 - list, _ := res.Output().(*P2PStreamsOutput)
182 + list := v.(*P2PStreamsOutput)
183 buf := new(bytes.Buffer)
184 w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0)
185 for _, stream := range list.Streams {
@@ -186,7 +197,7 @@ var p2pStreamLsCmd = &cmds.Command{
197 }
198
199 var p2pListenerListenCmd = &cmds.Command{
189 - Helptext: cmds.HelpText{
200 + Helptext: cmdkit.HelpText{
201 Tagline: "Forward p2p connections to a network multiaddr.",
202 ShortDescription: `
203 Register a p2p connection handler and forward the connections to a specified
@@ -195,32 +206,32 @@ address.
206 Note that the connections originate from the ipfs daemon process.
207 `,
208 },
198 - Arguments: []cmds.Argument{
199 - cmds.StringArg("Protocol", true, false, "Protocol identifier."),
200 - cmds.StringArg("Address", true, false, "Request handling application address."),
209 + Arguments: []cmdkit.Argument{
210 + cmdkit.StringArg("Protocol", true, false, "Protocol identifier."),
211 + cmdkit.StringArg("Address", true, false, "Request handling application address."),
212 },
213 Run: func(req cmds.Request, res cmds.Response) {
214 n, err := getNode(req)
215 if err != nil {
205 - res.SetError(err, cmds.ErrNormal)
216 + res.SetError(err, cmdkit.ErrNormal)
217 return
218 }
219
220 proto := "/p2p/" + req.Arguments()[0]
221 if n.P2P.CheckProtoExists(proto) {
211 - res.SetError(errors.New("protocol handler already registered"), cmds.ErrNormal)
222 + res.SetError(errors.New("protocol handler already registered"), cmdkit.ErrNormal)
223 return
224 }
225
226 addr, err := ma.NewMultiaddr(req.Arguments()[1])
227 if err != nil {
217 - res.SetError(err, cmds.ErrNormal)
228 + res.SetError(err, cmdkit.ErrNormal)
229 return
230 }
231
232 _, err = n.P2P.NewListener(n.Context(), proto, addr)
233 if err != nil {
223 - res.SetError(err, cmds.ErrNormal)
234 + res.SetError(err, cmdkit.ErrNormal)
235 return
236 }
237
@@ -233,7 +244,7 @@ Note that the connections originate from the ipfs daemon process.
244 }
245
246 var p2pStreamDialCmd = &cmds.Command{
236 - Helptext: cmds.HelpText{
247 + Helptext: cmdkit.HelpText{
248 Tagline: "Dial to a p2p listener.",
249
250 ShortDescription: `
@@ -244,21 +255,21 @@ time TCP listener and return it's bind port, this way a dialing application
255 can transparently connect to a p2p service.
256 `,
257 },
247 - Arguments: []cmds.Argument{
248 - cmds.StringArg("Peer", true, false, "Remote peer to connect to"),
249 - cmds.StringArg("Protocol", true, false, "Protocol identifier."),
250 - cmds.StringArg("BindAddress", false, false, "Address to listen for connection/s (default: /ip4/127.0.0.1/tcp/0)."),
258 + Arguments: []cmdkit.Argument{
259 + cmdkit.StringArg("Peer", true, false, "Remote peer to connect to"),
260 + cmdkit.StringArg("Protocol", true, false, "Protocol identifier."),
261 + cmdkit.StringArg("BindAddress", false, false, "Address to listen for connection/s (default: /ip4/127.0.0.1/tcp/0)."),
262 },
263 Run: func(req cmds.Request, res cmds.Response) {
264 n, err := getNode(req)
265 if err != nil {
255 - res.SetError(err, cmds.ErrNormal)
266 + res.SetError(err, cmdkit.ErrNormal)
267 return
268 }
269
270 addr, peer, err := ParsePeerParam(req.Arguments()[0])
271 if err != nil {
261 - res.SetError(err, cmds.ErrNormal)
272 + res.SetError(err, cmdkit.ErrNormal)
273 return
274 }
275
@@ -268,14 +279,14 @@ can transparently connect to a p2p service.
279 if len(req.Arguments()) == 3 {
280 bindAddr, err = ma.NewMultiaddr(req.Arguments()[2])
281 if err != nil {
271 - res.SetError(err, cmds.ErrNormal)
282 + res.SetError(err, cmdkit.ErrNormal)
283 return
284 }
285 }
286
287 listenerInfo, err := n.P2P.Dial(n.Context(), addr, peer, proto, bindAddr)
288 if err != nil {
278 - res.SetError(err, cmds.ErrNormal)
289 + res.SetError(err, cmdkit.ErrNormal)
290 return
291 }
292
@@ -289,19 +300,21 @@ can transparently connect to a p2p service.
300 }
301
302 var p2pListenerCloseCmd = &cmds.Command{
292 - Helptext: cmds.HelpText{
303 + Helptext: cmdkit.HelpText{
304 Tagline: "Close active p2p listener.",
305 },
295 - Arguments: []cmds.Argument{
296 - cmds.StringArg("Protocol", false, false, "P2P listener protocol"),
306 + Arguments: []cmdkit.Argument{
307 + cmdkit.StringArg("Protocol", false, false, "P2P listener protocol"),
308 },
298 - Options: []cmds.Option{
299 - cmds.BoolOption("all", "a", "Close all listeners.").Default(false),
309 + Options: []cmdkit.Option{
310 + cmdkit.BoolOption("all", "a", "Close all listeners.").Default(false),
311 },
312 Run: func(req cmds.Request, res cmds.Response) {
313 + res.SetOutput(nil)
314 +
315 n, err := getNode(req)
316 if err != nil {
304 - res.SetError(err, cmds.ErrNormal)
317 + res.SetError(err, cmdkit.ErrNormal)
318 return
319 }
320
@@ -310,7 +323,7 @@ var p2pListenerCloseCmd = &cmds.Command{
323
324 if !closeAll {
325 if len(req.Arguments()) == 0 {
313 - res.SetError(errors.New("no protocol name specified"), cmds.ErrNormal)
326 + res.SetError(errors.New("no protocol name specified"), cmdkit.ErrNormal)
327 return
328 }
329
@@ -330,19 +343,21 @@ var p2pListenerCloseCmd = &cmds.Command{
343 }
344
345 var p2pStreamCloseCmd = &cmds.Command{
333 - Helptext: cmds.HelpText{
346 + Helptext: cmdkit.HelpText{
347 Tagline: "Close active p2p stream.",
348 },
336 - Arguments: []cmds.Argument{
337 - cmds.StringArg("HandlerID", false, false, "Stream HandlerID"),
349 + Arguments: []cmdkit.Argument{
350 + cmdkit.StringArg("HandlerID", false, false, "Stream HandlerID"),
351 },
339 - Options: []cmds.Option{
340 - cmds.BoolOption("all", "a", "Close all streams.").Default(false),
352 + Options: []cmdkit.Option{
353 + cmdkit.BoolOption("all", "a", "Close all streams.").Default(false),
354 },
355 Run: func(req cmds.Request, res cmds.Response) {
356 + res.SetOutput(nil)
357 +
358 n, err := getNode(req)
359 if err != nil {
345 - res.SetError(err, cmds.ErrNormal)
360 + res.SetError(err, cmdkit.ErrNormal)
361 return
362 }
363
@@ -351,13 +366,13 @@ var p2pStreamCloseCmd = &cmds.Command{
366
367 if !closeAll {
368 if len(req.Arguments()) == 0 {
354 - res.SetError(errors.New("no HandlerID specified"), cmds.ErrNormal)
369 + res.SetError(errors.New("no HandlerID specified"), cmdkit.ErrNormal)
370 return
371 }
372
373 handlerID, err = strconv.ParseUint(req.Arguments()[0], 10, 64)
374 if err != nil {
360 - res.SetError(err, cmds.ErrNormal)
375 + res.SetError(err, cmdkit.ErrNormal)
376 return
377 }
378 }
core/commands/pin.go
+102 -94
@@ -2,25 +2,27 @@ package commands
2
3 import (
4 "bytes"
5 + "context"
6 "fmt"
7 "io"
8 "time"
9
10 cmds "github.com/ipfs/go-ipfs/commands"
11 core "github.com/ipfs/go-ipfs/core"
12 + e "github.com/ipfs/go-ipfs/core/commands/e"
13 corerepo "github.com/ipfs/go-ipfs/core/corerepo"
14 dag "github.com/ipfs/go-ipfs/merkledag"
15 path "github.com/ipfs/go-ipfs/path"
16 pin "github.com/ipfs/go-ipfs/pin"
17 uio "github.com/ipfs/go-ipfs/unixfs/io"
18
17 - context "context"
19 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
20 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
21 u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
22 )
23
24 var PinCmd = &cmds.Command{
23 - Helptext: cmds.HelpText{
25 + Helptext: cmdkit.HelpText{
26 Tagline: "Pin (and unpin) objects to local storage.",
27 },
28
@@ -43,23 +45,23 @@ type AddPinOutput struct {
45 }
46
47 var addPinCmd = &cmds.Command{
46 - Helptext: cmds.HelpText{
48 + Helptext: cmdkit.HelpText{
49 Tagline: "Pin objects to local storage.",
50 ShortDescription: "Stores an IPFS object(s) from a given path locally to disk.",
51 },
52
51 - Arguments: []cmds.Argument{
52 - cmds.StringArg("ipfs-path", true, true, "Path to object(s) to be pinned.").EnableStdin(),
53 + Arguments: []cmdkit.Argument{
54 + cmdkit.StringArg("ipfs-path", true, true, "Path to object(s) to be pinned.").EnableStdin(),
55 },
54 - Options: []cmds.Option{
55 - cmds.BoolOption("recursive", "r", "Recursively pin the object linked to by the specified object(s).").Default(true),
56 - cmds.BoolOption("progress", "Show progress"),
56 + Options: []cmdkit.Option{
57 + cmdkit.BoolOption("recursive", "r", "Recursively pin the object linked to by the specified object(s).").Default(true),
58 + cmdkit.BoolOption("progress", "Show progress"),
59 },
60 Type: AddPinOutput{},
61 Run: func(req cmds.Request, res cmds.Response) {
62 n, err := req.InvocContext().GetNode()
63 if err != nil {
62 - res.SetError(err, cmds.ErrNormal)
64 + res.SetError(err, cmdkit.ErrNormal)
65 return
66 }
67
@@ -68,7 +70,7 @@ var addPinCmd = &cmds.Command{
70 // set recursive flag
71 recursive, _, err := req.Option("recursive").Bool()
72 if err != nil {
71 - res.SetError(err, cmds.ErrNormal)
73 + res.SetError(err, cmdkit.ErrNormal)
74 return
75 }
76 showProgress, _, _ := req.Option("progress").Bool()
@@ -76,13 +78,15 @@ var addPinCmd = &cmds.Command{
78 if !showProgress {
79 added, err := corerepo.Pin(n, req.Context(), req.Arguments(), recursive)
80 if err != nil {
79 - res.SetError(err, cmds.ErrNormal)
81 + res.SetError(err, cmdkit.ErrNormal)
82 return
83 }
84 res.SetOutput(&AddPinOutput{Pins: cidsToStrings(added)})
85 return
86 }
87
88 + out := make(chan interface{})
89 + res.SetOutput((<-chan interface{})(out))
90 v := new(dag.ProgressTracker)
91 ctx := v.DeriveContext(req.Context())
92
@@ -91,68 +95,62 @@ var addPinCmd = &cmds.Command{
95 defer close(ch)
96 added, err := corerepo.Pin(n, ctx, req.Arguments(), recursive)
97 if err != nil {
94 - res.SetError(err, cmds.ErrNormal)
98 + res.SetError(err, cmdkit.ErrNormal)
99 return
100 }
101 ch <- added
102 }()
99 - out := make(chan interface{})
100 - res.SetOutput((<-chan interface{})(out))
101 - go func() {
102 - ticker := time.NewTicker(500 * time.Millisecond)
103 - defer ticker.Stop()
104 - defer close(out)
105 - for {
106 - select {
107 - case val, ok := <-ch:
108 - if !ok {
109 - // error already set just return
110 - return
111 - }
112 - if pv := v.Value(); pv != 0 {
113 - out <- &AddPinOutput{Progress: v.Value()}
114 - }
115 - out <- &AddPinOutput{Pins: cidsToStrings(val)}
103 +
104 + ticker := time.NewTicker(500 * time.Millisecond)
105 + defer ticker.Stop()
106 + defer close(out)
107 + for {
108 + select {
109 + case val, ok := <-ch:
110 + if !ok {
111 + // error already set just return
112 return
117 - case <-ticker.C:
113 + }
114 +
115 + if pv := v.Value(); pv != 0 {
116 out <- &AddPinOutput{Progress: v.Value()}
119 - case <-ctx.Done():
120 - res.SetError(ctx.Err(), cmds.ErrNormal)
121 - return
117 }
118 + out <- &AddPinOutput{Pins: cidsToStrings(val)}
119 + return
120 + case <-ticker.C:
121 + out <- &AddPinOutput{Progress: v.Value()}
122 + case <-ctx.Done():
123 + log.Error(ctx.Err())
124 + res.SetError(ctx.Err(), cmdkit.ErrNormal)
125 + return
126 }
124 - }()
127 + }
128 },
129 Marshalers: cmds.MarshalerMap{
130 cmds.Text: func(res cmds.Response) (io.Reader, error) {
131 + v, err := unwrapOutput(res.Output())
132 + if err != nil {
133 + return nil, err
134 + }
135 +
136 var added []string
137
130 - switch out := res.Output().(type) {
138 + switch out := v.(type) {
139 case *AddPinOutput:
132 - added = out.Pins
133 - case <-chan interface{}:
134 - progressLine := false
135 - for r0 := range out {
136 - r := r0.(*AddPinOutput)
137 - if r.Pins != nil {
138 - added = r.Pins
139 - } else {
140 - if progressLine {
141 - fmt.Fprintf(res.Stderr(), "\r")
142 - }
143 - fmt.Fprintf(res.Stderr(), "Fetched/Processed %d nodes", r.Progress)
144 - progressLine = true
145 - }
146 - }
147 - if progressLine {
148 - fmt.Fprintf(res.Stderr(), "\n")
140 + if out.Pins != nil {
141 + added = out.Pins
142 + } else {
143 + // this can only happen if the progress option is set
144 + fmt.Fprintf(res.Stderr(), "Fetched/Processed %d nodes\r", out.Progress)
145 }
146 +
147 if res.Error() != nil {
148 return nil, res.Error()
149 }
150 default:
154 - return nil, u.ErrCast()
151 + return nil, e.TypeErr(out, v)
152 }
153 +
154 var pintype string
155 rec, found, _ := res.Request().Option("recursive").Bool()
156 if rec || !found {
@@ -171,7 +169,7 @@ var addPinCmd = &cmds.Command{
169 }
170
171 var rmPinCmd = &cmds.Command{
174 - Helptext: cmds.HelpText{
172 + Helptext: cmdkit.HelpText{
173 Tagline: "Remove pinned objects from local storage.",
174 ShortDescription: `
175 Removes the pin from the given object allowing it to be garbage
@@ -179,30 +177,30 @@ collected if needed. (By default, recursively. Use -r=false for direct pins.)
177 `,
178 },
179
182 - Arguments: []cmds.Argument{
183 - cmds.StringArg("ipfs-path", true, true, "Path to object(s) to be unpinned.").EnableStdin(),
180 + Arguments: []cmdkit.Argument{
181 + cmdkit.StringArg("ipfs-path", true, true, "Path to object(s) to be unpinned.").EnableStdin(),
182 },
185 - Options: []cmds.Option{
186 - cmds.BoolOption("recursive", "r", "Recursively unpin the object linked to by the specified object(s).").Default(true),
183 + Options: []cmdkit.Option{
184 + cmdkit.BoolOption("recursive", "r", "Recursively unpin the object linked to by the specified object(s).").Default(true),
185 },
186 Type: PinOutput{},
187 Run: func(req cmds.Request, res cmds.Response) {
188 n, err := req.InvocContext().GetNode()
189 if err != nil {
192 - res.SetError(err, cmds.ErrNormal)
190 + res.SetError(err, cmdkit.ErrNormal)
191 return
192 }
193
194 // set recursive flag
195 recursive, _, err := req.Option("recursive").Bool()
196 if err != nil {
199 - res.SetError(err, cmds.ErrNormal)
197 + res.SetError(err, cmdkit.ErrNormal)
198 return
199 }
200
201 removed, err := corerepo.Unpin(n, req.Context(), req.Arguments(), recursive)
202 if err != nil {
205 - res.SetError(err, cmds.ErrNormal)
203 + res.SetError(err, cmdkit.ErrNormal)
204 return
205 }
206
@@ -210,9 +208,14 @@ collected if needed. (By default, recursively. Use -r=false for direct pins.)
208 },
209 Marshalers: cmds.MarshalerMap{
210 cmds.Text: func(res cmds.Response) (io.Reader, error) {
213 - added, ok := res.Output().(*PinOutput)
211 + v, err := unwrapOutput(res.Output())
212 + if err != nil {
213 + return nil, err
214 + }
215 +
216 + added, ok := v.(*PinOutput)
217 if !ok {
215 - return nil, u.ErrCast()
218 + return nil, e.TypeErr(added, v)
219 }
220
221 buf := new(bytes.Buffer)
@@ -225,7 +228,7 @@ collected if needed. (By default, recursively. Use -r=false for direct pins.)
228 }
229
230 var listPinCmd = &cmds.Command{
228 - Helptext: cmds.HelpText{
231 + Helptext: cmdkit.HelpText{
232 Tagline: "List objects pinned to local storage.",
233 ShortDescription: `
234 Returns a list of objects that are pinned locally.
@@ -268,23 +271,23 @@ Example:
271 `,
272 },
273
271 - Arguments: []cmds.Argument{
272 - cmds.StringArg("ipfs-path", false, true, "Path to object(s) to be listed."),
274 + Arguments: []cmdkit.Argument{
275 + cmdkit.StringArg("ipfs-path", false, true, "Path to object(s) to be listed."),
276 },
274 - Options: []cmds.Option{
275 - cmds.StringOption("type", "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\".").Default("all"),
276 - cmds.BoolOption("quiet", "q", "Write just hashes of objects.").Default(false),
277 + Options: []cmdkit.Option{
278 + cmdkit.StringOption("type", "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\".").Default("all"),
279 + cmdkit.BoolOption("quiet", "q", "Write just hashes of objects.").Default(false),
280 },
281 Run: func(req cmds.Request, res cmds.Response) {
282 n, err := req.InvocContext().GetNode()
283 if err != nil {
281 - res.SetError(err, cmds.ErrNormal)
284 + res.SetError(err, cmdkit.ErrNormal)
285 return
286 }
287
288 typeStr, _, err := req.Option("type").String()
289 if err != nil {
287 - res.SetError(err, cmds.ErrNormal)
290 + res.SetError(err, cmdkit.ErrNormal)
291 return
292 }
293
@@ -292,7 +295,7 @@ Example:
295 case "all", "direct", "indirect", "recursive":
296 default:
297 err = fmt.Errorf("Invalid type '%s', must be one of {direct, indirect, recursive, all}", typeStr)
295 - res.SetError(err, cmds.ErrClient)
298 + res.SetError(err, cmdkit.ErrClient)
299 return
300 }
301
@@ -305,7 +308,7 @@ Example:
308 }
309
310 if err != nil {
308 - res.SetError(err, cmds.ErrNormal)
311 + res.SetError(err, cmdkit.ErrNormal)
312 } else {
313 res.SetOutput(&RefKeyList{Keys: keys})
314 }
@@ -313,14 +316,19 @@ Example:
316 Type: RefKeyList{},
317 Marshalers: cmds.MarshalerMap{
318 cmds.Text: func(res cmds.Response) (io.Reader, error) {
319 + v, err := unwrapOutput(res.Output())
320 + if err != nil {
321 + return nil, err
322 + }
323 +
324 quiet, _, err := res.Request().Option("quiet").Bool()
325 if err != nil {
326 return nil, err
327 }
328
321 - keys, ok := res.Output().(*RefKeyList)
329 + keys, ok := v.(*RefKeyList)
330 if !ok {
323 - return nil, u.ErrCast()
331 + return nil, e.TypeErr(keys, v)
332 }
333 out := new(bytes.Buffer)
334 for k, v := range keys.Keys {
@@ -336,7 +344,7 @@ Example:
344 }
345
346 var updatePinCmd = &cmds.Command{
339 - Helptext: cmds.HelpText{
347 + Helptext: cmdkit.HelpText{
348 Tagline: "Update a recursive pin",
349 ShortDescription: `
350 Updates one pin to another, making sure that all objects in the new pin are
@@ -345,36 +353,36 @@ new pin and removing the old one.
353 `,
354 },
355
348 - Arguments: []cmds.Argument{
349 - cmds.StringArg("from-path", true, false, "Path to old object."),
350 - cmds.StringArg("to-path", true, false, "Path to new object to be pinned."),
356 + Arguments: []cmdkit.Argument{
357 + cmdkit.StringArg("from-path", true, false, "Path to old object."),
358 + cmdkit.StringArg("to-path", true, false, "Path to new object to be pinned."),
359 },
352 - Options: []cmds.Option{
353 - cmds.BoolOption("unpin", "Remove the old pin.").Default(true),
360 + Options: []cmdkit.Option{
361 + cmdkit.BoolOption("unpin", "Remove the old pin.").Default(true),
362 },
363 Type: PinOutput{},
364 Run: func(req cmds.Request, res cmds.Response) {
365 n, err := req.InvocContext().GetNode()
366 if err != nil {
359 - res.SetError(err, cmds.ErrNormal)
367 + res.SetError(err, cmdkit.ErrNormal)
368 return
369 }
370
371 unpin, _, err := req.Option("unpin").Bool()
372 if err != nil {
365 - res.SetError(err, cmds.ErrNormal)
373 + res.SetError(err, cmdkit.ErrNormal)
374 return
375 }
376
377 from, err := path.ParsePath(req.Arguments()[0])
378 if err != nil {
371 - res.SetError(err, cmds.ErrNormal)
379 + res.SetError(err, cmdkit.ErrNormal)
380 return
381 }
382
383 to, err := path.ParsePath(req.Arguments()[1])
384 if err != nil {
377 - res.SetError(err, cmds.ErrNormal)
385 + res.SetError(err, cmdkit.ErrNormal)
386 return
387 }
388
@@ -385,19 +393,19 @@ new pin and removing the old one.
393
394 fromc, err := core.ResolveToCid(req.Context(), n.Namesys, r, from)
395 if err != nil {
388 - res.SetError(err, cmds.ErrNormal)
396 + res.SetError(err, cmdkit.ErrNormal)
397 return
398 }
399
400 toc, err := core.ResolveToCid(req.Context(), n.Namesys, r, to)
401 if err != nil {
394 - res.SetError(err, cmds.ErrNormal)
402 + res.SetError(err, cmdkit.ErrNormal)
403 return
404 }
405
406 err = n.Pinning.Update(req.Context(), fromc, toc, unpin)
407 if err != nil {
400 - res.SetError(err, cmds.ErrNormal)
408 + res.SetError(err, cmdkit.ErrNormal)
409 return
410 }
411
@@ -418,17 +426,17 @@ new pin and removing the old one.
426 }
427
428 var verifyPinCmd = &cmds.Command{
421 - Helptext: cmds.HelpText{
429 + Helptext: cmdkit.HelpText{
430 Tagline: "Verify that recursive pins are complete.",
431 },
424 - Options: []cmds.Option{
425 - cmds.BoolOption("verbose", "Also write the hashes of non-broken pins."),
426 - cmds.BoolOption("quiet", "q", "Write just hashes of broken pins."),
432 + Options: []cmdkit.Option{
433 + cmdkit.BoolOption("verbose", "Also write the hashes of non-broken pins."),
434 + cmdkit.BoolOption("quiet", "q", "Write just hashes of broken pins."),
435 },
436 Run: func(req cmds.Request, res cmds.Response) {
437 n, err := req.InvocContext().GetNode()
438 if err != nil {
431 - res.SetError(err, cmds.ErrNormal)
439 + res.SetError(err, cmdkit.ErrNormal)
440 return
441 }
442
@@ -436,7 +444,7 @@ var verifyPinCmd = &cmds.Command{
444 quiet, _, _ := res.Request().Option("quiet").Bool()
445
446 if verbose && quiet {
439 - res.SetError(fmt.Errorf("The --verbose and --quiet options can not be used at the same time"), cmds.ErrNormal)
447 + res.SetError(fmt.Errorf("The --verbose and --quiet options can not be used at the same time"), cmdkit.ErrNormal)
448 }
449
450 opts := pinVerifyOpts{
core/commands/ping.go
+27 -37
@@ -2,20 +2,20 @@ package commands
2
3 import (
4 "bytes"
5 + "context"
6 "fmt"
7 "io"
7 - "reflect"
8 "strings"
9 "time"
10
11 cmds "github.com/ipfs/go-ipfs/commands"
12 core "github.com/ipfs/go-ipfs/core"
13 +
14 pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore"
15 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
16 u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
15 - peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer"
16 -
17 - context "context"
17 ma "gx/ipfs/QmXY77cVe7rVRQXZZQRioukUM7aRW3BTcAgJe12MCtb3Ji/go-multiaddr"
18 + peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer"
19 )
20
21 const kPingTimeout = 10 * time.Second
@@ -27,7 +27,7 @@ type PingResult struct {
27 }
28
29 var PingCmd = &cmds.Command{
30 - Helptext: cmds.HelpText{
30 + Helptext: cmdkit.HelpText{
31 Tagline: "Send echo request packets to IPFS hosts.",
32 ShortDescription: `
33 'ipfs ping' is a tool to test sending data to other nodes. It finds nodes
@@ -35,61 +35,52 @@ via the routing system, sends pings, waits for pongs, and prints out round-
35 trip latency information.
36 `,
37 },
38 - Arguments: []cmds.Argument{
39 - cmds.StringArg("peer ID", true, true, "ID of peer to be pinged.").EnableStdin(),
38 + Arguments: []cmdkit.Argument{
39 + cmdkit.StringArg("peer ID", true, true, "ID of peer to be pinged.").EnableStdin(),
40 },
41 - Options: []cmds.Option{
42 - cmds.IntOption("count", "n", "Number of ping messages to send.").Default(10),
41 + Options: []cmdkit.Option{
42 + cmdkit.IntOption("count", "n", "Number of ping messages to send.").Default(10),
43 },
44 Marshalers: cmds.MarshalerMap{
45 cmds.Text: func(res cmds.Response) (io.Reader, error) {
46 - outChan, ok := res.Output().(<-chan interface{})
46 + v, err := unwrapOutput(res.Output())
47 + if err != nil {
48 + return nil, err
49 + }
50 +
51 + obj, ok := v.(*PingResult)
52 if !ok {
48 - fmt.Println(reflect.TypeOf(res.Output()))
53 return nil, u.ErrCast()
54 }
55
52 - marshal := func(v interface{}) (io.Reader, error) {
53 - obj, ok := v.(*PingResult)
54 - if !ok {
55 - return nil, u.ErrCast()
56 - }
57 -
58 - buf := new(bytes.Buffer)
59 - if len(obj.Text) > 0 {
60 - buf = bytes.NewBufferString(obj.Text + "\n")
61 - } else if obj.Success {
62 - fmt.Fprintf(buf, "Pong received: time=%.2f ms\n", obj.Time.Seconds()*1000)
63 - } else {
64 - fmt.Fprintf(buf, "Pong failed\n")
65 - }
66 - return buf, nil
56 + buf := new(bytes.Buffer)
57 + if len(obj.Text) > 0 {
58 + buf = bytes.NewBufferString(obj.Text + "\n")
59 + } else if obj.Success {
60 + fmt.Fprintf(buf, "Pong received: time=%.2f ms\n", obj.Time.Seconds()*1000)
61 + } else {
62 + fmt.Fprintf(buf, "Pong failed\n")
63 }
68 -
69 - return &cmds.ChannelMarshaler{
70 - Channel: outChan,
71 - Marshaler: marshal,
72 - Res: res,
73 - }, nil
64 + return buf, nil
65 },
66 },
67 Run: func(req cmds.Request, res cmds.Response) {
68 ctx := req.Context()
69 n, err := req.InvocContext().GetNode()
70 if err != nil {
80 - res.SetError(err, cmds.ErrNormal)
71 + res.SetError(err, cmdkit.ErrNormal)
72 return
73 }
74
75 // Must be online!
76 if !n.OnlineMode() {
86 - res.SetError(errNotOnline, cmds.ErrClient)
77 + res.SetError(errNotOnline, cmdkit.ErrClient)
78 return
79 }
80
81 addr, peerID, err := ParsePeerParam(req.Arguments()[0])
82 if err != nil {
92 - res.SetError(err, cmds.ErrNormal)
83 + res.SetError(err, cmdkit.ErrNormal)
84 return
85 }
86
@@ -99,7 +90,7 @@ trip latency information.
90
91 numPings, _, err := req.Option("count").Int()
92 if err != nil {
102 - res.SetError(err, cmds.ErrNormal)
93 + res.SetError(err, cmdkit.ErrNormal)
94 return
95 }
96
@@ -140,7 +131,6 @@ func pingPeer(ctx context.Context, n *core.IpfsNode, pid peer.ID, numPings int)
131 defer cancel()
132 pings, err := n.Ping.Ping(ctx, pid)
133 if err != nil {
143 - log.Debugf("Ping error: %s", err)
134 outChan <- &PingResult{
135 Success: false,
136 Text: fmt.Sprintf("Ping error: %s", err),
core/commands/publish.go
+29 -20
@@ -10,9 +10,11 @@ import (
10
11 cmds "github.com/ipfs/go-ipfs/commands"
12 core "github.com/ipfs/go-ipfs/core"
13 + e "github.com/ipfs/go-ipfs/core/commands/e"
14 keystore "github.com/ipfs/go-ipfs/keystore"
15 path "github.com/ipfs/go-ipfs/path"
16
17 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
18 peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer"
19 crypto "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto"
20 )
@@ -20,7 +22,7 @@ import (
22 var errNotOnline = errors.New("This command must be run in online mode. Try running 'ipfs daemon' first.")
23
24 var PublishCmd = &cmds.Command{
23 - Helptext: cmds.HelpText{
25 + Helptext: cmdkit.HelpText{
26 Tagline: "Publish IPNS names.",
27 ShortDescription: `
28 IPNS is a PKI namespace, where names are the hashes of public keys, and
@@ -59,43 +61,42 @@ Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
61 `,
62 },
63
62 - Arguments: []cmds.Argument{
63 - cmds.StringArg("ipfs-path", true, false, "ipfs path of the object to be published.").EnableStdin(),
64 + Arguments: []cmdkit.Argument{
65 + cmdkit.StringArg("ipfs-path", true, false, "ipfs path of the object to be published.").EnableStdin(),
66 },
65 - Options: []cmds.Option{
66 - cmds.BoolOption("resolve", "Resolve given path before publishing.").Default(true),
67 - cmds.StringOption("lifetime", "t",
67 + Options: []cmdkit.Option{
68 + cmdkit.BoolOption("resolve", "Resolve given path before publishing.").Default(true),
69 + cmdkit.StringOption("lifetime", "t",
70 `Time duration that the record will be valid for. <<default>>
71 This accepts durations such as "300s", "1.5h" or "2h45m". Valid time units are
72 "ns", "us" (or "µs"), "ms", "s", "m", "h".`).Default("24h"),
71 - cmds.StringOption("ttl", "Time duration this record should be cached for (caution: experimental)."),
72 - cmds.StringOption("key", "k", "Name of the key to be used or a valid PeerID, as listed by 'ipfs key list -l'. Default: <<default>>.").Default("self"),
73 + cmdkit.StringOption("ttl", "Time duration this record should be cached for (caution: experimental)."),
74 + cmdkit.StringOption("key", "k", "Name of the key to be used or a valid PeerID, as listed by 'ipfs key list -l'. Default: <<default>>.").Default("self"),
75 },
76 Run: func(req cmds.Request, res cmds.Response) {
75 - log.Debug("begin publish")
77 n, err := req.InvocContext().GetNode()
78 if err != nil {
78 - res.SetError(err, cmds.ErrNormal)
79 + res.SetError(err, cmdkit.ErrNormal)
80 return
81 }
82
83 if !n.OnlineMode() {
84 err := n.SetupOfflineRouting()
85 if err != nil {
85 - res.SetError(err, cmds.ErrNormal)
86 + res.SetError(err, cmdkit.ErrNormal)
87 return
88 }
89 }
90
91 if n.Mounts.Ipns != nil && n.Mounts.Ipns.IsActive() {
91 - res.SetError(errors.New("cannot manually publish while IPNS is mounted"), cmds.ErrNormal)
92 + res.SetError(errors.New("cannot manually publish while IPNS is mounted"), cmdkit.ErrNormal)
93 return
94 }
95
96 pstr := req.Arguments()[0]
97
98 if n.Identity == "" {
98 - res.SetError(errors.New("identity not loaded"), cmds.ErrNormal)
99 + res.SetError(errors.New("identity not loaded"), cmdkit.ErrNormal)
100 return
101 }
102
@@ -106,7 +107,7 @@ Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
107 validtime, _, _ := req.Option("lifetime").String()
108 d, err := time.ParseDuration(validtime)
109 if err != nil {
109 - res.SetError(fmt.Errorf("error parsing lifetime option: %s", err), cmds.ErrNormal)
110 + res.SetError(fmt.Errorf("error parsing lifetime option: %s", err), cmdkit.ErrNormal)
111 return
112 }
113
@@ -116,7 +117,7 @@ Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
117 if ttl, found, _ := req.Option("ttl").String(); found {
118 d, err := time.ParseDuration(ttl)
119 if err != nil {
119 - res.SetError(err, cmds.ErrNormal)
120 + res.SetError(err, cmdkit.ErrNormal)
121 return
122 }
123
@@ -126,27 +127,35 @@ Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
127 kname, _, _ := req.Option("key").String()
128 k, err := keylookup(n, kname)
129 if err != nil {
129 - res.SetError(err, cmds.ErrNormal)
130 + res.SetError(err, cmdkit.ErrNormal)
131 return
132 }
133
134 pth, err := path.ParsePath(pstr)
135 if err != nil {
135 - res.SetError(err, cmds.ErrNormal)
136 + res.SetError(err, cmdkit.ErrNormal)
137 return
138 }
139
140 output, err := publish(ctx, n, k, pth, popts)
141 if err != nil {
141 - res.SetError(err, cmds.ErrNormal)
142 + res.SetError(err, cmdkit.ErrNormal)
143 return
144 }
145 res.SetOutput(output)
146 },
147 Marshalers: cmds.MarshalerMap{
148 cmds.Text: func(res cmds.Response) (io.Reader, error) {
148 - v := res.Output().(*IpnsEntry)
149 - s := fmt.Sprintf("Published to %s: %s\n", v.Name, v.Value)
149 + v, err := unwrapOutput(res.Output())
150 + if err != nil {
151 + return nil, err
152 + }
153 + entry, ok := v.(*IpnsEntry)
154 + if !ok {
155 + return nil, e.TypeErr(entry, v)
156 + }
157 +
158 + s := fmt.Sprintf("Published to %s: %s\n", entry.Name, entry.Value)
159 return strings.NewReader(s), nil
160 },
161 },
core/commands/pubsub.go
+84 -106
@@ -1,27 +1,25 @@
1 package commands
2
3 import (
4 - "bytes"
4 "context"
5 "encoding/binary"
6 "fmt"
7 "io"
9 - "strings"
8 "sync"
9 "time"
10
13 - cmds "github.com/ipfs/go-ipfs/commands"
11 core "github.com/ipfs/go-ipfs/core"
15 - blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format"
12
13 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
14 pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore"
19 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
15 floodsub "gx/ipfs/QmUUSLfvihARhCxxgnjW4hmycJpPvzNu12Aaz6JWVdfnLg/go-libp2p-floodsub"
16 + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
17 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
18 + blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format"
19 )
20
21 var PubsubCmd = &cmds.Command{
24 - Helptext: cmds.HelpText{
22 + Helptext: cmdkit.HelpText{
23 Tagline: "An experimental publish-subscribe system on ipfs.",
24 ShortDescription: `
25 ipfs pubsub allows you to publish messages to a given topic, and also to
@@ -42,7 +40,7 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
40 }
41
42 var PubsubSubCmd = &cmds.Command{
45 - Helptext: cmds.HelpText{
43 + Helptext: cmdkit.HelpText{
44 Tagline: "Subscribe to messages on a given topic.",
45 ShortDescription: `
46 ipfs pubsub sub subscribes to messages on a given topic.
@@ -65,58 +63,37 @@ This command outputs data in the following encodings:
63 (Specified by the "--encoding" or "--enc" flag)
64 `,
65 },
68 - Arguments: []cmds.Argument{
69 - cmds.StringArg("topic", true, false, "String name of topic to subscribe to."),
66 + Arguments: []cmdkit.Argument{
67 + cmdkit.StringArg("topic", true, false, "String name of topic to subscribe to."),
68 },
71 - Options: []cmds.Option{
72 - cmds.BoolOption("discover", "try to discover other peers subscribed to the same topic"),
69 + Options: []cmdkit.Option{
70 + cmdkit.BoolOption("discover", "try to discover other peers subscribed to the same topic"),
71 },
74 - Run: func(req cmds.Request, res cmds.Response) {
72 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
73 n, err := req.InvocContext().GetNode()
74 if err != nil {
77 - res.SetError(err, cmds.ErrNormal)
75 + res.SetError(err, cmdkit.ErrNormal)
76 return
77 }
78
79 // Must be online!
80 if !n.OnlineMode() {
83 - res.SetError(errNotOnline, cmds.ErrClient)
81 + res.SetError(errNotOnline, cmdkit.ErrClient)
82 return
83 }
84
85 if n.Floodsub == nil {
88 - res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmds.ErrNormal)
86 + res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmdkit.ErrNormal)
87 return
88 }
89
90 topic := req.Arguments()[0]
91 sub, err := n.Floodsub.Subscribe(topic)
92 if err != nil {
95 - res.SetError(err, cmds.ErrNormal)
93 + res.SetError(err, cmdkit.ErrNormal)
94 return
95 }
98 -
99 - out := make(chan interface{})
100 - res.SetOutput((<-chan interface{})(out))
101 -
102 - go func() {
103 - defer sub.Cancel()
104 - defer close(out)
105 -
106 - out <- floodsub.Message{}
107 -
108 - for {
109 - msg, err := sub.Next(req.Context())
110 - if err == io.EOF || err == context.Canceled {
111 - return
112 - } else if err != nil {
113 - res.SetError(err, cmds.ErrNormal)
114 - return
115 - }
116 -
117 - out <- msg
118 - }
119 - }()
96 + defer sub.Cancel()
97
98 discover, _, _ := req.Option("discover").Bool()
99 if discover {
@@ -131,20 +108,51 @@ This command outputs data in the following encodings:
108 connectToPubSubPeers(req.Context(), n, cid)
109 }()
110 }
111 +
112 + for {
113 + msg, err := sub.Next(req.Context())
114 + if err == io.EOF || err == context.Canceled {
115 + return
116 + } else if err != nil {
117 + res.SetError(err, cmdkit.ErrNormal)
118 + return
119 + }
120 +
121 + res.Emit(msg)
122 + }
123 },
135 - Marshalers: cmds.MarshalerMap{
136 - cmds.Text: getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) {
137 - return bytes.NewReader(m.Data), nil
124 + Encoders: cmds.EncoderMap{
125 + cmds.Text: cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error {
126 + m, ok := v.(*floodsub.Message)
127 + if !ok {
128 + return fmt.Errorf("unexpected type: %T", v)
129 + }
130 +
131 + _, err := w.Write(m.Data)
132 + return err
133 }),
139 - "ndpayload": getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) {
134 + "ndpayload": cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error {
135 + m, ok := v.(*floodsub.Message)
136 + if !ok {
137 + return fmt.Errorf("unexpected type: %T", v)
138 + }
139 +
140 m.Data = append(m.Data, '\n')
141 - return bytes.NewReader(m.Data), nil
141 + _, err := w.Write(m.Data)
142 + return err
143 }),
143 - "lenpayload": getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) {
144 - buf := make([]byte, 8)
144 + "lenpayload": cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error {
145 + m, ok := v.(*floodsub.Message)
146 + if !ok {
147 + return fmt.Errorf("unexpected type: %T", v)
148 + }
149 +
150 + buf := make([]byte, 8, len(m.Data)+8)
151
152 n := binary.PutUvarint(buf, uint64(len(m.Data)))
147 - return io.MultiReader(bytes.NewReader(buf[:n]), bytes.NewReader(m.Data)), nil
153 + buf = append(buf[:n], m.Data...)
154 + _, err := w.Write(buf)
155 + return err
156 }),
157 },
158 Type: floodsub.Message{},
@@ -174,35 +182,8 @@ func connectToPubSubPeers(ctx context.Context, n *core.IpfsNode, cid *cid.Cid) {
182 wg.Wait()
183 }
184
177 -func getPsMsgMarshaler(f func(m *floodsub.Message) (io.Reader, error)) func(cmds.Response) (io.Reader, error) {
178 - return func(res cmds.Response) (io.Reader, error) {
179 - outChan, ok := res.Output().(<-chan interface{})
180 - if !ok {
181 - return nil, u.ErrCast()
182 - }
183 -
184 - marshal := func(v interface{}) (io.Reader, error) {
185 - obj, ok := v.(*floodsub.Message)
186 - if !ok {
187 - return nil, u.ErrCast()
188 - }
189 - if obj.Message == nil {
190 - return strings.NewReader(""), nil
191 - }
192 -
193 - return f(obj)
194 - }
195 -
196 - return &cmds.ChannelMarshaler{
197 - Channel: outChan,
198 - Marshaler: marshal,
199 - Res: res,
200 - }, nil
201 - }
202 -}
203 -
185 var PubsubPubCmd = &cmds.Command{
205 - Helptext: cmds.HelpText{
186 + Helptext: cmdkit.HelpText{
187 Tagline: "Publish a message to a given pubsub topic.",
188 ShortDescription: `
189 ipfs pubsub pub publishes a message to a specified topic.
@@ -213,25 +194,25 @@ to be used in a production environment.
194 To use, the daemon must be run with '--enable-pubsub-experiment'.
195 `,
196 },
216 - Arguments: []cmds.Argument{
217 - cmds.StringArg("topic", true, false, "Topic to publish to."),
218 - cmds.StringArg("data", true, true, "Payload of message to publish.").EnableStdin(),
197 + Arguments: []cmdkit.Argument{
198 + cmdkit.StringArg("topic", true, false, "Topic to publish to."),
199 + cmdkit.StringArg("data", true, true, "Payload of message to publish.").EnableStdin(),
200 },
220 - Run: func(req cmds.Request, res cmds.Response) {
201 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
202 n, err := req.InvocContext().GetNode()
203 if err != nil {
223 - res.SetError(err, cmds.ErrNormal)
204 + res.SetError(err, cmdkit.ErrNormal)
205 return
206 }
207
208 // Must be online!
209 if !n.OnlineMode() {
229 - res.SetError(errNotOnline, cmds.ErrClient)
210 + res.SetError(errNotOnline, cmdkit.ErrClient)
211 return
212 }
213
214 if n.Floodsub == nil {
234 - res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmds.ErrNormal)
215 + res.SetError("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.", cmdkit.ErrNormal)
216 return
217 }
218
@@ -239,7 +220,7 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
220
221 for _, data := range req.Arguments()[1:] {
222 if err := n.Floodsub.Publish(topic, []byte(data)); err != nil {
242 - res.SetError(err, cmds.ErrNormal)
223 + res.SetError(err, cmdkit.ErrNormal)
224 return
225 }
226 }
@@ -247,7 +228,7 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
228 }
229
230 var PubsubLsCmd = &cmds.Command{
250 - Helptext: cmds.HelpText{
231 + Helptext: cmdkit.HelpText{
232 Tagline: "List subscribed topics by name.",
233 ShortDescription: `
234 ipfs pubsub ls lists out the names of topics you are currently subscribed to.
@@ -258,34 +239,33 @@ to be used in a production environment.
239 To use, the daemon must be run with '--enable-pubsub-experiment'.
240 `,
241 },
261 - Run: func(req cmds.Request, res cmds.Response) {
242 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
243 n, err := req.InvocContext().GetNode()
244 if err != nil {
264 - res.SetError(err, cmds.ErrNormal)
245 + res.SetError(err, cmdkit.ErrNormal)
246 return
247 }
248
249 // Must be online!
250 if !n.OnlineMode() {
270 - res.SetError(errNotOnline, cmds.ErrClient)
251 + res.SetError(errNotOnline, cmdkit.ErrClient)
252 return
253 }
254
255 if n.Floodsub == nil {
275 - res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmds.ErrNormal)
256 + res.SetError("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.", cmdkit.ErrNormal)
257 return
258 }
259
279 - res.SetOutput(&stringList{n.Floodsub.GetTopics()})
280 - },
281 - Type: stringList{},
282 - Marshalers: cmds.MarshalerMap{
283 - cmds.Text: stringListMarshaler,
260 + for _, topic := range n.Floodsub.GetTopics() {
261 + res.Emit(topic)
262 + }
263 },
264 + Type: "",
265 }
266
267 var PubsubPeersCmd = &cmds.Command{
288 - Helptext: cmds.HelpText{
268 + Helptext: cmdkit.HelpText{
269 Tagline: "List peers we are currently pubsubbing with.",
270 ShortDescription: `
271 ipfs pubsub peers with no arguments lists out the pubsub peers you are
@@ -298,24 +278,24 @@ to be used in a production environment.
278 To use, the daemon must be run with '--enable-pubsub-experiment'.
279 `,
280 },
301 - Arguments: []cmds.Argument{
302 - cmds.StringArg("topic", false, false, "topic to list connected peers of"),
281 + Arguments: []cmdkit.Argument{
282 + cmdkit.StringArg("topic", false, false, "topic to list connected peers of"),
283 },
304 - Run: func(req cmds.Request, res cmds.Response) {
284 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
285 n, err := req.InvocContext().GetNode()
286 if err != nil {
307 - res.SetError(err, cmds.ErrNormal)
287 + res.SetError(err, cmdkit.ErrNormal)
288 return
289 }
290
291 // Must be online!
292 if !n.OnlineMode() {
313 - res.SetError(errNotOnline, cmds.ErrClient)
293 + res.SetError(errNotOnline, cmdkit.ErrClient)
294 return
295 }
296
297 if n.Floodsub == nil {
318 - res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmds.ErrNormal)
298 + res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmdkit.ErrNormal)
299 return
300 }
301
@@ -324,14 +304,12 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
304 topic = req.Arguments()[0]
305 }
306
327 - var out []string
328 - for _, p := range n.Floodsub.ListPeers(topic) {
329 - out = append(out, p.Pretty())
307 + for _, peer := range n.Floodsub.ListPeers(topic) {
308 + res.Emit(peer.Pretty())
309 }
331 - res.SetOutput(&stringList{out})
310 },
333 - Type: stringList{},
334 - Marshalers: cmds.MarshalerMap{
335 - cmds.Text: stringListMarshaler,
311 + Type: "",
312 + Encoders: cmds.EncoderMap{
313 + cmds.Text: cmds.Encoders[cmds.TextNewline],
314 },
315 }
core/commands/refs.go
+40 -38
@@ -9,12 +9,13 @@ import (
9
10 cmds "github.com/ipfs/go-ipfs/commands"
11 "github.com/ipfs/go-ipfs/core"
12 + e "github.com/ipfs/go-ipfs/core/commands/e"
13 dag "github.com/ipfs/go-ipfs/merkledag"
14 path "github.com/ipfs/go-ipfs/path"
15
16 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
17 node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format"
17 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
18 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
19 )
20
21 // KeyList is a general type for outputting lists of keys
@@ -24,7 +25,16 @@ type KeyList struct {
25
26 // KeyListTextMarshaler outputs a KeyList as plaintext, one key per line
27 func KeyListTextMarshaler(res cmds.Response) (io.Reader, error) {
27 - output := res.Output().(*KeyList)
28 + out, err := unwrapOutput(res.Output())
29 + if err != nil {
30 + return nil, err
31 + }
32 +
33 + output, ok := out.(*KeyList)
34 + if !ok {
35 + return nil, e.TypeErr(output, out)
36 + }
37 +
38 buf := new(bytes.Buffer)
39 for _, key := range output.Keys {
40 buf.WriteString(key.String() + "\n")
@@ -33,7 +43,7 @@ func KeyListTextMarshaler(res cmds.Response) (io.Reader, error) {
43 }
44
45 var RefsCmd = &cmds.Command{
36 - Helptext: cmds.HelpText{
46 + Helptext: cmdkit.HelpText{
47 Tagline: "List links (references) from an object.",
48 ShortDescription: `
49 Lists the hashes of all the links an IPFS or IPNS object(s) contains,
@@ -47,50 +57,50 @@ NOTE: List all references recursively by using the flag '-r'.
57 Subcommands: map[string]*cmds.Command{
58 "local": RefsLocalCmd,
59 },
50 - Arguments: []cmds.Argument{
51 - cmds.StringArg("ipfs-path", true, true, "Path to the object(s) to list refs from.").EnableStdin(),
60 + Arguments: []cmdkit.Argument{
61 + cmdkit.StringArg("ipfs-path", true, true, "Path to the object(s) to list refs from.").EnableStdin(),
62 },
53 - Options: []cmds.Option{
54 - cmds.StringOption("format", "Emit edges with given format. Available tokens: <src> <dst> <linkname>.").Default("<dst>"),
55 - cmds.BoolOption("edges", "e", "Emit edge format: `<from> -> <to>`.").Default(false),
56 - cmds.BoolOption("unique", "u", "Omit duplicate refs from output.").Default(false),
57 - cmds.BoolOption("recursive", "r", "Recursively list links of child nodes.").Default(false),
63 + Options: []cmdkit.Option{
64 + cmdkit.StringOption("format", "Emit edges with given format. Available tokens: <src> <dst> <linkname>.").Default("<dst>"),
65 + cmdkit.BoolOption("edges", "e", "Emit edge format: `<from> -> <to>`.").Default(false),
66 + cmdkit.BoolOption("unique", "u", "Omit duplicate refs from output.").Default(false),
67 + cmdkit.BoolOption("recursive", "r", "Recursively list links of child nodes.").Default(false),
68 },
69 Run: func(req cmds.Request, res cmds.Response) {
70 ctx := req.Context()
71 n, err := req.InvocContext().GetNode()
72 if err != nil {
63 - res.SetError(err, cmds.ErrNormal)
73 + res.SetError(err, cmdkit.ErrNormal)
74 return
75 }
76
77 unique, _, err := req.Option("unique").Bool()
78 if err != nil {
69 - res.SetError(err, cmds.ErrNormal)
79 + res.SetError(err, cmdkit.ErrNormal)
80 return
81 }
82
83 recursive, _, err := req.Option("recursive").Bool()
84 if err != nil {
75 - res.SetError(err, cmds.ErrNormal)
85 + res.SetError(err, cmdkit.ErrNormal)
86 return
87 }
88
89 format, _, err := req.Option("format").String()
90 if err != nil {
81 - res.SetError(err, cmds.ErrNormal)
91 + res.SetError(err, cmdkit.ErrNormal)
92 return
93 }
94
95 edges, _, err := req.Option("edges").Bool()
96 if err != nil {
87 - res.SetError(err, cmds.ErrNormal)
97 + res.SetError(err, cmdkit.ErrNormal)
98 return
99 }
100 if edges {
101 if format != "<dst>" {
102 res.SetError(errors.New("using format arguement with edges is not allowed"),
93 - cmds.ErrClient)
103 + cmdkit.ErrClient)
104 return
105 }
106
@@ -99,7 +109,7 @@ NOTE: List all references recursively by using the flag '-r'.
109
110 objs, err := objectsForPaths(ctx, n, req.Arguments())
111 if err != nil {
102 - res.SetError(err, cmds.ErrNormal)
112 + res.SetError(err, cmdkit.ErrNormal)
113 return
114 }
115
@@ -131,7 +141,7 @@ NOTE: List all references recursively by using the flag '-r'.
141 }
142
143 var RefsLocalCmd = &cmds.Command{
134 - Helptext: cmds.HelpText{
144 + Helptext: cmdkit.HelpText{
145 Tagline: "List all local references.",
146 ShortDescription: `
147 Displays the hashes of all local objects.
@@ -142,14 +152,14 @@ Displays the hashes of all local objects.
152 ctx := req.Context()
153 n, err := req.InvocContext().GetNode()
154 if err != nil {
145 - res.SetError(err, cmds.ErrNormal)
155 + res.SetError(err, cmdkit.ErrNormal)
156 return
157 }
158
159 // todo: make async
160 allKeys, err := n.Blockstore.AllKeysChan(ctx)
161 if err != nil {
152 - res.SetError(err, cmds.ErrNormal)
162 + res.SetError(err, cmdkit.ErrNormal)
163 return
164 }
165
@@ -170,29 +180,21 @@ Displays the hashes of all local objects.
180
181 var refsMarshallerMap = cmds.MarshalerMap{
182 cmds.Text: func(res cmds.Response) (io.Reader, error) {
173 - outChan, ok := res.Output().(<-chan interface{})
174 - if !ok {
175 - return nil, u.ErrCast()
183 + v, err := unwrapOutput(res.Output())
184 + if err != nil {
185 + return nil, err
186 }
187
178 - marshal := func(v interface{}) (io.Reader, error) {
179 - obj, ok := v.(*RefWrapper)
180 - if !ok {
181 - return nil, u.ErrCast()
182 - }
183 -
184 - if obj.Err != "" {
185 - return nil, errors.New(obj.Err)
186 - }
188 + obj, ok := v.(*RefWrapper)
189 + if !ok {
190 + return nil, e.TypeErr(obj, v)
191 + }
192
188 - return strings.NewReader(obj.Ref + "\n"), nil
193 + if obj.Err != "" {
194 + return nil, errors.New(obj.Err)
195 }
196
191 - return &cmds.ChannelMarshaler{
192 - Channel: outChan,
193 - Marshaler: marshal,
194 - Res: res,
195 - }, nil
197 + return strings.NewReader(obj.Ref + "\n"), nil
198 },
199 }
200
core/commands/repo.go
+132 -131
@@ -10,14 +10,16 @@ import (
10 "text/tabwriter"
11
12 bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
13 - cmds "github.com/ipfs/go-ipfs/commands"
13 + oldcmds "github.com/ipfs/go-ipfs/commands"
14 + e "github.com/ipfs/go-ipfs/core/commands/e"
15 corerepo "github.com/ipfs/go-ipfs/core/corerepo"
16 config "github.com/ipfs/go-ipfs/repo/config"
17 fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
18 lockfile "github.com/ipfs/go-ipfs/repo/fsrepo/lock"
19
20 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
20 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
21 + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
22 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
23 )
24
25 type RepoVersion struct {
@@ -25,7 +27,7 @@ type RepoVersion struct {
27 }
28
29 var RepoCmd = &cmds.Command{
28 - Helptext: cmds.HelpText{
30 + Helptext: cmdkit.HelpText{
31 Tagline: "Manipulate the IPFS repo.",
32 ShortDescription: `
33 'ipfs repo' is a plumbing command used to manipulate the repo.
@@ -33,8 +35,10 @@ var RepoCmd = &cmds.Command{
35 },
36
37 Subcommands: map[string]*cmds.Command{
38 + "stat": repoStatCmd,
39 + },
40 + OldSubcommands: map[string]*oldcmds.Command{
41 "gc": repoGcCmd,
37 - "stat": repoStatCmd,
42 "fsck": RepoFsckCmd,
43 "version": repoVersionCmd,
44 "verify": repoVerifyCmd,
@@ -47,8 +51,8 @@ type GcResult struct {
51 Error string `json:",omitempty"`
52 }
53
50 -var repoGcCmd = &cmds.Command{
51 - Helptext: cmds.HelpText{
54 +var repoGcCmd = &oldcmds.Command{
55 + Helptext: cmdkit.HelpText{
56 Tagline: "Perform a garbage collection sweep on the repo.",
57 ShortDescription: `
58 'ipfs repo gc' is a plumbing command that will sweep the local
@@ -56,14 +60,14 @@ set of stored objects and remove ones that are not pinned in
60 order to reclaim hard disk space.
61 `,
62 },
59 - Options: []cmds.Option{
60 - cmds.BoolOption("quiet", "q", "Write minimal output.").Default(false),
61 - cmds.BoolOption("stream-errors", "Stream errors.").Default(false),
63 + Options: []cmdkit.Option{
64 + cmdkit.BoolOption("stream-errors", "Stream errors.").Default(false),
65 + cmdkit.BoolOption("quiet", "q", "Write minimal output.").Default(false),
66 },
63 - Run: func(req cmds.Request, res cmds.Response) {
67 + Run: func(req oldcmds.Request, res oldcmds.Response) {
68 n, err := req.InvocContext().GetNode()
69 if err != nil {
66 - res.SetError(err, cmds.ErrNormal)
70 + res.SetError(err, cmdkit.ErrNormal)
71 return
72 }
73
@@ -71,11 +75,12 @@ order to reclaim hard disk space.
75
76 gcOutChan := corerepo.GarbageCollectAsync(n, req.Context())
77
74 - outChan := make(chan interface{}, cap(gcOutChan))
75 - res.SetOutput((<-chan interface{})(outChan))
78 + outChan := make(chan interface{})
79 + res.SetOutput(outChan)
80
81 go func() {
82 defer close(outChan)
83 +
84 if streamErrors {
85 errs := false
86 for res := range gcOutChan {
@@ -87,24 +92,24 @@ order to reclaim hard disk space.
92 }
93 }
94 if errs {
90 - res.SetError(fmt.Errorf("encountered errors during gc run"), cmds.ErrNormal)
95 + res.SetError(fmt.Errorf("encountered errors during gc run"), cmdkit.ErrNormal)
96 }
97 } else {
98 err := corerepo.CollectResult(req.Context(), gcOutChan, func(k *cid.Cid) {
99 outChan <- &GcResult{Key: k}
100 })
101 if err != nil {
97 - res.SetError(err, cmds.ErrNormal)
102 + res.SetError(err, cmdkit.ErrNormal)
103 }
104 }
105 }()
106 },
107 Type: GcResult{},
103 - Marshalers: cmds.MarshalerMap{
104 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
105 - outChan, ok := res.Output().(<-chan interface{})
106 - if !ok {
107 - return nil, u.ErrCast()
108 + Marshalers: oldcmds.MarshalerMap{
109 + oldcmds.Text: func(res oldcmds.Response) (io.Reader, error) {
110 + v, err := unwrapOutput(res.Output())
111 + if err != nil {
112 + return nil, err
113 }
114
115 quiet, _, err := res.Request().Option("quiet").Bool()
@@ -112,35 +117,28 @@ order to reclaim hard disk space.
117 return nil, err
118 }
119
115 - marshal := func(v interface{}) (io.Reader, error) {
116 - obj, ok := v.(*GcResult)
117 - if !ok {
118 - return nil, u.ErrCast()
119 - }
120 + obj, ok := v.(*GcResult)
121 + if !ok {
122 + return nil, e.TypeErr(obj, v)
123 + }
124
121 - if obj.Error != "" {
122 - fmt.Fprintf(res.Stderr(), "Error: %s\n", obj.Error)
123 - return nil, nil
124 - }
125 + if obj.Error != "" {
126 + fmt.Fprintf(res.Stderr(), "Error: %s\n", obj.Error)
127 + return nil, nil
128 + }
129
126 - if quiet {
127 - return bytes.NewBufferString(obj.Key.String() + "\n"), nil
128 - } else {
129 - return bytes.NewBufferString(fmt.Sprintf("removed %s\n", obj.Key)), nil
130 - }
130 + msg := obj.Key.String() + "\n"
131 + if !quiet {
132 + msg = "removed " + msg
133 }
134
133 - return &cmds.ChannelMarshaler{
134 - Channel: outChan,
135 - Marshaler: marshal,
136 - Res: res,
137 - }, nil
135 + return bytes.NewBufferString(msg), nil
136 },
137 },
138 }
139
140 var repoStatCmd = &cmds.Command{
143 - Helptext: cmds.HelpText{
141 + Helptext: cmdkit.HelpText{
142 Tagline: "Get stats for the currently used repo.",
143 ShortDescription: `
144 'ipfs repo stat' is a plumbing command that will scan the local
@@ -151,39 +149,39 @@ RepoSize int Size in bytes that the repo is currently taking.
149 Version string The repo version.
150 `,
151 },
154 - Run: func(req cmds.Request, res cmds.Response) {
152 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
153 n, err := req.InvocContext().GetNode()
154 if err != nil {
157 - res.SetError(err, cmds.ErrNormal)
155 + res.SetError(err, cmdkit.ErrNormal)
156 return
157 }
158
159 stat, err := corerepo.RepoStat(n, req.Context())
160 if err != nil {
163 - res.SetError(err, cmds.ErrNormal)
161 + res.SetError(err, cmdkit.ErrNormal)
162 return
163 }
164
167 - res.SetOutput(stat)
165 + res.Emit(stat)
166 },
169 - Options: []cmds.Option{
170 - cmds.BoolOption("human", "Output RepoSize in MiB.").Default(false),
167 + Options: []cmdkit.Option{
168 + cmdkit.BoolOption("human", "Output RepoSize in MiB.").Default(false),
169 },
170 Type: corerepo.Stat{},
173 - Marshalers: cmds.MarshalerMap{
174 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
175 - stat, ok := res.Output().(*corerepo.Stat)
171 + Encoders: cmds.EncoderMap{
172 + cmds.Text: cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error {
173 + stat, ok := v.(*corerepo.Stat)
174 if !ok {
177 - return nil, u.ErrCast()
175 + return e.TypeErr(stat, v)
176 }
177
180 - human, _, err := res.Request().Option("human").Bool()
178 + human, _, err := req.Option("human").Bool()
179 if err != nil {
182 - return nil, err
180 + return err
181 }
182
185 - buf := new(bytes.Buffer)
186 - wtr := tabwriter.NewWriter(buf, 0, 0, 1, ' ', 0)
183 + wtr := tabwriter.NewWriter(w, 0, 0, 1, ' ', 0)
184 +
185 fmt.Fprintf(wtr, "NumObjects:\t%d\n", stat.NumObjects)
186 sizeInMiB := stat.RepoSize / (1024 * 1024)
187 if human && sizeInMiB > 0 {
@@ -203,13 +201,14 @@ Version string The repo version.
201 fmt.Fprintf(wtr, "Version:\t%s\n", stat.Version)
202 wtr.Flush()
203
206 - return buf, nil
207 - },
204 + return nil
205 +
206 + }),
207 },
208 }
209
211 -var RepoFsckCmd = &cmds.Command{
212 - Helptext: cmds.HelpText{
210 +var RepoFsckCmd = &oldcmds.Command{
211 + Helptext: cmdkit.HelpText{
212 Tagline: "Remove repo lockfiles.",
213 ShortDescription: `
214 'ipfs repo fsck' is a plumbing command that will remove repo and level db
@@ -217,12 +216,12 @@ lockfiles, as well as the api file. This command can only run when no ipfs
216 daemons are running.
217 `,
218 },
220 - Run: func(req cmds.Request, res cmds.Response) {
219 + Run: func(req oldcmds.Request, res oldcmds.Response) {
220 configRoot := req.InvocContext().ConfigRoot
221
222 dsPath, err := config.DataStorePath(configRoot)
223 if err != nil {
225 - res.SetError(err, cmds.ErrNormal)
224 + res.SetError(err, cmdkit.ErrNormal)
225 return
226 }
227
@@ -236,135 +235,137 @@ daemons are running.
235
236 err = os.Remove(repoLockFile)
237 if err != nil && !os.IsNotExist(err) {
239 - res.SetError(err, cmds.ErrNormal)
238 + res.SetError(err, cmdkit.ErrNormal)
239 return
240 }
241 err = os.Remove(dsLockFile)
242 if err != nil && !os.IsNotExist(err) {
244 - res.SetError(err, cmds.ErrNormal)
243 + res.SetError(err, cmdkit.ErrNormal)
244 return
245 }
246 err = os.Remove(apiFile)
247 if err != nil && !os.IsNotExist(err) {
249 - res.SetError(err, cmds.ErrNormal)
248 + res.SetError(err, cmdkit.ErrNormal)
249 return
250 }
251
252 res.SetOutput(&MessageOutput{"Lockfiles have been removed.\n"})
253 },
254 Type: MessageOutput{},
256 - Marshalers: cmds.MarshalerMap{
257 - cmds.Text: MessageTextMarshaler,
255 + Marshalers: oldcmds.MarshalerMap{
256 + oldcmds.Text: MessageTextMarshaler,
257 },
258 }
259
260 type VerifyProgress struct {
262 - Message string
261 + Msg string
262 Progress int
263 }
264
266 -var repoVerifyCmd = &cmds.Command{
267 - Helptext: cmds.HelpText{
265 +var repoVerifyCmd = &oldcmds.Command{
266 + Helptext: cmdkit.HelpText{
267 Tagline: "Verify all blocks in repo are not corrupted.",
268 },
270 - Run: func(req cmds.Request, res cmds.Response) {
269 + Run: func(req oldcmds.Request, res oldcmds.Response) {
270 nd, err := req.InvocContext().GetNode()
271 if err != nil {
273 - res.SetError(err, cmds.ErrNormal)
272 + res.SetError(err, cmdkit.ErrNormal)
273 return
274 }
275
276 out := make(chan interface{})
278 - go func() {
279 - defer close(out)
280 - bs := bstore.NewBlockstore(nd.Repo.Datastore())
277 + res.SetOutput((<-chan interface{})(out))
278 + defer close(out)
279
282 - bs.HashOnRead(true)
280 + bs := bstore.NewBlockstore(nd.Repo.Datastore())
281 + bs.HashOnRead(true)
282
284 - keys, err := bs.AllKeysChan(req.Context())
283 + keys, err := bs.AllKeysChan(req.Context())
284 + if err != nil {
285 + log.Error(err)
286 + return
287 + }
288 +
289 + var fails int
290 + var i int
291 + for k := range keys {
292 + _, err := bs.Get(k)
293 if err != nil {
286 - log.Error(err)
287 - return
294 + out <- &VerifyProgress{
295 + Msg: fmt.Sprintf("block %s was corrupt (%s)", k, err),
296 + }
297 + fails++
298 }
299 + i++
300 + out <- &VerifyProgress{Progress: i}
301 + }
302
290 - var fails int
291 - var i int
292 - for k := range keys {
293 - _, err := bs.Get(k)
294 - if err != nil {
295 - out <- &VerifyProgress{
296 - Message: fmt.Sprintf("block %s was corrupt (%s)", k, err),
297 - }
298 - fails++
299 - }
300 - i++
301 - out <- &VerifyProgress{Progress: i}
303 + if fails == 0 {
304 + out <- &VerifyProgress{Msg: "verify complete, all blocks validated."}
305 + } else {
306 + res.SetError(fmt.Errorf("verify complete, some blocks were corrupt"), cmdkit.ErrNormal)
307 + }
308 + },
309 + Type: &VerifyProgress{},
310 + Marshalers: oldcmds.MarshalerMap{
311 + oldcmds.Text: func(res oldcmds.Response) (io.Reader, error) {
312 + v, err := unwrapOutput(res.Output())
313 + if err != nil {
314 + return nil, err
315 }
303 - if fails == 0 {
304 - out <- &VerifyProgress{Message: "verify complete, all blocks validated."}
305 - } else {
306 - out <- &VerifyProgress{Message: "verify complete, some blocks were corrupt."}
316 +
317 + obj, ok := v.(*VerifyProgress)
318 + if !ok {
319 + return nil, e.TypeErr(obj, v)
320 }
308 - }()
321
310 - res.SetOutput((<-chan interface{})(out))
311 - },
312 - Type: VerifyProgress{},
313 - Marshalers: cmds.MarshalerMap{
314 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
315 - out := res.Output().(<-chan interface{})
316 -
317 - marshal := func(v interface{}) (io.Reader, error) {
318 - obj, ok := v.(*VerifyProgress)
319 - if !ok {
320 - return nil, u.ErrCast()
321 - }
322 + buf := new(bytes.Buffer)
323 + if strings.Contains(obj.Msg, "was corrupt") {
324 + fmt.Fprintln(os.Stdout, obj.Msg)
325 + return buf, nil
326 + }
327
323 - buf := new(bytes.Buffer)
324 - if obj.Message != "" {
325 - if strings.Contains(obj.Message, "blocks were corrupt") {
326 - return nil, fmt.Errorf(obj.Message)
327 - }
328 - if len(obj.Message) < 20 {
329 - obj.Message += " "
330 - }
331 - fmt.Fprintln(buf, obj.Message)
332 - return buf, nil
328 + if obj.Msg != "" {
329 + if len(obj.Msg) < 20 {
330 + obj.Msg += " "
331 }
334 -
335 - fmt.Fprintf(buf, "%d blocks processed.\r", obj.Progress)
332 + fmt.Fprintln(buf, obj.Msg)
333 return buf, nil
334 }
335
339 - return &cmds.ChannelMarshaler{
340 - Channel: out,
341 - Marshaler: marshal,
342 - Res: res,
343 - }, nil
336 + fmt.Fprintf(buf, "%d blocks processed.\r", obj.Progress)
337 + return buf, nil
338 },
339 },
340 }
341
348 -var repoVersionCmd = &cmds.Command{
349 - Helptext: cmds.HelpText{
342 +var repoVersionCmd = &oldcmds.Command{
343 + Helptext: cmdkit.HelpText{
344 Tagline: "Show the repo version.",
345 ShortDescription: `
346 'ipfs repo version' returns the current repo version.
347 `,
348 },
349
356 - Options: []cmds.Option{
357 - cmds.BoolOption("quiet", "q", "Write minimal output."),
350 + Options: []cmdkit.Option{
351 + cmdkit.BoolOption("quiet", "q", "Write minimal output."),
352 },
359 - Run: func(req cmds.Request, res cmds.Response) {
353 + Run: func(req oldcmds.Request, res oldcmds.Response) {
354 res.SetOutput(&RepoVersion{
355 Version: fmt.Sprint(fsrepo.RepoVersion),
356 })
357 },
358 Type: RepoVersion{},
365 - Marshalers: cmds.MarshalerMap{
366 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
367 - response := res.Output().(*RepoVersion)
359 + Marshalers: oldcmds.MarshalerMap{
360 + oldcmds.Text: func(res oldcmds.Response) (io.Reader, error) {
361 + v, err := unwrapOutput(res.Output())
362 + if err != nil {
363 + return nil, err
364 + }
365 + response, ok := v.(*RepoVersion)
366 + if !ok {
367 + return nil, e.TypeErr(response, v)
368 + }
369
370 quiet, _, err := res.Request().Option("quiet").Bool()
371 if err != nil {
core/commands/resolve.go
+20 -13
@@ -6,9 +6,11 @@ import (
6
7 cmds "github.com/ipfs/go-ipfs/commands"
8 "github.com/ipfs/go-ipfs/core"
9 + e "github.com/ipfs/go-ipfs/core/commands/e"
10 ns "github.com/ipfs/go-ipfs/namesys"
11 path "github.com/ipfs/go-ipfs/path"
11 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
12 +
13 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
14 )
15
16 type ResolvedPath struct {
@@ -16,7 +18,7 @@ type ResolvedPath struct {
18 }
19
20 var ResolveCmd = &cmds.Command{
19 - Helptext: cmds.HelpText{
21 + Helptext: cmdkit.HelpText{
22 Tagline: "Resolve the value of names to IPFS.",
23 ShortDescription: `
24 There are a number of mutable name protocols that can link among
@@ -55,24 +57,24 @@ Resolve the value of an IPFS DAG path:
57 `,
58 },
59
58 - Arguments: []cmds.Argument{
59 - cmds.StringArg("name", true, false, "The name to resolve.").EnableStdin(),
60 + Arguments: []cmdkit.Argument{
61 + cmdkit.StringArg("name", true, false, "The name to resolve.").EnableStdin(),
62 },
61 - Options: []cmds.Option{
62 - cmds.BoolOption("recursive", "r", "Resolve until the result is an IPFS name.").Default(false),
63 + Options: []cmdkit.Option{
64 + cmdkit.BoolOption("recursive", "r", "Resolve until the result is an IPFS name.").Default(false),
65 },
66 Run: func(req cmds.Request, res cmds.Response) {
67
68 n, err := req.InvocContext().GetNode()
69 if err != nil {
68 - res.SetError(err, cmds.ErrNormal)
70 + res.SetError(err, cmdkit.ErrNormal)
71 return
72 }
73
74 if !n.OnlineMode() {
75 err := n.SetupOfflineRouting()
76 if err != nil {
75 - res.SetError(err, cmds.ErrNormal)
77 + res.SetError(err, cmdkit.ErrNormal)
78 return
79 }
80 }
@@ -85,7 +87,7 @@ Resolve the value of an IPFS DAG path:
87 p, err := n.Namesys.ResolveN(req.Context(), name, 1)
88 // ErrResolveRecursion is fine
89 if err != nil && err != ns.ErrResolveRecursion {
88 - res.SetError(err, cmds.ErrNormal)
90 + res.SetError(err, cmdkit.ErrNormal)
91 return
92 }
93 res.SetOutput(&ResolvedPath{p})
@@ -95,13 +97,13 @@ Resolve the value of an IPFS DAG path:
97 // else, ipfs path or ipns with recursive flag
98 p, err := path.ParsePath(name)
99 if err != nil {
98 - res.SetError(err, cmds.ErrNormal)
100 + res.SetError(err, cmdkit.ErrNormal)
101 return
102 }
103
104 node, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, p)
105 if err != nil {
104 - res.SetError(err, cmds.ErrNormal)
106 + res.SetError(err, cmdkit.ErrNormal)
107 return
108 }
109
@@ -111,9 +113,14 @@ Resolve the value of an IPFS DAG path:
113 },
114 Marshalers: cmds.MarshalerMap{
115 cmds.Text: func(res cmds.Response) (io.Reader, error) {
114 - output, ok := res.Output().(*ResolvedPath)
116 + v, err := unwrapOutput(res.Output())
117 + if err != nil {
118 + return nil, err
119 + }
120 +
121 + output, ok := v.(*ResolvedPath)
122 if !ok {
116 - return nil, u.ErrCast()
123 + return nil, e.TypeErr(output, v)
124 }
125 return strings.NewReader(output.Path.String() + "\n"), nil
126 },
core/commands/root.go
+54 -31
@@ -4,11 +4,15 @@ import (
4 "io"
5 "strings"
6
7 - cmds "github.com/ipfs/go-ipfs/commands"
7 + oldcmds "github.com/ipfs/go-ipfs/commands"
8 dag "github.com/ipfs/go-ipfs/core/commands/dag"
9 + e "github.com/ipfs/go-ipfs/core/commands/e"
10 files "github.com/ipfs/go-ipfs/core/commands/files"
11 ocmd "github.com/ipfs/go-ipfs/core/commands/object"
12 unixfs "github.com/ipfs/go-ipfs/core/commands/unixfs"
13 +
14 + "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
15 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
16 logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
17 )
18
@@ -19,7 +23,7 @@ const (
23 )
24
25 var Root = &cmds.Command{
22 - Helptext: cmds.HelpText{
26 + Helptext: cmdkit.HelpText{
27 Tagline: "Global p2p merkle-dag filesystem.",
28 Synopsis: "ipfs [--config=<config> | -c] [--debug=<debug> | -D] [--help=<help>] [-h=<h>] [--local=<local> | -L] [--api=<api>] <command> ...",
29 Subcommands: `
@@ -80,13 +84,13 @@ The CLI will exit with one of the following values:
84 1 Failed executions.
85 `,
86 },
83 - Options: []cmds.Option{
84 - cmds.StringOption("config", "c", "Path to the configuration file to use."),
85 - cmds.BoolOption("debug", "D", "Operate in debug mode.").Default(false),
86 - cmds.BoolOption("help", "Show the full command help text.").Default(false),
87 - cmds.BoolOption("h", "Show a short version of the command help text.").Default(false),
88 - cmds.BoolOption("local", "L", "Run the command locally, instead of using the daemon.").Default(false),
89 - cmds.StringOption(ApiOption, "Use a specific API instance (defaults to /ip4/127.0.0.1/tcp/5001)"),
87 + Options: []cmdkit.Option{
88 + cmdkit.StringOption("config", "c", "Path to the configuration file to use."),
89 + cmdkit.BoolOption("debug", "D", "Operate in debug mode.").Default(false),
90 + cmdkit.BoolOption("help", "Show the full command help text.").Default(false),
91 + cmdkit.BoolOption("h", "Show a short version of the command help text.").Default(false),
92 + cmdkit.BoolOption("local", "L", "Run the command locally, instead of using the daemon.").Default(false),
93 + cmdkit.StringOption(ApiOption, "Use a specific API instance (defaults to /ip4/127.0.0.1/tcp/5001)"),
94 },
95 }
96
@@ -95,17 +99,25 @@ var CommandsDaemonCmd = CommandsCmd(Root)
99
100 var rootSubcommands = map[string]*cmds.Command{
101 "add": AddCmd,
102 + "bitswap": BitswapCmd,
103 "block": BlockCmd,
99 - "bootstrap": BootstrapCmd,
104 "cat": CatCmd,
105 "commands": CommandsDaemonCmd,
106 + "filestore": FileStoreCmd,
107 + "get": GetCmd,
108 + "pubsub": PubsubCmd,
109 + "repo": RepoCmd,
110 + "stats": StatsCmd,
111 +}
112 +
113 +var rootOldSubcommands = map[string]*oldcmds.Command{
114 + "bootstrap": BootstrapCmd,
115 "config": ConfigCmd,
116 "dag": dag.DagCmd,
117 "dht": DhtCmd,
118 "diag": DiagCmd,
119 "dns": DNSCmd,
120 "files": files.FilesCmd,
108 - "get": GetCmd,
121 "id": IDCmd,
122 "key": KeyCmd,
123 "log": LogCmd,
@@ -116,18 +128,13 @@ var rootSubcommands = map[string]*cmds.Command{
128 "pin": PinCmd,
129 "ping": PingCmd,
130 "p2p": P2PCmd,
119 - "pubsub": PubsubCmd,
131 "refs": RefsCmd,
121 - "repo": RepoCmd,
132 "resolve": ResolveCmd,
123 - "stats": StatsCmd,
133 "swarm": SwarmCmd,
134 "tar": TarCmd,
135 "file": unixfs.UnixFSCmd,
136 "update": ExternalBinary(),
137 "version": VersionCmd,
129 - "bitswap": BitswapCmd,
130 - "filestore": FileStoreCmd,
138 "shutdown": daemonShutdownCmd,
139 }
140
@@ -136,27 +143,30 @@ var RootRO = &cmds.Command{}
143
144 var CommandsDaemonROCmd = CommandsCmd(RootRO)
145
139 -var RefsROCmd = &cmds.Command{}
146 +var RefsROCmd = &oldcmds.Command{}
147
148 var rootROSubcommands = map[string]*cmds.Command{
149 + "commands": CommandsDaemonROCmd,
150 + "cat": CatCmd,
151 "block": &cmds.Command{
152 Subcommands: map[string]*cmds.Command{
153 "stat": blockStatCmd,
154 "get": blockGetCmd,
155 },
156 },
148 - "cat": CatCmd,
149 - "commands": CommandsDaemonROCmd,
150 - "dns": DNSCmd,
151 - "get": GetCmd,
152 - "ls": LsCmd,
153 - "name": &cmds.Command{
154 - Subcommands: map[string]*cmds.Command{
157 + "get": GetCmd,
158 +}
159 +
160 +var rootROOldSubcommands = map[string]*oldcmds.Command{
161 + "dns": DNSCmd,
162 + "ls": LsCmd,
163 + "name": &oldcmds.Command{
164 + Subcommands: map[string]*oldcmds.Command{
165 "resolve": IpnsCmd,
166 },
167 },
158 - "object": &cmds.Command{
159 - Subcommands: map[string]*cmds.Command{
168 + "object": &oldcmds.Command{
169 + Subcommands: map[string]*oldcmds.Command{
170 "data": ocmd.ObjectDataCmd,
171 "links": ocmd.ObjectLinksCmd,
172 "get": ocmd.ObjectGetCmd,
@@ -164,8 +174,8 @@ var rootROSubcommands = map[string]*cmds.Command{
174 "patch": ocmd.ObjectPatchCmd,
175 },
176 },
167 - "dag": &cmds.Command{
168 - Subcommands: map[string]*cmds.Command{
177 + "dag": &oldcmds.Command{
178 + Subcommands: map[string]*oldcmds.Command{
179 "get": dag.DagGetCmd,
180 "resolve": dag.DagResolveCmd,
181 },
@@ -181,9 +191,12 @@ func init() {
191
192 // sanitize readonly refs command
193 *RefsROCmd = *RefsCmd
184 - RefsROCmd.Subcommands = map[string]*cmds.Command{}
194 + RefsROCmd.Subcommands = map[string]*oldcmds.Command{}
195
196 + Root.OldSubcommands = rootOldSubcommands
197 Root.Subcommands = rootSubcommands
198 +
199 + RootRO.OldSubcommands = rootROOldSubcommands
200 RootRO.Subcommands = rootROSubcommands
201 }
202
@@ -191,6 +204,16 @@ type MessageOutput struct {
204 Message string
205 }
206
194 -func MessageTextMarshaler(res cmds.Response) (io.Reader, error) {
195 - return strings.NewReader(res.Output().(*MessageOutput).Message), nil
207 +func MessageTextMarshaler(res oldcmds.Response) (io.Reader, error) {
208 + v, err := unwrapOutput(res.Output())
209 + if err != nil {
210 + return nil, err
211 + }
212 +
213 + out, ok := v.(*MessageOutput)
214 + if !ok {
215 + return nil, e.TypeErr(out, v)
216 + }
217 +
218 + return strings.NewReader(out.Message), nil
219 }
core/commands/shutdown.go
+7 -3
@@ -3,27 +3,31 @@ package commands
3 import (
4 "fmt"
5
6 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
7 +
8 cmds "github.com/ipfs/go-ipfs/commands"
9 )
10
11 var daemonShutdownCmd = &cmds.Command{
10 - Helptext: cmds.HelpText{
12 + Helptext: cmdkit.HelpText{
13 Tagline: "Shut down the ipfs daemon",
14 },
15 Run: func(req cmds.Request, res cmds.Response) {
16 nd, err := req.InvocContext().GetNode()
17 if err != nil {
16 - res.SetError(err, cmds.ErrNormal)
18 + res.SetError(err, cmdkit.ErrNormal)
19 return
20 }
21
22 if nd.LocalMode() {
21 - res.SetError(fmt.Errorf("daemon not running"), cmds.ErrClient)
23 + res.SetError(fmt.Errorf("daemon not running"), cmdkit.ErrClient)
24 return
25 }
26
27 if err := nd.Process().Close(); err != nil {
28 log.Error("error while shutting down ipfs daemon:", err)
29 }
30 +
31 + res.SetOutput(nil)
32 },
33 }
core/commands/stat.go
+70 -84
@@ -1,23 +1,22 @@
1 package commands
2
3 import (
4 - "bytes"
4 "errors"
5 "fmt"
6 "io"
7 + "os"
8 "time"
9
10 humanize "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
11 -
12 - cmds "github.com/ipfs/go-ipfs/commands"
11 + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
12 metrics "gx/ipfs/QmQbh3Rb7KM37As3vkHYnEFnzkVXNCP8EYGtHz6g2fXk14/go-libp2p-metrics"
14 - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
13 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
14 peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer"
15 protocol "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol"
16 )
17
18 var StatsCmd = &cmds.Command{
20 - Helptext: cmds.HelpText{
19 + Helptext: cmdkit.HelpText{
20 Tagline: "Query IPFS statistics.",
21 ShortDescription: `'ipfs stats' is a set of commands to help look at statistics
22 for your IPFS node.
@@ -34,7 +33,7 @@ for your IPFS node.`,
33 }
34
35 var statBwCmd = &cmds.Command{
37 - Helptext: cmds.HelpText{
36 + Helptext: cmdkit.HelpText{
37 Tagline: "Print ipfs bandwidth information.",
38 ShortDescription: `'ipfs stats bw' prints bandwidth information for the ipfs daemon.
39 It displays: TotalIn, TotalOut, RateIn, RateOut.
@@ -70,47 +69,47 @@ Example:
69 RateOut: 0B/s
70 `,
71 },
73 - Options: []cmds.Option{
74 - cmds.StringOption("peer", "p", "Specify a peer to print bandwidth for."),
75 - cmds.StringOption("proto", "t", "Specify a protocol to print bandwidth for."),
76 - cmds.BoolOption("poll", "Print bandwidth at an interval.").Default(false),
77 - cmds.StringOption("interval", "i", `Time interval to wait between updating output, if 'poll' is true.
72 + Options: []cmdkit.Option{
73 + cmdkit.StringOption("peer", "p", "Specify a peer to print bandwidth for."),
74 + cmdkit.StringOption("proto", "t", "Specify a protocol to print bandwidth for."),
75 + cmdkit.BoolOption("poll", "Print bandwidth at an interval.").Default(false),
76 + cmdkit.StringOption("interval", "i", `Time interval to wait between updating output, if 'poll' is true.
77
78 This accepts durations such as "300s", "1.5h" or "2h45m". Valid time units are:
79 "ns", "us" (or "µs"), "ms", "s", "m", "h".`).Default("1s"),
80 },
81
83 - Run: func(req cmds.Request, res cmds.Response) {
82 + Run: func(req cmds.Request, res cmds.ResponseEmitter) {
83 nd, err := req.InvocContext().GetNode()
84 if err != nil {
86 - res.SetError(err, cmds.ErrNormal)
85 + res.SetError(err, cmdkit.ErrNormal)
86 return
87 }
88
89 // Must be online!
90 if !nd.OnlineMode() {
92 - res.SetError(errNotOnline, cmds.ErrClient)
91 + res.SetError(errNotOnline, cmdkit.ErrClient)
92 return
93 }
94
95 if nd.Reporter == nil {
97 - res.SetError(fmt.Errorf("bandwidth reporter disabled in config"), cmds.ErrNormal)
96 + res.SetError(fmt.Errorf("bandwidth reporter disabled in config"), cmdkit.ErrNormal)
97 return
98 }
99
100 pstr, pfound, err := req.Option("peer").String()
101 if err != nil {
103 - res.SetError(err, cmds.ErrNormal)
102 + res.SetError(err, cmdkit.ErrNormal)
103 return
104 }
105
106 tstr, tfound, err := req.Option("proto").String()
107 if err != nil {
109 - res.SetError(err, cmds.ErrNormal)
108 + res.SetError(err, cmdkit.ErrNormal)
109 return
110 }
111 if pfound && tfound {
113 - res.SetError(errors.New("please only specify peer OR protocol"), cmds.ErrClient)
112 + res.SetError(errors.New("please only specify peer OR protocol"), cmdkit.ErrClient)
113 return
114 }
115
@@ -118,7 +117,7 @@ Example:
117 if pfound {
118 checkpid, err := peer.IDB58Decode(pstr)
119 if err != nil {
121 - res.SetError(err, cmds.ErrNormal)
120 + res.SetError(err, cmdkit.ErrNormal)
121 return
122 }
123 pid = checkpid
@@ -126,92 +125,79 @@ Example:
125
126 timeS, _, err := req.Option("interval").String()
127 if err != nil {
129 - res.SetError(err, cmds.ErrNormal)
128 + res.SetError(err, cmdkit.ErrNormal)
129 return
130 }
131 interval, err := time.ParseDuration(timeS)
132 if err != nil {
134 - res.SetError(err, cmds.ErrNormal)
133 + res.SetError(err, cmdkit.ErrNormal)
134 return
135 }
136
137 doPoll, _, err := req.Option("poll").Bool()
138 if err != nil {
140 - res.SetError(err, cmds.ErrNormal)
139 + res.SetError(err, cmdkit.ErrNormal)
140 return
141 }
142
144 - out := make(chan interface{})
145 - res.SetOutput((<-chan interface{})(out))
146 -
147 - go func() {
148 - defer close(out)
149 - for {
150 - if pfound {
151 - stats := nd.Reporter.GetBandwidthForPeer(pid)
152 - out <- &stats
153 - } else if tfound {
154 - protoId := protocol.ID(tstr)
155 - stats := nd.Reporter.GetBandwidthForProtocol(protoId)
156 - out <- &stats
157 - } else {
158 - totals := nd.Reporter.GetBandwidthTotals()
159 - out <- &totals
160 - }
161 - if !doPoll {
162 - return
163 - }
164 - select {
165 - case <-time.After(interval):
166 - case <-req.Context().Done():
167 - return
168 - }
143 + for {
144 + if pfound {
145 + stats := nd.Reporter.GetBandwidthForPeer(pid)
146 + res.Emit(&stats)
147 + } else if tfound {
148 + protoId := protocol.ID(tstr)
149 + stats := nd.Reporter.GetBandwidthForProtocol(protoId)
150 + res.Emit(&stats)
151 + } else {
152 + totals := nd.Reporter.GetBandwidthTotals()
153 + res.Emit(&totals)
154 }
170 - }()
155 + if !doPoll {
156 + return
157 + }
158 + select {
159 + case <-time.After(interval):
160 + case <-req.Context().Done():
161 + return
162 + }
163 + }
164 +
165 },
166 Type: metrics.Stats{},
173 - Marshalers: cmds.MarshalerMap{
174 - cmds.Text: func(res cmds.Response) (io.Reader, error) {
175 - outCh, ok := res.Output().(<-chan interface{})
176 - if !ok {
177 - return nil, u.ErrCast()
178 - }
167 + PostRun: cmds.PostRunMap{
168 + cmds.CLI: func(req cmds.Request, re cmds.ResponseEmitter) cmds.ResponseEmitter {
169 + reNext, res := cmds.NewChanResponsePair(req)
170
180 - polling, _, err := res.Request().Option("poll").Bool()
181 - if err != nil {
182 - return nil, err
183 - }
171 + go func() {
172 + defer re.Close()
173
185 - first := true
186 - marshal := func(v interface{}) (io.Reader, error) {
187 - bs, ok := v.(*metrics.Stats)
188 - if !ok {
189 - return nil, u.ErrCast()
174 + polling, _, err := res.Request().Option("poll").Bool()
175 + if err != nil {
176 + return
177 }
191 - out := new(bytes.Buffer)
192 - if !polling {
193 - printStats(out, bs)
194 - } else {
195 - if first {
196 - fmt.Fprintln(out, "Total Up Total Down Rate Up Rate Down")
197 - first = false
178 +
179 + fmt.Fprintln(os.Stdout, "Total Up Total Down Rate Up Rate Down")
180 + for {
181 + v, err := res.Next()
182 + if !cmds.HandleError(err, res, re) {
183 + break
184 }
199 - fmt.Fprint(out, "\r")
200 - // In the worst case scenario, the humanized output is of form "xxx.x xB", which is 8 characters long
201 - fmt.Fprintf(out, "%8s ", humanize.Bytes(uint64(bs.TotalOut)))
202 - fmt.Fprintf(out, "%8s ", humanize.Bytes(uint64(bs.TotalIn)))
203 - fmt.Fprintf(out, "%8s/s ", humanize.Bytes(uint64(bs.RateOut)))
204 - fmt.Fprintf(out, "%8s/s ", humanize.Bytes(uint64(bs.RateIn)))
205 - }
206 - return out, nil
185
208 - }
186 + bs := v.(*metrics.Stats)
187 +
188 + if !polling {
189 + printStats(os.Stdout, bs)
190 + return
191 + }
192 +
193 + fmt.Fprintf(os.Stdout, "%8s ", humanize.Bytes(uint64(bs.TotalOut)))
194 + fmt.Fprintf(os.Stdout, "%8s ", humanize.Bytes(uint64(bs.TotalIn)))
195 + fmt.Fprintf(os.Stdout, "%8s/s ", humanize.Bytes(uint64(bs.RateOut)))
196 + fmt.Fprintf(os.Stdout, "%8s/s \n", humanize.Bytes(uint64(bs.RateIn)))
197 + }
198 + }()
199
210 - return &cmds.ChannelMarshaler{
211 - Channel: outCh,
212 - Marshaler: marshal,
213 - Res: res,
214 - }, nil
200 + return reNext
201 },
202 },
203 }
core/commands/swarm.go
+91 -76
@@ -10,15 +10,17 @@ import (
10 "strings"
11
12 cmds "github.com/ipfs/go-ipfs/commands"
13 + e "github.com/ipfs/go-ipfs/core/commands/e"
14 repo "github.com/ipfs/go-ipfs/repo"
15 config "github.com/ipfs/go-ipfs/repo/config"
16 "github.com/ipfs/go-ipfs/repo/fsrepo"
16 - pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore"
17 - swarm "gx/ipfs/QmdQFrFnPrKRQtpeHKjZ3cVNwxmGKKS2TvhJTuN9C9yduh/go-libp2p-swarm"
18 - iaddr "gx/ipfs/QmeS8cCKawUwejVrsBtmC1toTXmwVWZGiRJqzgTURVWeF9/go-ipfs-addr"
17
18 + pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore"
19 mafilter "gx/ipfs/QmSMZwvs3n4GBikZ7hKzT17c3bk65FmyZo2JqtJ16swqCv/multiaddr-filter"
20 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
21 ma "gx/ipfs/QmXY77cVe7rVRQXZZQRioukUM7aRW3BTcAgJe12MCtb3Ji/go-multiaddr"
22 + swarm "gx/ipfs/QmdQFrFnPrKRQtpeHKjZ3cVNwxmGKKS2TvhJTuN9C9yduh/go-libp2p-swarm"
23 + iaddr "gx/ipfs/QmeS8cCKawUwejVrsBtmC1toTXmwVWZGiRJqzgTURVWeF9/go-ipfs-addr"
24 )
25
26 type stringList struct {
@@ -30,7 +32,7 @@ type addrMap struct {
32 }
33
34 var SwarmCmd = &cmds.Command{
33 - Helptext: cmds.HelpText{
35 + Helptext: cmdkit.HelpText{
36 Tagline: "Interact with the swarm.",
37 ShortDescription: `
38 'ipfs swarm' is a tool to manipulate the network swarm. The swarm is the
@@ -48,28 +50,27 @@ ipfs peers in the internet.
50 }
51
52 var swarmPeersCmd = &cmds.Command{
51 - Helptext: cmds.HelpText{
53 + Helptext: cmdkit.HelpText{
54 Tagline: "List peers with open connections.",
55 ShortDescription: `
56 'ipfs swarm peers' lists the set of peers this node is connected to.
57 `,
58 },
57 - Options: []cmds.Option{
58 - cmds.BoolOption("verbose", "v", "display all extra information"),
59 - cmds.BoolOption("streams", "Also list information about open streams for each peer"),
60 - cmds.BoolOption("latency", "Also list information about latency to each peer"),
59 + Options: []cmdkit.Option{
60 + cmdkit.BoolOption("verbose", "v", "display all extra information"),
61 + cmdkit.BoolOption("streams", "Also list information about open streams for each peer"),
62 + cmdkit.BoolOption("latency", "Also list information about latency to each peer"),
63 },
64 Run: func(req cmds.Request, res cmds.Response) {
65
64 - log.Debug("ipfs swarm peers")
66 n, err := req.InvocContext().GetNode()
67 if err != nil {
67 - res.SetError(err, cmds.ErrNormal)
68 + res.SetError(err, cmdkit.ErrNormal)
69 return
70 }
71
72 if n.PeerHost == nil {
72 - res.SetError(errNotOnline, cmds.ErrClient)
73 + res.SetError(errNotOnline, cmdkit.ErrClient)
74 return
75 }
76
@@ -105,7 +106,7 @@ var swarmPeersCmd = &cmds.Command{
106 if verbose || streams {
107 strs, err := c.GetStreams()
108 if err != nil {
108 - res.SetError(err, cmds.ErrNormal)
109 + res.SetError(err, cmdkit.ErrNormal)
110 return
111 }
112
@@ -122,9 +123,14 @@ var swarmPeersCmd = &cmds.Command{
123 },
124 Marshalers: cmds.MarshalerMap{
125 cmds.Text: func(res cmds.Response) (io.Reader, error) {
125 - ci, ok := res.Output().(*connInfos)
126 + v, err := unwrapOutput(res.Output())
127 + if err != nil {
128 + return nil, err
129 + }
130 +
131 + ci, ok := v.(*connInfos)
132 if !ok {
127 - return nil, fmt.Errorf("expected output type to be connInfos")
133 + return nil, e.TypeErr(ci, v)
134 }
135
136 buf := new(bytes.Buffer)
@@ -197,7 +203,7 @@ func (ci connInfos) Swap(i, j int) {
203 }
204
205 var swarmAddrsCmd = &cmds.Command{
200 - Helptext: cmds.HelpText{
206 + Helptext: cmdkit.HelpText{
207 Tagline: "List known addresses. Useful for debugging.",
208 ShortDescription: `
209 'ipfs swarm addrs' lists all addresses this node is aware of.
@@ -211,12 +217,12 @@ var swarmAddrsCmd = &cmds.Command{
217
218 n, err := req.InvocContext().GetNode()
219 if err != nil {
214 - res.SetError(err, cmds.ErrNormal)
220 + res.SetError(err, cmdkit.ErrNormal)
221 return
222 }
223
224 if n.PeerHost == nil {
219 - res.SetError(errNotOnline, cmds.ErrClient)
225 + res.SetError(errNotOnline, cmdkit.ErrClient)
226 return
227 }
228
@@ -234,9 +240,14 @@ var swarmAddrsCmd = &cmds.Command{
240 },
241 Marshalers: cmds.MarshalerMap{
242 cmds.Text: func(res cmds.Response) (io.Reader, error) {
237 - m, ok := res.Output().(*addrMap)
243 + v, err := unwrapOutput(res.Output())
244 + if err != nil {
245 + return nil, err
246 + }
247 +
248 + m, ok := v.(*addrMap)
249 if !ok {
239 - return nil, errors.New("failed to cast map[string]string")
250 + return nil, e.TypeErr(m, v)
251 }
252
253 // sort the ids first
@@ -261,25 +272,25 @@ var swarmAddrsCmd = &cmds.Command{
272 }
273
274 var swarmAddrsLocalCmd = &cmds.Command{
264 - Helptext: cmds.HelpText{
275 + Helptext: cmdkit.HelpText{
276 Tagline: "List local addresses.",
277 ShortDescription: `
278 'ipfs swarm addrs local' lists all local listening addresses announced to the network.
279 `,
280 },
270 - Options: []cmds.Option{
271 - cmds.BoolOption("id", "Show peer ID in addresses.").Default(false),
281 + Options: []cmdkit.Option{
282 + cmdkit.BoolOption("id", "Show peer ID in addresses.").Default(false),
283 },
284 Run: func(req cmds.Request, res cmds.Response) {
274 -
275 - n, err := req.InvocContext().GetNode()
285 + iCtx := req.InvocContext()
286 + n, err := iCtx.GetNode()
287 if err != nil {
277 - res.SetError(err, cmds.ErrNormal)
288 + res.SetError(err, cmdkit.ErrNormal)
289 return
290 }
291
292 if n.PeerHost == nil {
282 - res.SetError(errNotOnline, cmds.ErrClient)
293 + res.SetError(errNotOnline, cmdkit.ErrClient)
294 return
295 }
296
@@ -295,7 +306,6 @@ var swarmAddrsLocalCmd = &cmds.Command{
306 addrs = append(addrs, saddr)
307 }
308 sort.Sort(sort.StringSlice(addrs))
298 -
309 res.SetOutput(&stringList{addrs})
310 },
311 Type: stringList{},
@@ -305,7 +315,7 @@ var swarmAddrsLocalCmd = &cmds.Command{
315 }
316
317 var swarmAddrsListenCmd = &cmds.Command{
308 - Helptext: cmds.HelpText{
318 + Helptext: cmdkit.HelpText{
319 Tagline: "List interface listening addresses.",
320 ShortDescription: `
321 'ipfs swarm addrs listen' lists all interface addresses the node is listening on.
@@ -315,19 +325,19 @@ var swarmAddrsListenCmd = &cmds.Command{
325
326 n, err := req.InvocContext().GetNode()
327 if err != nil {
318 - res.SetError(err, cmds.ErrNormal)
328 + res.SetError(err, cmdkit.ErrNormal)
329 return
330 }
331
332 if n.PeerHost == nil {
323 - res.SetError(errNotOnline, cmds.ErrClient)
333 + res.SetError(errNotOnline, cmdkit.ErrClient)
334 return
335 }
336
337 var addrs []string
338 maddrs, err := n.PeerHost.Network().InterfaceListenAddresses()
339 if err != nil {
330 - res.SetError(err, cmds.ErrNormal)
340 + res.SetError(err, cmdkit.ErrNormal)
341 return
342 }
343
@@ -345,7 +355,7 @@ var swarmAddrsListenCmd = &cmds.Command{
355 }
356
357 var swarmConnectCmd = &cmds.Command{
348 - Helptext: cmds.HelpText{
358 + Helptext: cmdkit.HelpText{
359 Tagline: "Open connection to a given address.",
360 ShortDescription: `
361 'ipfs swarm connect' opens a new direct connection to a peer address.
@@ -355,28 +365,28 @@ The address format is an IPFS multiaddr:
365 ipfs swarm connect /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
366 `,
367 },
358 - Arguments: []cmds.Argument{
359 - cmds.StringArg("address", true, true, "Address of peer to connect to.").EnableStdin(),
368 + Arguments: []cmdkit.Argument{
369 + cmdkit.StringArg("address", true, true, "Address of peer to connect to.").EnableStdin(),
370 },
371 Run: func(req cmds.Request, res cmds.Response) {
372 ctx := req.Context()
373
374 n, err := req.InvocContext().GetNode()
375 if err != nil {
366 - res.SetError(err, cmds.ErrNormal)
376 + res.SetError(err, cmdkit.ErrNormal)
377 return
378 }
379
380 addrs := req.Arguments()
381
382 if n.PeerHost == nil {
373 - res.SetError(errNotOnline, cmds.ErrClient)
383 + res.SetError(errNotOnline, cmdkit.ErrClient)
384 return
385 }
386
387 snet, ok := n.PeerHost.Network().(*swarm.Network)
388 if !ok {
379 - res.SetError(fmt.Errorf("peerhost network was not swarm"), cmds.ErrNormal)
389 + res.SetError(fmt.Errorf("peerhost network was not swarm"), cmdkit.ErrNormal)
390 return
391 }
392
@@ -384,7 +394,7 @@ ipfs swarm connect /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3
394
395 pis, err := peersWithAddresses(addrs)
396 if err != nil {
387 - res.SetError(err, cmds.ErrNormal)
397 + res.SetError(err, cmdkit.ErrNormal)
398 return
399 }
400
@@ -396,7 +406,7 @@ ipfs swarm connect /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3
406
407 err := n.PeerHost.Connect(ctx, pi)
408 if err != nil {
399 - res.SetError(fmt.Errorf("%s failure: %s", output[i], err), cmds.ErrNormal)
409 + res.SetError(fmt.Errorf("%s failure: %s", output[i], err), cmdkit.ErrNormal)
410 return
411 }
412 output[i] += " success"
@@ -411,7 +421,7 @@ ipfs swarm connect /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3
421 }
422
423 var swarmDisconnectCmd = &cmds.Command{
414 - Helptext: cmds.HelpText{
424 + Helptext: cmdkit.HelpText{
425 Tagline: "Close connection to a given address.",
426 ShortDescription: `
427 'ipfs swarm disconnect' closes a connection to a peer address. The address
@@ -423,26 +433,26 @@ The disconnect is not permanent; if ipfs needs to talk to that address later,
433 it will reconnect.
434 `,
435 },
426 - Arguments: []cmds.Argument{
427 - cmds.StringArg("address", true, true, "Address of peer to disconnect from.").EnableStdin(),
436 + Arguments: []cmdkit.Argument{
437 + cmdkit.StringArg("address", true, true, "Address of peer to disconnect from.").EnableStdin(),
438 },
439 Run: func(req cmds.Request, res cmds.Response) {
440 n, err := req.InvocContext().GetNode()
441 if err != nil {
432 - res.SetError(err, cmds.ErrNormal)
442 + res.SetError(err, cmdkit.ErrNormal)
443 return
444 }
445
446 addrs := req.Arguments()
447
448 if n.PeerHost == nil {
439 - res.SetError(errNotOnline, cmds.ErrClient)
449 + res.SetError(errNotOnline, cmdkit.ErrClient)
450 return
451 }
452
453 iaddrs, err := parseAddresses(addrs)
454 if err != nil {
445 - res.SetError(err, cmds.ErrNormal)
455 + res.SetError(err, cmdkit.ErrNormal)
456 return
457 }
458
@@ -455,7 +465,6 @@ it will reconnect.
465 conns := n.PeerHost.Network().ConnsToPeer(addr.ID())
466 for _, conn := range conns {
467 if !conn.RemoteMultiaddr().Equal(taddr) {
458 - log.Debug("it's not", conn.RemoteMultiaddr(), taddr)
468 continue
469 }
470
@@ -481,9 +490,14 @@ it will reconnect.
490 }
491
492 func stringListMarshaler(res cmds.Response) (io.Reader, error) {
484 - list, ok := res.Output().(*stringList)
493 + v, err := unwrapOutput(res.Output())
494 + if err != nil {
495 + return nil, err
496 + }
497 +
498 + list, ok := v.(*stringList)
499 if !ok {
486 - return nil, errors.New("failed to cast []string")
500 + return nil, e.TypeErr(list, v)
501 }
502
503 buf := new(bytes.Buffer)
@@ -491,6 +505,7 @@ func stringListMarshaler(res cmds.Response) (io.Reader, error) {
505 buf.WriteString(s)
506 buf.WriteString("\n")
507 }
508 +
509 return buf, nil
510 }
511
@@ -525,7 +540,7 @@ func peersWithAddresses(addrs []string) (pis []pstore.PeerInfo, err error) {
540 }
541
542 var swarmFiltersCmd = &cmds.Command{
528 - Helptext: cmds.HelpText{
543 + Helptext: cmdkit.HelpText{
544 Tagline: "Manipulate address filters.",
545 ShortDescription: `
546 'ipfs swarm filters' will list out currently applied filters. Its subcommands
@@ -550,18 +565,18 @@ Filters default to those specified under the "Swarm.AddrFilters" config key.
565 Run: func(req cmds.Request, res cmds.Response) {
566 n, err := req.InvocContext().GetNode()
567 if err != nil {
553 - res.SetError(err, cmds.ErrNormal)
568 + res.SetError(err, cmdkit.ErrNormal)
569 return
570 }
571
572 if n.PeerHost == nil {
558 - res.SetError(errNotOnline, cmds.ErrNormal)
573 + res.SetError(errNotOnline, cmdkit.ErrNormal)
574 return
575 }
576
577 snet, ok := n.PeerHost.Network().(*swarm.Network)
578 if !ok {
564 - res.SetError(errors.New("failed to cast network to swarm network"), cmds.ErrNormal)
579 + res.SetError(errors.New("failed to cast network to swarm network"), cmdkit.ErrNormal)
580 return
581 }
582
@@ -569,7 +584,7 @@ Filters default to those specified under the "Swarm.AddrFilters" config key.
584 for _, f := range snet.Filters.Filters() {
585 s, err := mafilter.ConvertIPNet(f)
586 if err != nil {
572 - res.SetError(err, cmds.ErrNormal)
587 + res.SetError(err, cmdkit.ErrNormal)
588 return
589 }
590 output = append(output, s)
@@ -583,7 +598,7 @@ Filters default to those specified under the "Swarm.AddrFilters" config key.
598 }
599
600 var swarmFiltersAddCmd = &cmds.Command{
586 - Helptext: cmds.HelpText{
601 + Helptext: cmdkit.HelpText{
602 Tagline: "Add an address filter.",
603 ShortDescription: `
604 'ipfs swarm filters add' will add an address filter to the daemons swarm.
@@ -591,48 +606,48 @@ Filters applied this way will not persist daemon reboots, to achieve that,
606 add your filters to the ipfs config file.
607 `,
608 },
594 - Arguments: []cmds.Argument{
595 - cmds.StringArg("address", true, true, "Multiaddr to filter.").EnableStdin(),
609 + Arguments: []cmdkit.Argument{
610 + cmdkit.StringArg("address", true, true, "Multiaddr to filter.").EnableStdin(),
611 },
612 Run: func(req cmds.Request, res cmds.Response) {
613 n, err := req.InvocContext().GetNode()
614 if err != nil {
600 - res.SetError(err, cmds.ErrNormal)
615 + res.SetError(err, cmdkit.ErrNormal)
616 return
617 }
618
619 if n.PeerHost == nil {
605 - res.SetError(errNotOnline, cmds.ErrNormal)
620 + res.SetError(errNotOnline, cmdkit.ErrNormal)
621 return
622 }
623
624 snet, ok := n.PeerHost.Network().(*swarm.Network)
625 if !ok {
611 - res.SetError(errors.New("failed to cast network to swarm network"), cmds.ErrNormal)
626 + res.SetError(errors.New("failed to cast network to swarm network"), cmdkit.ErrNormal)
627 return
628 }
629
630 if len(req.Arguments()) == 0 {
616 - res.SetError(errors.New("no filters to add"), cmds.ErrClient)
631 + res.SetError(errors.New("no filters to add"), cmdkit.ErrClient)
632 return
633 }
634
635 r, err := fsrepo.Open(req.InvocContext().ConfigRoot)
636 if err != nil {
622 - res.SetError(err, cmds.ErrNormal)
637 + res.SetError(err, cmdkit.ErrNormal)
638 return
639 }
640 defer r.Close()
641 cfg, err := r.Config()
642 if err != nil {
628 - res.SetError(err, cmds.ErrNormal)
643 + res.SetError(err, cmdkit.ErrNormal)
644 return
645 }
646
647 for _, arg := range req.Arguments() {
648 mask, err := mafilter.NewMask(arg)
649 if err != nil {
635 - res.SetError(err, cmds.ErrNormal)
650 + res.SetError(err, cmdkit.ErrNormal)
651 return
652 }
653
@@ -641,7 +656,7 @@ add your filters to the ipfs config file.
656
657 added, err := filtersAdd(r, cfg, req.Arguments())
658 if err != nil {
644 - res.SetError(err, cmds.ErrNormal)
659 + res.SetError(err, cmdkit.ErrNormal)
660 return
661
662 }
@@ -655,7 +670,7 @@ add your filters to the ipfs config file.
670 }
671
672 var swarmFiltersRmCmd = &cmds.Command{
658 - Helptext: cmds.HelpText{
673 + Helptext: cmdkit.HelpText{
674 Tagline: "Remove an address filter.",
675 ShortDescription: `
676 'ipfs swarm filters rm' will remove an address filter from the daemons swarm.
@@ -663,36 +678,36 @@ Filters removed this way will not persist daemon reboots, to achieve that,
678 remove your filters from the ipfs config file.
679 `,
680 },
666 - Arguments: []cmds.Argument{
667 - cmds.StringArg("address", true, true, "Multiaddr filter to remove.").EnableStdin(),
681 + Arguments: []cmdkit.Argument{
682 + cmdkit.StringArg("address", true, true, "Multiaddr filter to remove.").EnableStdin(),
683 },
684 Run: func(req cmds.Request, res cmds.Response) {
685 n, err := req.InvocContext().GetNode()
686 if err != nil {
672 - res.SetError(err, cmds.ErrNormal)
687 + res.SetError(err, cmdkit.ErrNormal)
688 return
689 }
690
691 if n.PeerHost == nil {
677 - res.SetError(errNotOnline, cmds.ErrNormal)
692 + res.SetError(errNotOnline, cmdkit.ErrNormal)
693 return
694 }
695
696 snet, ok := n.PeerHost.Network().(*swarm.Network)
697 if !ok {
683 - res.SetError(errors.New("failed to cast network to swarm network"), cmds.ErrNormal)
698 + res.SetError(errors.New("failed to cast network to swarm network"), cmdkit.ErrNormal)
699 return
700 }
701
702 r, err := fsrepo.Open(req.InvocContext().ConfigRoot)
703 if err != nil {
689 - res.SetError(err, cmds.ErrNormal)
704 + res.SetError(err, cmdkit.ErrNormal)
705 return
706 }
707 defer r.Close()
708 cfg, err := r.Config()
709 if err != nil {
695 - res.SetError(err, cmds.ErrNormal)
710 + res.SetError(err, cmdkit.ErrNormal)
711 return
712 }
713
@@ -704,7 +719,7 @@ remove your filters from the ipfs config file.
719
720 removed, err := filtersRemoveAll(r, cfg)
721 if err != nil {
707 - res.SetError(err, cmds.ErrNormal)
722 + res.SetError(err, cmdkit.ErrNormal)
723 return
724 }
725
@@ -716,7 +731,7 @@ remove your filters from the ipfs config file.
731 for _, arg := range req.Arguments() {
732 mask, err := mafilter.NewMask(arg)
733 if err != nil {
719 - res.SetError(err, cmds.ErrNormal)
734 + res.SetError(err, cmdkit.ErrNormal)
735 return
736 }
737
@@ -725,7 +740,7 @@ remove your filters from the ipfs config file.
740
741 removed, err := filtersRemove(r, cfg, req.Arguments())
742 if err != nil {
728 - res.SetError(err, cmds.ErrNormal)
743 + res.SetError(err, cmdkit.ErrNormal)
744 return
745 }
746
core/commands/sysdiag.go
+8 -7
@@ -8,12 +8,13 @@ import (
8 cmds "github.com/ipfs/go-ipfs/commands"
9 config "github.com/ipfs/go-ipfs/repo/config"
10
11 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
12 manet "gx/ipfs/QmX3U3YXCQ6UYBxq2LVWF8dARS1hPUTEYLrSx654Qyxyw6/go-multiaddr-net"
13 sysi "gx/ipfs/QmZRjKbHa6DenStpQJFiaPcEwkZqrx7TH6xTf342LDU3qM/go-sysinfo"
14 )
15
16 var sysDiagCmd = &cmds.Command{
16 - Helptext: cmds.HelpText{
17 + Helptext: cmdkit.HelpText{
18 Tagline: "Print system diagnostic information.",
19 ShortDescription: `
20 Prints out information about your computer to aid in easier debugging.
@@ -23,36 +24,36 @@ Prints out information about your computer to aid in easier debugging.
24 info := make(map[string]interface{})
25 err := runtimeInfo(info)
26 if err != nil {
26 - res.SetError(err, cmds.ErrNormal)
27 + res.SetError(err, cmdkit.ErrNormal)
28 return
29 }
30
31 err = envVarInfo(info)
32 if err != nil {
32 - res.SetError(err, cmds.ErrNormal)
33 + res.SetError(err, cmdkit.ErrNormal)
34 return
35 }
36
37 err = diskSpaceInfo(info)
38 if err != nil {
38 - res.SetError(err, cmds.ErrNormal)
39 + res.SetError(err, cmdkit.ErrNormal)
40 return
41 }
42
43 err = memInfo(info)
44 if err != nil {
44 - res.SetError(err, cmds.ErrNormal)
45 + res.SetError(err, cmdkit.ErrNormal)
46 return
47 }
48 node, err := req.InvocContext().GetNode()
49 if err != nil {
49 - res.SetError(err, cmds.ErrNormal)
50 + res.SetError(err, cmdkit.ErrNormal)
51 return
52 }
53
54 err = netInfo(node.OnlineMode(), info)
55 if err != nil {
55 - res.SetError(err, cmds.ErrNormal)
56 + res.SetError(err, cmdkit.ErrNormal)
57 return
58 }
59
core/commands/tar.go
+27 -16
@@ -6,14 +6,17 @@ import (
6
7 cmds "github.com/ipfs/go-ipfs/commands"
8 core "github.com/ipfs/go-ipfs/core"
9 + e "github.com/ipfs/go-ipfs/core/commands/e"
10 "github.com/ipfs/go-ipfs/core/coreunix"
11 dag "github.com/ipfs/go-ipfs/merkledag"
12 path "github.com/ipfs/go-ipfs/path"
13 tar "github.com/ipfs/go-ipfs/tar"
14 +
15 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
16 )
17
18 var TarCmd = &cmds.Command{
16 - Helptext: cmds.HelpText{
19 + Helptext: cmdkit.HelpText{
20 Tagline: "Utility functions for tar files in ipfs.",
21 },
22
@@ -24,7 +27,7 @@ var TarCmd = &cmds.Command{
27 }
28
29 var tarAddCmd = &cmds.Command{
27 - Helptext: cmds.HelpText{
30 + Helptext: cmdkit.HelpText{
31 Tagline: "Import a tar file into ipfs.",
32 ShortDescription: `
33 'ipfs tar add' will parse a tar file and create a merkledag structure to
@@ -32,25 +35,25 @@ represent it.
35 `,
36 },
37
35 - Arguments: []cmds.Argument{
36 - cmds.FileArg("file", true, false, "Tar file to add.").EnableStdin(),
38 + Arguments: []cmdkit.Argument{
39 + cmdkit.FileArg("file", true, false, "Tar file to add.").EnableStdin(),
40 },
41 Run: func(req cmds.Request, res cmds.Response) {
42 nd, err := req.InvocContext().GetNode()
43 if err != nil {
41 - res.SetError(err, cmds.ErrNormal)
44 + res.SetError(err, cmdkit.ErrNormal)
45 return
46 }
47
48 fi, err := req.Files().NextFile()
49 if err != nil {
47 - res.SetError(err, cmds.ErrNormal)
50 + res.SetError(err, cmdkit.ErrNormal)
51 return
52 }
53
54 node, err := tar.ImportTar(fi, nd.DAG)
55 if err != nil {
53 - res.SetError(err, cmds.ErrNormal)
56 + res.SetError(err, cmdkit.ErrNormal)
57 return
58 }
59
@@ -65,51 +68,59 @@ represent it.
68 Type: coreunix.AddedObject{},
69 Marshalers: cmds.MarshalerMap{
70 cmds.Text: func(res cmds.Response) (io.Reader, error) {
68 - o := res.Output().(*coreunix.AddedObject)
71 + v, err := unwrapOutput(res.Output())
72 + if err != nil {
73 + return nil, err
74 + }
75 +
76 + o, ok := v.(*coreunix.AddedObject)
77 + if !ok {
78 + return nil, e.TypeErr(o, v)
79 + }
80 return strings.NewReader(o.Hash + "\n"), nil
81 },
82 },
83 }
84
85 var tarCatCmd = &cmds.Command{
75 - Helptext: cmds.HelpText{
86 + Helptext: cmdkit.HelpText{
87 Tagline: "Export a tar file from IPFS.",
88 ShortDescription: `
89 'ipfs tar cat' will export a tar file from a previously imported one in IPFS.
90 `,
91 },
92
82 - Arguments: []cmds.Argument{
83 - cmds.StringArg("path", true, false, "ipfs path of archive to export.").EnableStdin(),
93 + Arguments: []cmdkit.Argument{
94 + cmdkit.StringArg("path", true, false, "ipfs path of archive to export.").EnableStdin(),
95 },
96 Run: func(req cmds.Request, res cmds.Response) {
97 nd, err := req.InvocContext().GetNode()
98 if err != nil {
88 - res.SetError(err, cmds.ErrNormal)
99 + res.SetError(err, cmdkit.ErrNormal)
100 return
101 }
102
103 p, err := path.ParsePath(req.Arguments()[0])
104 if err != nil {
94 - res.SetError(err, cmds.ErrNormal)
105 + res.SetError(err, cmdkit.ErrNormal)
106 return
107 }
108
109 root, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, p)
110 if err != nil {
100 - res.SetError(err, cmds.ErrNormal)
111 + res.SetError(err, cmdkit.ErrNormal)
112 return
113 }
114
115 rootpb, ok := root.(*dag.ProtoNode)
116 if !ok {
106 - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal)
117 + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal)
118 return
119 }
120
121 r, err := tar.ExportTar(req.Context(), rootpb, nd.DAG)
122 if err != nil {
112 - res.SetError(err, cmds.ErrNormal)
123 + res.SetError(err, cmdkit.ErrNormal)
124 return
125 }
126
core/commands/unixfs/ls.go
+22 -13
@@ -9,11 +9,13 @@ import (
9
10 cmds "github.com/ipfs/go-ipfs/commands"
11 core "github.com/ipfs/go-ipfs/core"
12 + e "github.com/ipfs/go-ipfs/core/commands/e"
13 merkledag "github.com/ipfs/go-ipfs/merkledag"
14 path "github.com/ipfs/go-ipfs/path"
15 unixfs "github.com/ipfs/go-ipfs/unixfs"
16 uio "github.com/ipfs/go-ipfs/unixfs/io"
17 unixfspb "github.com/ipfs/go-ipfs/unixfs/pb"
18 + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
19 )
20
21 type LsLink struct {
@@ -35,7 +37,7 @@ type LsOutput struct {
37 }
38
39 var LsCmd = &cmds.Command{
38 - Helptext: cmds.HelpText{
40 + Helptext: cmdkit.HelpText{
41 Tagline: "List directory contents for Unix filesystem objects.",
42 ShortDescription: `
43 Displays the contents of an IPFS or IPNS object(s) at the given path.
@@ -69,13 +71,13 @@ possible, please use 'ipfs ls' instead.
71 `,
72 },
73
72 - Arguments: []cmds.Argument{
73 - cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to list links from.").EnableStdin(),
74 + Arguments: []cmdkit.Argument{
75 + cmdkit.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to list links from.").EnableStdin(),
76 },
77 Run: func(req cmds.Request, res cmds.Response) {
78 node, err := req.InvocContext().GetNode()
79 if err != nil {
78 - res.SetError(err, cmds.ErrNormal)
80 + res.SetError(err, cmdkit.ErrNormal)
81 return
82 }
83
@@ -96,7 +98,7 @@ possible, please use 'ipfs ls' instead.
98
99 merkleNode, err := core.Resolve(ctx, node.Namesys, resolver, path.Path(fpath))
100 if err != nil {
99 - res.SetError(err, cmds.ErrNormal)
101 + res.SetError(err, cmdkit.ErrNormal)
102 return
103 }
104
@@ -112,13 +114,13 @@ possible, please use 'ipfs ls' instead.
114
115 ndpb, ok := merkleNode.(*merkledag.ProtoNode)
116 if !ok {
115 - res.SetError(merkledag.ErrNotProtobuf, cmds.ErrNormal)
117 + res.SetError(merkledag.ErrNotProtobuf, cmdkit.ErrNormal)
118 return
119 }
120
121 unixFSNode, err := unixfs.FromBytes(ndpb.Data())
122 if err != nil {
121 - res.SetError(err, cmds.ErrNormal)
123 + res.SetError(err, cmdkit.ErrNormal)
124 return
125 }
126
@@ -139,18 +141,18 @@ possible, please use 'ipfs ls' instead.
141 for i, link := range merkleNode.Links() {
142 linkNode, err := link.GetNode(ctx, node.DAG)
143 if err != nil {
142 - res.SetError(err, cmds.ErrNormal)
144 + res.SetError(err, cmdkit.ErrNormal)
145 return
146 }
147 lnpb, ok := linkNode.(*merkledag.ProtoNode)
148 if !ok {
147 - res.SetError(merkledag.ErrNotProtobuf, cmds.ErrNormal)
149 + res.SetError(merkledag.ErrNotProtobuf, cmdkit.ErrNormal)
150 return
151 }
152
153 d, err := unixfs.FromBytes(lnpb.Data())
154 if err != nil {
153 - res.SetError(err, cmds.ErrNormal)
155 + res.SetError(err, cmdkit.ErrNormal)
156 return
157 }
158 t := d.GetType()
@@ -167,10 +169,10 @@ possible, please use 'ipfs ls' instead.
169 links[i] = lsLink
170 }
171 case unixfspb.Data_Symlink:
170 - res.SetError(fmt.Errorf("cannot list symlinks yet"), cmds.ErrNormal)
172 + res.SetError(fmt.Errorf("cannot list symlinks yet"), cmdkit.ErrNormal)
173 return
174 default:
173 - res.SetError(fmt.Errorf("unrecognized type: %s", t), cmds.ErrImplementation)
175 + res.SetError(fmt.Errorf("unrecognized type: %s", t), cmdkit.ErrImplementation)
176 return
177 }
178 }
@@ -179,8 +181,15 @@ possible, please use 'ipfs ls' instead.
181 },
182 Marshalers: cmds.MarshalerMap{
183 cmds.Text: func(res cmds.Response) (io.Reader, error) {
184 + v, err := unwrapOutput(res.Output())
185 + if err != nil {
186 + return nil, err
187 + }
188
183 - output := res.Output().(*LsOutput)
189 + output, ok := v.(*LsOutput)
190 + if !ok {
191 + return nil, e.TypeErr(output, v)
192 + }
193 buf := new(bytes.Buffer)
194 w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0)
195
core/commands/unixfs/unixfs.go
+21 -2
@@ -1,9 +1,14 @@
1 package unixfs
2
3 -import cmds "github.com/ipfs/go-ipfs/commands"
3 +import (
4 + cmds "github.com/ipfs/go-ipfs/commands"
5 + e "github.com/ipfs/go-ipfs/core/commands/e"
6 +
7 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
8 +)
9
10 var UnixFSCmd = &cmds.Command{
6 - Helptext: cmds.HelpText{
11 + Helptext: cmdkit.HelpText{
12 Tagline: "Interact with IPFS objects representing Unix filesystems.",
13 ShortDescription: `
14 'ipfs file' provides a familiar interface to file systems represented
@@ -21,3 +26,17 @@ objects (e.g. fanout and chunking).
26 "ls": LsCmd,
27 },
28 }
29 +
30 +// copy+pasted from ../commands.go
31 +func unwrapOutput(i interface{}) (interface{}, error) {
32 + var (
33 + ch <-chan interface{}
34 + ok bool
35 + )
36 +
37 + if ch, ok = i.(<-chan interface{}); !ok {
38 + return nil, e.TypeErr(ch, i)
39 + }
40 +
41 + return <-ch, nil
42 +}
core/commands/version.go
+22 -12
@@ -7,8 +7,10 @@ import (
7 "strings"
8
9 cmds "github.com/ipfs/go-ipfs/commands"
10 + e "github.com/ipfs/go-ipfs/core/commands/e"
11 config "github.com/ipfs/go-ipfs/repo/config"
12 fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
13 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
14 )
15
16 type VersionOutput struct {
@@ -20,16 +22,16 @@ type VersionOutput struct {
22 }
23
24 var VersionCmd = &cmds.Command{
23 - Helptext: cmds.HelpText{
25 + Helptext: cmdkit.HelpText{
26 Tagline: "Show ipfs version information.",
27 ShortDescription: "Returns the current version of ipfs and exits.",
28 },
29
28 - Options: []cmds.Option{
29 - cmds.BoolOption("number", "n", "Only show the version number.").Default(false),
30 - cmds.BoolOption("commit", "Show the commit hash.").Default(false),
31 - cmds.BoolOption("repo", "Show repo version.").Default(false),
32 - cmds.BoolOption("all", "Show all version information").Default(false),
30 + Options: []cmdkit.Option{
31 + cmdkit.BoolOption("number", "n", "Only show the version number.").Default(false),
32 + cmdkit.BoolOption("commit", "Show the commit hash.").Default(false),
33 + cmdkit.BoolOption("repo", "Show repo version.").Default(false),
34 + cmdkit.BoolOption("all", "Show all version information").Default(false),
35 },
36 Run: func(req cmds.Request, res cmds.Response) {
37 res.SetOutput(&VersionOutput{
@@ -42,7 +44,15 @@ var VersionCmd = &cmds.Command{
44 },
45 Marshalers: cmds.MarshalerMap{
46 cmds.Text: func(res cmds.Response) (io.Reader, error) {
45 - v := res.Output().(*VersionOutput)
47 + v, err := unwrapOutput(res.Output())
48 + if err != nil {
49 + return nil, err
50 + }
51 +
52 + version, ok := v.(*VersionOutput)
53 + if !ok {
54 + return nil, e.TypeErr(version, v)
55 + }
56
57 repo, _, err := res.Request().Option("repo").Bool()
58 if err != nil {
@@ -50,7 +60,7 @@ var VersionCmd = &cmds.Command{
60 }
61
62 if repo {
53 - return strings.NewReader(v.Repo + "\n"), nil
63 + return strings.NewReader(version.Repo + "\n"), nil
64 }
65
66 commit, _, err := res.Request().Option("commit").Bool()
@@ -59,7 +69,7 @@ var VersionCmd = &cmds.Command{
69 return nil, err
70 }
71 if commit {
62 - commitTxt = "-" + v.Commit
72 + commitTxt = "-" + version.Commit
73 }
74
75 number, _, err := res.Request().Option("number").Bool()
@@ -67,7 +77,7 @@ var VersionCmd = &cmds.Command{
77 return nil, err
78 }
79 if number {
70 - return strings.NewReader(fmt.Sprintln(v.Version + commitTxt)), nil
80 + return strings.NewReader(fmt.Sprintln(version.Version + commitTxt)), nil
81 }
82
83 all, _, err := res.Request().Option("all").Bool()
@@ -77,11 +87,11 @@ var VersionCmd = &cmds.Command{
87 if all {
88 out := fmt.Sprintf("go-ipfs version: %s-%s\n"+
89 "Repo version: %s\nSystem version: %s\nGolang version: %s\n",
80 - v.Version, v.Commit, v.Repo, v.System, v.Golang)
90 + version.Version, version.Commit, version.Repo, version.System, version.Golang)
91 return strings.NewReader(out), nil
92 }
93
84 - return strings.NewReader(fmt.Sprintf("ipfs version %s%s\n", v.Version, commitTxt)), nil
94 + return strings.NewReader(fmt.Sprintf("ipfs version %s%s\n", version.Version, commitTxt)), nil
95 },
96 },
97 Type: VersionOutput{},
core/core_test.go
+1
@@ -4,6 +4,7 @@ import (
4 "testing"
5
6 context "context"
7 +
8 "github.com/ipfs/go-ipfs/repo"
9 config "github.com/ipfs/go-ipfs/repo/config"
10 ds2 "github.com/ipfs/go-ipfs/thirdparty/datastore2"
core/corehttp/commands.go
+6 -5
@@ -7,11 +7,12 @@ import (
7 "strconv"
8 "strings"
9
10 - commands "github.com/ipfs/go-ipfs/commands"
11 - cmdsHttp "github.com/ipfs/go-ipfs/commands/http"
10 core "github.com/ipfs/go-ipfs/core"
11 corecommands "github.com/ipfs/go-ipfs/core/commands"
12 config "github.com/ipfs/go-ipfs/repo/config"
13 +
14 + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds"
15 + cmdsHttp "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds/http"
16 )
17
18 const originEnvKey = "API_ORIGIN"
@@ -99,7 +100,7 @@ func patchCORSVars(c *cmdsHttp.ServerConfig, addr net.Addr) {
100 c.SetAllowedOrigins(origins...)
101 }
102
102 -func commandsOption(cctx commands.Context, command *commands.Command) ServeOption {
103 +func commandsOption(cctx cmds.Context, command *cmds.Command) ServeOption {
104 return func(n *core.IpfsNode, l net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
105
106 cfg := cmdsHttp.NewServerConfig()
@@ -120,10 +121,10 @@ func commandsOption(cctx commands.Context, command *commands.Command) ServeOptio
121 }
122 }
123
123 -func CommandsOption(cctx commands.Context) ServeOption {
124 +func CommandsOption(cctx cmds.Context) ServeOption {
125 return commandsOption(cctx, corecommands.Root)
126 }
127
127 -func CommandsROOption(cctx commands.Context) ServeOption {
128 +func CommandsROOption(cctx cmds.Context) ServeOption {
129 return commandsOption(cctx, corecommands.RootRO)
130 }
core/corehttp/gateway.go
+1
@@ -8,6 +8,7 @@ import (
8 core "github.com/ipfs/go-ipfs/core"
9 coreapi "github.com/ipfs/go-ipfs/core/coreapi"
10 config "github.com/ipfs/go-ipfs/repo/config"
11 +
12 id "gx/ipfs/QmefgzMbKZYsmHFkLqxgaTBG9ypeEjrdWRD5WXH4j1cWDL/go-libp2p/p2p/protocol/identify"
13 )
14
core/coreunix/add.go
+1 -1
@@ -12,7 +12,6 @@ import (
12 bs "github.com/ipfs/go-ipfs/blocks/blockstore"
13 bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
14 bserv "github.com/ipfs/go-ipfs/blockservice"
15 - "github.com/ipfs/go-ipfs/commands/files"
15 core "github.com/ipfs/go-ipfs/core"
16 "github.com/ipfs/go-ipfs/exchange/offline"
17 balanced "github.com/ipfs/go-ipfs/importer/balanced"
@@ -27,6 +26,7 @@ import (
26
27 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
28 node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format"
29 + files "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files"
30 logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
31 ds "gx/ipfs/QmVSase1JP7cq9QkPT46oNwdp9pT6kBkG3oqS14y3QcZjG/go-datastore"
32 syncds "gx/ipfs/QmVSase1JP7cq9QkPT46oNwdp9pT6kBkG3oqS14y3QcZjG/go-datastore/sync"
core/coreunix/add_test.go
+1 -1
@@ -12,7 +12,6 @@ import (
12
13 "github.com/ipfs/go-ipfs/blocks/blockstore"
14 "github.com/ipfs/go-ipfs/blockservice"
15 - "github.com/ipfs/go-ipfs/commands/files"
15 "github.com/ipfs/go-ipfs/core"
16 dag "github.com/ipfs/go-ipfs/merkledag"
17 "github.com/ipfs/go-ipfs/pin/gc"
@@ -23,6 +22,7 @@ import (
22 "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format"
23
24 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
25 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files"
26 )
27
28 func TestAddRecursive(t *testing.T) {
core/coreunix/metadata_test.go
+1 -1
@@ -2,6 +2,7 @@ package coreunix
2
3 import (
4 "bytes"
5 + "context"
6 "io/ioutil"
7 "testing"
8
@@ -15,7 +16,6 @@ import (
16 ft "github.com/ipfs/go-ipfs/unixfs"
17 uio "github.com/ipfs/go-ipfs/unixfs/io"
18
18 - context "context"
19 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
20 u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
21 ds "gx/ipfs/QmVSase1JP7cq9QkPT46oNwdp9pT6kBkG3oqS14y3QcZjG/go-datastore"
exchange/bitswap/bitswap_test.go
+3 -3
@@ -14,14 +14,14 @@ import (
14 tn "github.com/ipfs/go-ipfs/exchange/bitswap/testnet"
15 mockrouting "github.com/ipfs/go-ipfs/routing/mock"
16 delay "github.com/ipfs/go-ipfs/thirdparty/delay"
17 - blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format"
18 - travis "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil/ci/travis"
17
18 detectrace "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-detect-race"
19
20 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
23 - p2ptestutil "gx/ipfs/QmQGX417WoxKxDJeHqouMEmmH4G1RCENNSzkZYHrXy3Xb3/go-libp2p-netutil"
21 tu "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil"
22 + travis "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil/ci/travis"
23 + blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format"
24 + p2ptestutil "gx/ipfs/QmQGX417WoxKxDJeHqouMEmmH4G1RCENNSzkZYHrXy3Xb3/go-libp2p-netutil"
25 )
26
27 // FIXME the tests are really sensitive to the network delay. fix them to work
exchange/bitswap/decision/engine_test.go
+1 -1
@@ -1,6 +1,7 @@
1 package decision
2
3 import (
4 + "context"
5 "errors"
6 "fmt"
7 "math"
@@ -8,7 +9,6 @@ import (
9 "sync"
10 "testing"
11
11 - context "context"
12 blockstore "github.com/ipfs/go-ipfs/blocks/blockstore"
13 message "github.com/ipfs/go-ipfs/exchange/bitswap/message"
14 blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format"
exchange/bitswap/message/message_test.go
+2 -2
@@ -4,12 +4,12 @@ import (
4 "bytes"
5 "testing"
6
7 - proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
8 -
7 pb "github.com/ipfs/go-ipfs/exchange/bitswap/message/pb"
8 +
9 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
10 u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
11 blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format"
12 + proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
13 )
14
15 func mkFakeCid(s string) *cid.Cid {
exchange/bitswap/message/pb/Makefile new
+8
@@ -0,0 +1,8 @@
1 +# TODO(brian): add proto tasks
2 +all: message.pb.go
3 +
4 +message.pb.go: message.proto
5 + protoc --gogo_out=. --proto_path=../../../../../:/usr/local/opt/protobuf/include:. $<
6 +
7 +clean:
8 + rm message.pb.go
exchange/bitswap/testnet/network_test.go
+1 -1
@@ -1,10 +1,10 @@
1 package bitswap
2
3 import (
4 + "context"
5 "sync"
6 "testing"
7
7 - context "context"
8 bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message"
9 bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
10 mockrouting "github.com/ipfs/go-ipfs/routing/mock"
exchange/bitswap/testnet/peernet.go
+1
@@ -2,6 +2,7 @@ package bitswap
2
3 import (
4 "context"
5 +
6 bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
7 mockrouting "github.com/ipfs/go-ipfs/routing/mock"
8 ds "gx/ipfs/QmVSase1JP7cq9QkPT46oNwdp9pT6kBkG3oqS14y3QcZjG/go-datastore"
exchange/reprovide/reprovide_test.go
+1 -1
@@ -1,9 +1,9 @@
1 package reprovide_test
2
3 import (
4 + "context"
5 "testing"
6
6 - context "context"
7 blockstore "github.com/ipfs/go-ipfs/blocks/blockstore"
8 mock "github.com/ipfs/go-ipfs/routing/mock"
9 pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore"
fuse/ipns/common.go
+1 -1
@@ -1,7 +1,7 @@
1 package ipns
2
3 import (
4 - context "context"
4 + "context"
5
6 "github.com/ipfs/go-ipfs/core"
7 nsys "github.com/ipfs/go-ipfs/namesys"
fuse/node/mount_test.go
+2 -1
@@ -9,7 +9,8 @@ import (
9 "testing"
10 "time"
11
12 - context "context"
12 + "context"
13 +
14 core "github.com/ipfs/go-ipfs/core"
15 ipns "github.com/ipfs/go-ipfs/fuse/ipns"
16 mount "github.com/ipfs/go-ipfs/fuse/mount"
importer/balanced/balanced_test.go
+1 -1
@@ -2,6 +2,7 @@ package balanced
2
3 import (
4 "bytes"
5 + "context"
6 "fmt"
7 "io"
8 "io/ioutil"
@@ -14,7 +15,6 @@ import (
15 mdtest "github.com/ipfs/go-ipfs/merkledag/test"
16 uio "github.com/ipfs/go-ipfs/unixfs/io"
17
17 - "context"
18 u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
19 )
20
importer/chunk/rabin_test.go
+3 -2
@@ -3,10 +3,11 @@ package chunk
3 import (
4 "bytes"
5 "fmt"
6 - "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
7 - "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format"
6 "io"
7 "testing"
8 +
9 + util "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
10 + blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format"
11 )
12
13 func TestRabinChunking(t *testing.T) {
importer/helpers/dagbuilder.go
+1 -1
@@ -4,13 +4,13 @@ import (
4 "io"
5 "os"
6
7 - "github.com/ipfs/go-ipfs/commands/files"
7 "github.com/ipfs/go-ipfs/importer/chunk"
8 dag "github.com/ipfs/go-ipfs/merkledag"
9 ft "github.com/ipfs/go-ipfs/unixfs"
10
11 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
12 node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format"
13 + files "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files"
14 )
15
16 // DagBuilderHelper wraps together a bunch of objects needed to
importer/importer.go
+1 -1
@@ -6,12 +6,12 @@ import (
6 "fmt"
7 "os"
8
9 - "github.com/ipfs/go-ipfs/commands/files"
9 bal "github.com/ipfs/go-ipfs/importer/balanced"
10 "github.com/ipfs/go-ipfs/importer/chunk"
11 h "github.com/ipfs/go-ipfs/importer/helpers"
12 trickle "github.com/ipfs/go-ipfs/importer/trickle"
13 dag "github.com/ipfs/go-ipfs/merkledag"
14 + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files"
15
16 node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format"
17 )
merkledag/utils/utils_test.go
+1 -1
@@ -1,13 +1,13 @@
1 package dagutils
2
3 import (
4 + "context"
5 "testing"
6
7 dag "github.com/ipfs/go-ipfs/merkledag"
8 mdtest "github.com/ipfs/go-ipfs/merkledag/test"
9 path "github.com/ipfs/go-ipfs/path"
10
10 - context "context"
11 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
12 )
13
mfs/repub_test.go
+2 -3
@@ -1,13 +1,12 @@
1 package mfs
2
3 import (
4 + "context"
5 "testing"
6 "time"
7
7 - ci "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil/ci"
8 -
9 - "context"
8 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
9 + ci "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil/ci"
10 )
11
12 func TestRepublisher(t *testing.T) {
namesys/dns.go
-1
@@ -7,7 +7,6 @@ import (
7 "strings"
8
9 path "github.com/ipfs/go-ipfs/path"
10 -
10 isd "gx/ipfs/QmZmmuAXgX73UQmX1jRKjTGmjzq24Jinqkq8vzkBtno4uX/go-is-domain"
11 )
12
namesys/interface.go
+1
@@ -34,6 +34,7 @@ import (
34 "time"
35
36 context "context"
37 +
38 path "github.com/ipfs/go-ipfs/path"
39 ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto"
40 )
namesys/ipns_select_test.go
+2 -2
@@ -6,11 +6,11 @@ import (
6 "testing"
7 "time"
8
9 - proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
10 -
9 pb "github.com/ipfs/go-ipfs/namesys/pb"
10 path "github.com/ipfs/go-ipfs/path"
11 +
12 u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
13 + proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
14 ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto"
15 )
16
namesys/proquint.go
+1
@@ -4,6 +4,7 @@ import (
4 "errors"
5
6 context "context"
7 +
8 path "github.com/ipfs/go-ipfs/path"
9 proquint "gx/ipfs/QmYnf27kzqR2cxt6LFZdrAFJuQd6785fTkBvMuEj9EeRxM/proquint"
10 )
namesys/republisher/repub_test.go
+3 -3
@@ -1,20 +1,20 @@
1 package republisher_test
2
3 import (
4 + "context"
5 "errors"
6 "testing"
7 "time"
8
8 - context "context"
9 - goprocess "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess"
10 -
9 "github.com/ipfs/go-ipfs/core"
10 mock "github.com/ipfs/go-ipfs/core/mock"
11 namesys "github.com/ipfs/go-ipfs/namesys"
12 . "github.com/ipfs/go-ipfs/namesys/republisher"
13 path "github.com/ipfs/go-ipfs/path"
14 +
15 pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore"
16 mocknet "gx/ipfs/QmefgzMbKZYsmHFkLqxgaTBG9ypeEjrdWRD5WXH4j1cWDL/go-libp2p/p2p/net/mock"
17 + goprocess "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess"
18 )
19
20 func TestRepublish(t *testing.T) {
package.json
+10
@@ -413,6 +413,16 @@
413 "name": "go-libp2p-swarm",
414 "version": "2.0.5"
415 },
416 + {
417 + "hash": "QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe",
418 + "name": "go-ipfs-cmds",
419 + "version": "0.4.5"
420 + },
421 + {
422 + "hash": "QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf",
423 + "name": "go-ipfs-cmdkit",
424 + "version": "0.3.3"
425 + },
426 {
427 "author": "whyrusleeping",
428 "hash": "QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU",
repo/config/identity.go
+1
@@ -2,6 +2,7 @@ package config
2
3 import (
4 "encoding/base64"
5 +
6 ic "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto"
7 )
8
routing/offline/offline_test.go
+3 -2
@@ -3,9 +3,10 @@ package offline
3 import (
4 "bytes"
5 "context"
6 - ds "gx/ipfs/QmVSase1JP7cq9QkPT46oNwdp9pT6kBkG3oqS14y3QcZjG/go-datastore"
7 - "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil"
6 "testing"
7 +
8 + "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil"
9 + ds "gx/ipfs/QmVSase1JP7cq9QkPT46oNwdp9pT6kBkG3oqS14y3QcZjG/go-datastore"
10 )
11
12 func TestOfflineRouterStorage(t *testing.T) {
test/integration/addcat_test.go
+2 -1
@@ -2,6 +2,7 @@ package integrationtest
2
3 import (
4 "bytes"
5 + "context"
6 "errors"
7 "fmt"
8 "io"
@@ -10,13 +11,13 @@ import (
11 "testing"
12 "time"
13
13 - context "context"
14 random "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-random"
15
16 "github.com/ipfs/go-ipfs/core"
17 coreunix "github.com/ipfs/go-ipfs/core/coreunix"
18 mock "github.com/ipfs/go-ipfs/core/mock"
19 "github.com/ipfs/go-ipfs/thirdparty/unit"
20 +
21 pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore"
22 logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
23 testutil "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil"
test/integration/bench_cat_test.go
+2 -1
@@ -2,16 +2,17 @@ package integrationtest
2
3 import (
4 "bytes"
5 + "context"
6 "errors"
7 "io"
8 "math"
9 "testing"
10
10 - context "context"
11 "github.com/ipfs/go-ipfs/core"
12 coreunix "github.com/ipfs/go-ipfs/core/coreunix"
13 mock "github.com/ipfs/go-ipfs/core/mock"
14 "github.com/ipfs/go-ipfs/thirdparty/unit"
15 +
16 pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore"
17 testutil "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil"
18 mocknet "gx/ipfs/QmefgzMbKZYsmHFkLqxgaTBG9ypeEjrdWRD5WXH4j1cWDL/go-libp2p/p2p/net/mock"
test/integration/bitswap_wo_routing_test.go
+1 -1
@@ -2,13 +2,13 @@ package integrationtest
2
3 import (
4 "bytes"
5 + "context"
6 "testing"
7
8 "github.com/ipfs/go-ipfs/core"
9 "github.com/ipfs/go-ipfs/core/mock"
10 "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format"
11
11 - context "context"
12 cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
13 mocknet "gx/ipfs/QmefgzMbKZYsmHFkLqxgaTBG9ypeEjrdWRD5WXH4j1cWDL/go-libp2p/p2p/net/mock"
14 )
test/integration/three_legged_cat_test.go
+2 -2
@@ -2,18 +2,18 @@ package integrationtest
2
3 import (
4 "bytes"
5 + "context"
6 "errors"
7 "io"
8 "math"
9 "testing"
10 "time"
11
11 - context "context"
12 -
12 core "github.com/ipfs/go-ipfs/core"
13 coreunix "github.com/ipfs/go-ipfs/core/coreunix"
14 mock "github.com/ipfs/go-ipfs/core/mock"
15 "github.com/ipfs/go-ipfs/thirdparty/unit"
16 +
17 pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore"
18 testutil "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil"
19 mocknet "gx/ipfs/QmefgzMbKZYsmHFkLqxgaTBG9ypeEjrdWRD5WXH4j1cWDL/go-libp2p/p2p/net/mock"