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"