cmds: use Executors
- some fixes for cmds1.0 - reinsert plugin loading code, pretty print wrapper TODO: if plugin loading fails it only calls log.Warning. returning an error would be better but that would have to happen after PreRun, which is not possible atm. License: MIT Signed-off-by: keks <keks@cryptoscope.co>
keks committed
Dec 7, 2017 at 19:33 UTC
feef5c3415ec249cf307f43a422545de24aee319
9 files changed
+141
-278
cmd/ipfs/main.go
+58
-262
@@ -22,7 +22,7 @@ import (
22
core "github.com/ipfs/go-ipfs/core"
23
coreCmds "github.com/ipfs/go-ipfs/core/commands"
24
corehttp "github.com/ipfs/go-ipfs/core/corehttp"
25
- "github.com/ipfs/go-ipfs/plugin/loader"
25
+ loader "github.com/ipfs/go-ipfs/plugin/loader"
26
repo "github.com/ipfs/go-ipfs/repo"
27
config "github.com/ipfs/go-ipfs/repo/config"
28
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
@@ -31,7 +31,6 @@ import (
31
manet "gx/ipfs/QmSGL5Uoa6gKHgBBwQG8u1CWKUC8ZnwaZiLgFVTFBR2bxr/go-multiaddr-net"
32
logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
33
loggables "gx/ipfs/QmSvcDkiRwB8LuMhUtnvhum2C851Mproo75ZDD19jx43tD/go-libp2p-loggables"
34
- "gx/ipfs/QmVD1W3MC8Hk1WZgFQPWWmBECJ3X72BgUYf9eCQ4PGzPps/go-ipfs-cmdkit"
34
ma "gx/ipfs/QmW8s4zTsUoX1Q6CeYxVKPyqSKbF7H1YDUyTostBtZ8DaG/go-multiaddr"
35
osh "gx/ipfs/QmXuBJ7DR6k3rmUEKtvVMhwjmXDuJgXXPUt4LQXKBMsU93/go-os-helper"
36
"gx/ipfs/QmYopJAcV7R9SbxiPBCvqhnt8EusQpWPHewoZakCMt8hps/go-ipfs-cmds"
@@ -90,96 +89,64 @@ func mainRet() int {
89
}
90
defer stopFunc() // to be executed as late as possible
91
93
- var invoc cmdInvocation
94
- defer invoc.close()
95
-
96
- // this is a local helper to print out help text.
97
- // there's some considerations that this makes easier.
98
- printHelp := func(long bool, w io.Writer) {
99
- helpFunc := cli.ShortHelp
100
- if long {
101
- helpFunc = cli.LongHelp
102
- }
103
-
104
- var p []string
105
- if invoc.req != nil {
106
- p = invoc.req.Path
107
- }
108
-
109
- helpFunc("ipfs", Root, p, w)
110
- }
111
-
112
- // this is a message to tell the user how to get the help text
113
- printMetaHelp := func(w io.Writer) {
114
- cmdPath := strings.Join(invoc.req.Path, " ")
115
- fmt.Fprintf(w, "Use 'ipfs %s --help' for information about this command\n", cmdPath)
116
- }
92
+ intrh, ctx := setupInterruptHandler(ctx)
93
+ defer intrh.Close()
94
95
// Handle `ipfs help'
96
if len(os.Args) == 2 {
97
if os.Args[1] == "help" {
121
- printHelp(false, os.Stdout)
122
- return 0
98
+ os.Args[1] = "-h"
99
} else if os.Args[1] == "--version" {
100
os.Args[1] = "version"
101
}
102
}
103
128
- intrh, ctx := invoc.SetupInterruptHandler(ctx)
129
- defer intrh.Close()
130
-
131
- // parse the commandline into a command invocation
132
- parseErr := invoc.Parse(ctx, os.Args[1:])
133
-
134
- // BEFORE handling the parse error, if we have enough information
135
- // AND the user requested help, print it out and exit
136
- if invoc.req != nil {
137
- longH, shortH, err := invoc.requestedHelp()
104
+ buildEnv := func(ctx context.Context, req *cmds.Request) (interface{}, error) {
105
+ repoPath, err := getRepoPath(req)
106
if err != nil {
139
- printErr(err)
140
- return 1
141
- }
142
- if longH || shortH {
143
- printHelp(longH, os.Stdout)
144
- return 0
107
+ return nil, err
108
}
146
- }
109
+ log.Debugf("config path is %s", repoPath)
110
148
- // ok now handle parse error (which means cli input was wrong,
149
- // e.g. incorrect number of args, or nonexistent subcommand)
150
- if parseErr != nil {
151
- printErr(parseErr)
111
+ // this sets up the function that will initialize the config lazily.
112
153
- // this was a user error, print help.
154
- if invoc.req != nil && invoc.req.Command != nil {
155
- // we need a newline space.
156
- fmt.Fprintf(os.Stderr, "\n")
157
- printHelp(false, os.Stderr)
158
- }
159
- return 1
160
- }
113
+ // this sets up the function that will initialize the node
114
+ // this is so that we can construct the node lazily.
115
162
- // here we handle the cases where
163
- // - commands with no Run func are invoked directly.
164
- // - the main command is invoked.
165
- if invoc.req == nil || invoc.req.Command == nil || invoc.req.Command.Run == nil {
166
- printHelp(false, os.Stdout)
167
- return 0
168
- }
116
+ return &oldcmds.Context{
117
+ ConfigRoot: repoPath,
118
+ LoadConfig: loadConfig,
119
+ ReqLog: &oldcmds.ReqLog{},
120
+ ConstructNode: func() (n *core.IpfsNode, err error) {
121
+ if req == nil {
122
+ return nil, errors.New("constructing node without a request")
123
+ }
124
170
- // ok, finally, run the command invocation.
171
- err = invoc.Run(ctx)
172
- if err != nil {
173
- if code, ok := err.(exitErr); ok {
174
- return int(code)
175
- }
125
+ r, err := fsrepo.Open(repoPath)
126
+ if err != nil { // repo is owned by the node
127
+ return nil, err
128
+ }
129
177
- printErr(err)
130
+ // ok everything is good. set it on the invocation (for ownership)
131
+ // and return it.
132
+ n, err = core.NewNode(ctx, &core.BuildCfg{
133
+ // TODO(keks) figure out how Online was set before. I think it was set to
134
+ // a value that always is the zero value so we can just drop it, but
135
+ // I'll have to check that.
136
+ Repo: r,
137
+ })
138
+ if err != nil {
139
+ return nil, err
140
+ }
141
179
- // if this error was a client error, print short help too.
180
- if isClientError(err) {
181
- printMetaHelp(os.Stderr)
182
- }
142
+ n.SetLocal(true)
143
+ return n, nil
144
+ },
145
+ }, nil
146
+ }
147
+
148
+ err = cli.Run(ctx, Root, os.Args, os.Stdin, os.Stdout, os.Stderr, buildEnv, makeExecutor)
149
+ if err != nil {
150
return 1
151
}
152
@@ -187,10 +154,9 @@ func mainRet() int {
154
return 0
155
}
156
190
-func (i *cmdInvocation) Run(ctx context.Context) error {
191
-
157
+func checkDebug(req *cmds.Request) {
158
// check if user wants to debug. option OR env var.
193
- debug, _ := i.req.Options["debug"].(bool)
159
+ debug, _ := req.Options["debug"].(bool)
160
if debug || os.Getenv("IPFS_LOGGING") == "debug" {
161
u.Debug = true
162
logging.SetDebugLogging()
@@ -198,193 +164,33 @@ func (i *cmdInvocation) Run(ctx context.Context) error {
164
if u.GetenvBool("DEBUG") {
165
u.Debug = true
166
}
201
-
202
- return callCommand(ctx, i.req, Root, i.ctx)
203
-}
204
-
205
-func (i *cmdInvocation) constructNodeFunc(ctx context.Context) func() (*core.IpfsNode, error) {
206
- return func() (n *core.IpfsNode, err error) {
207
- if i.req == nil {
208
- return nil, errors.New("constructing node without a request")
209
- }
210
-
211
- r, err := fsrepo.Open(i.ctx.ConfigRoot)
212
- if err != nil { // repo is owned by the node
213
- return nil, err
214
- }
215
-
216
- // ok everything is good. set it on the invocation (for ownership)
217
- // and return it.
218
- n, err = core.NewNode(ctx, &core.BuildCfg{
219
- Online: i.ctx.Online,
220
- Repo: r,
221
- })
222
- if err != nil {
223
- return nil, err
224
- }
225
- n.SetLocal(true)
226
- i.node = n
227
- return i.node, nil
228
- }
229
-}
230
-
231
-func (i *cmdInvocation) close() {
232
- // let's not forget teardown. If a node was initialized, we must close it.
233
- // Note that this means the underlying req.Context().Node variable is exposed.
234
- // this is gross, and should be changed when we extract out the exec Context.
235
- if i.node != nil {
236
- log.Info("Shutting down node...")
237
- i.node.Close()
238
- }
239
-}
240
-
241
-func (i *cmdInvocation) Parse(ctx context.Context, args []string) error {
242
- var err error
243
-
244
- i.req, err = cli.Parse(args, os.Stdin, Root)
245
- if err != nil {
246
- return err
247
- }
248
-
249
- //TODO remove this
250
- //fmt.Printf("%#v\n", i.req)
251
-
252
- // TODO(keks): pass this as arg to cli.Parse()
253
- i.req.Context = ctx
254
-
255
- repoPath, err := getRepoPath(i.req)
256
- if err != nil {
257
- return err
258
- }
259
- log.Debugf("config path is %s", repoPath)
260
-
261
- // this sets up the function that will initialize the config lazily.
262
- if i.ctx == nil {
263
- i.ctx = &oldcmds.Context{}
264
- }
265
- i.ctx.ConfigRoot = repoPath
266
- i.ctx.LoadConfig = loadConfig
267
- // this sets up the function that will initialize the node
268
- // this is so that we can construct the node lazily.
269
- i.ctx.ConstructNode = i.constructNodeFunc(ctx)
270
-
271
- // if no encoding was specified by user, default to plaintext encoding
272
- // (if command doesn't support plaintext, use JSON instead)
273
- if enc := i.req.Options[cmds.EncLong]; enc == "" {
274
- if i.req.Command.Encoders != nil && i.req.Command.Encoders[cmds.Text] != nil {
275
- i.req.SetOption(cmds.EncLong, cmds.Text)
276
- } else {
277
- i.req.SetOption(cmds.EncLong, cmds.JSON)
278
- }
279
- }
280
-
281
- return nil
282
-}
283
-
284
-func (i *cmdInvocation) requestedHelp() (short bool, long bool, err error) {
285
- longHelp, _ := i.req.Options["help"].(bool)
286
- shortHelp, _ := i.req.Options["h"].(bool)
287
- return longHelp, shortHelp, nil
288
-}
289
-
290
-func callPreCommandHooks(ctx context.Context, details cmdDetails, req *cmds.Request, root *cmds.Command) error {
291
-
292
- log.Event(ctx, "callPreCommandHooks", &details)
293
- log.Debug("calling pre-command hooks...")
294
-
295
- return nil
167
}
168
298
-func callCommand(ctx context.Context, req *cmds.Request, root *cmds.Command, cctx *oldcmds.Context) error {
299
- log.Info(config.EnvDir, " ", cctx.ConfigRoot)
300
- cmd := req.Command
301
-
302
- details, err := commandDetails(req.Path, root)
169
+func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
170
+ checkDebug(req)
171
+ details, err := commandDetails(req.Path, Root)
172
if err != nil {
304
- return err
305
- }
306
-
307
- client, err := commandShouldRunOnDaemon(*details, req, root, cctx)
308
- if err != nil {
309
- return err
173
+ return nil, err
174
}
175
312
- err = callPreCommandHooks(ctx, *details, req, root)
176
+ client, err := commandShouldRunOnDaemon(*details, req, Root, env.(*oldcmds.Context))
177
if err != nil {
314
- return err
315
- }
316
-
317
- encTypeStr, _ := req.Options[cmds.EncLong].(string)
318
- encType := cmds.EncodingType(encTypeStr)
319
-
320
- var (
321
- re cmds.ResponseEmitter
322
- exitCh <-chan int
323
- )
324
-
325
- // first if condition checks the command's encoder map, second checks global encoder map (cmd vs. cmds)
326
- if enc, ok := cmd.Encoders[encType]; ok {
327
- re, exitCh = cli.NewResponseEmitter(os.Stdout, os.Stderr, enc, req)
328
- } else if enc, ok := cmds.Encoders[encType]; ok {
329
- re, exitCh = cli.NewResponseEmitter(os.Stdout, os.Stderr, enc, req)
330
- } else {
331
- return fmt.Errorf("could not find matching encoder for enctype %#v", encType)
332
- }
333
-
334
- if cmd.PreRun != nil {
335
- err = cmd.PreRun(req, cctx)
336
- if err != nil {
337
- return err
338
- }
339
- }
340
-
341
- if cmd.PostRun != nil && cmd.PostRun[cmds.CLI] != nil {
342
- re = cmd.PostRun[cmds.CLI](req, re)
178
+ return nil, err
179
}
180
345
- if client != nil && !cmd.External {
346
- log.Debug("executing command via API")
347
-
348
- res, err := client.Send(req)
349
- if err != nil {
350
- if isConnRefused(err) {
351
- err = repo.ErrApiNotRunning
352
- }
353
-
354
- return wrapContextCanceled(err)
355
- }
356
-
357
- go func() {
358
- err := cmds.Copy(re, res)
359
- if err != nil {
360
- err = re.Emit(cmdkit.Error{err.Error(), cmdkit.ErrNormal | cmdkit.ErrFatal})
361
- if err != nil {
362
- log.Error(err)
363
- }
364
- }
365
- }()
181
+ var exctr cmds.Executor
182
+ if client != nil && !req.Command.External {
183
+ exctr = client.(cmds.Executor)
184
} else {
367
- log.Debug("executing command locally")
368
-
369
- pluginpath := filepath.Join(cctx.ConfigRoot, "plugins")
185
+ pluginpath := filepath.Join(env.(*oldcmds.Context).ConfigRoot, "plugins")
186
if _, err := loader.LoadPlugins(pluginpath); err != nil {
371
- return err
187
+ log.Warning("error loading plugins: ", err)
188
}
189
374
- // Okay!!!!! NOW we can call the command.
375
- go func() {
376
- err := root.Call(req, re, cctx)
377
- if err != nil {
378
- re.SetError(err, cmdkit.ErrNormal)
379
- }
380
- }()
381
- }
382
-
383
- if returnCode := <-exitCh; returnCode != 0 {
384
- err = exitErr(returnCode)
190
+ exctr = cmds.NewExecutor(req.Root)
191
}
192
387
- return err
193
+ return exctr, nil
194
}
195
196
// commandDetails returns a command's details for the command given by |path|
@@ -468,14 +274,6 @@ func commandShouldRunOnDaemon(details cmdDetails, req *cmds.Request, root *cmds.
274
return nil, nil
275
}
276
471
-func isClientError(err error) bool {
472
- if e, ok := err.(*cmdkit.Error); ok {
473
- return e.Code == cmdkit.ErrClient
474
- }
475
-
476
- return false
477
-}
478
-
277
func getRepoPath(req *cmds.Request) (string, error) {
278
repoOpt, found := req.Options["config"].(string)
279
if found && repoOpt != "" {
@@ -496,7 +294,6 @@ func loadConfig(path string) (*config.Config, error) {
294
// startProfiling begins CPU profiling and returns a `stop` function to be
295
// executed as late as possible. The stop function captures the memprofile.
296
func startProfiling() (func(), error) {
499
-
297
// start CPU profiling as early as possible
298
ofi, err := os.Create(cpuProfile)
299
if err != nil {
@@ -566,8 +363,7 @@ func (ih *IntrHandler) Handle(handler func(count int, ih *IntrHandler), sigs ...
363
}()
364
}
365
569
-func (i *cmdInvocation) SetupInterruptHandler(ctx context.Context) (io.Closer, context.Context) {
570
-
366
+func setupInterruptHandler(ctx context.Context) (io.Closer, context.Context) {
367
intrh := NewIntrHandler()
368
ctx, cancelFunc := context.WithCancel(ctx)
369
commands/legacy/request.go
+26
-1
@@ -20,6 +20,14 @@ type requestWrapper struct {
20
ctx *oldcmds.Context
21
}
22
23
+func (r *requestWrapper) String() string {
24
+ return fmt.Sprintf("{%v, %v}", r.req, r.ctx)
25
+}
26
+
27
+func (r *requestWrapper) GoString() string {
28
+ return fmt.Sprintf("lgc.Request{%#v, %#v}", r.req, r.ctx)
29
+}
30
+
31
// InvocContext retuns the invocation context of the oldcmds.Request.
32
// It is faked using OldContext().
33
func (r *requestWrapper) InvocContext() *oldcmds.Context {
@@ -36,6 +44,19 @@ func (r *requestWrapper) SetInvocContext(ctx oldcmds.Context) {
44
func (r *requestWrapper) Command() *oldcmds.Command { return nil }
45
46
func (r *requestWrapper) Arguments() []string {
47
+ cmdArgs := r.req.Command.Arguments
48
+ reqArgs := r.req.Arguments
49
+
50
+ // TODO figure out the exaclt policy for when to use these automatically
51
+ // TODO once that's done, change the log.Debug below to log.Error
52
+ // read arguments from body if we don't have all of them or the command has variadic arguemnts
53
+ if len(reqArgs) < len(cmdArgs) ||
54
+ len(cmdArgs) > 0 && cmdArgs[len(cmdArgs)-1].Variadic {
55
+ err := r.req.ParseBodyArgs()
56
+ if err != nil {
57
+ log.Debug("error reading arguments from stdin: ", err)
58
+ }
59
+ }
60
return r.req.Arguments
61
}
62
@@ -54,7 +75,11 @@ func (r *requestWrapper) Files() files.File {
75
func (r *requestWrapper) Option(name string) *cmdkit.OptionValue {
76
var option cmdkit.Option
77
57
- for _, def := range r.req.Command.Options {
78
+ optDefs, err := r.req.Root.GetOptions(r.req.Path)
79
+ if err != nil {
80
+ return &cmdkit.OptionValue{nil, false, nil}
81
+ }
82
+ for _, def := range optDefs {
83
for _, optName := range def.Names() {
84
if name == optName {
85
option = def
commands/request.go
+29
@@ -9,6 +9,7 @@ import (
9
"os"
10
"reflect"
11
"strconv"
12
+ "strings"
13
"time"
14
15
"github.com/ipfs/go-ipfs/core"
@@ -17,6 +18,7 @@ import (
18
19
"gx/ipfs/QmVD1W3MC8Hk1WZgFQPWWmBECJ3X72BgUYf9eCQ4PGzPps/go-ipfs-cmdkit"
20
"gx/ipfs/QmVD1W3MC8Hk1WZgFQPWWmBECJ3X72BgUYf9eCQ4PGzPps/go-ipfs-cmdkit/files"
21
+ "gx/ipfs/QmYopJAcV7R9SbxiPBCvqhnt8EusQpWPHewoZakCMt8hps/go-ipfs-cmds"
22
)
23
24
type Context struct {
@@ -74,6 +76,33 @@ func (c *Context) RootContext() context.Context {
76
return n.Context()
77
}
78
79
+func (c *Context) LogRequest(req *cmds.Request) func() {
80
+ rle := &ReqLogEntry{
81
+ StartTime: time.Now(),
82
+ Active: true,
83
+ Command: strings.Join(req.Path, "/"),
84
+ Options: req.Options,
85
+ Args: req.Arguments,
86
+ ID: c.ReqLog.nextID,
87
+ log: c.ReqLog,
88
+ }
89
+ c.ReqLog.AddEntry(rle)
90
+
91
+ return func() {
92
+ c.ReqLog.Finish(rle)
93
+ }
94
+}
95
+
96
+func (c *Context) Close() {
97
+ // let's not forget teardown. If a node was initialized, we must close it.
98
+ // Note that this means the underlying req.Context().Node variable is exposed.
99
+ // this is gross, and should be changed when we extract out the exec Context.
100
+ if c.node != nil {
101
+ log.Info("Shutting down node...")
102
+ c.node.Close()
103
+ }
104
+}
105
+
106
// Request represents a call to a command from a consumer
107
type Request interface {
108
Path() []string
core/commands/add.go
+1
-1
@@ -429,7 +429,7 @@ You can now check what blocks have been created by:
429
bar.ShowTimeLeft = true
430
}
431
case <-req.Context.Done():
432
- re.SetError(req.Context.Err(), cmdkit.ErrNormal)
432
+ //re.SetError(req.Context.Err(), cmdkit.ErrNormal)
433
return
434
}
435
}
core/commands/dag/dag.go
+3
@@ -13,12 +13,15 @@ import (
13
path "github.com/ipfs/go-ipfs/path"
14
pin "github.com/ipfs/go-ipfs/pin"
15
16
+ logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
17
cmdkit "gx/ipfs/QmVD1W3MC8Hk1WZgFQPWWmBECJ3X72BgUYf9eCQ4PGzPps/go-ipfs-cmdkit"
18
files "gx/ipfs/QmVD1W3MC8Hk1WZgFQPWWmBECJ3X72BgUYf9eCQ4PGzPps/go-ipfs-cmdkit/files"
19
mh "gx/ipfs/QmYeKnKpubCMRiq3PGZcTREErthbb5Q9cXsCoSkD9bjEBd/go-multihash"
20
cid "gx/ipfs/QmeSrf6pzut73u6zLQkRFQ3ygt3k6XFT2kjdYP8Tnkwwyg/go-cid"
21
)
22
23
+var log = logging.Logger("cmds/files")
24
+
25
var DagCmd = &cmds.Command{
26
Helptext: cmdkit.HelpText{
27
Tagline: "Interact with ipld dag objects.",
core/commands/files/files.go
+11
-9
@@ -67,6 +67,12 @@ var hashOption = cmdkit.StringOption("hash", "Hash function to use. Will set Cid
67
68
var formatError = errors.New("Format was set by multiple options. Only one format option is allowed")
69
70
+const defaultStatFormat = `<hash>
71
+Size: <size>
72
+CumulativeSize: <cumulsize>
73
+ChildBlocks: <childs>
74
+Type: <type>`
75
+
76
var FilesStatCmd = &cmds.Command{
77
Helptext: cmdkit.HelpText{
78
Tagline: "Display file status.",
@@ -77,12 +83,7 @@ var FilesStatCmd = &cmds.Command{
83
},
84
Options: []cmdkit.Option{
85
cmdkit.StringOption("format", "Print statistics in given format. Allowed tokens: "+
80
- "<hash> <size> <cumulsize> <type> <childs>. Conflicts with other format options.").WithDefault(
81
- `<hash>
82
-Size: <size>
83
-CumulativeSize: <cumulsize>
84
-ChildBlocks: <childs>
85
-Type: <type>`),
86
+ "<hash> <size> <cumulsize> <type> <childs>. Conflicts with other format options.").WithDefault(defaultStatFormat),
87
cmdkit.BoolOption("hash", "Print only hash. Implies '--format=<hash>'. Conflicts with other format options."),
88
cmdkit.BoolOption("size", "Print only size. Implies '--format=<cumulsize>'. Conflicts with other format options."),
89
},
@@ -154,9 +155,9 @@ func statGetFormatOptions(req cmds.Request) (string, error) {
155
156
hash, _, _ := req.Option("hash").Bool()
157
size, _, _ := req.Option("size").Bool()
157
- format, found, _ := req.Option("format").String()
158
+ format, _, _ := req.Option("format").String()
159
159
- if moreThanOne(hash, size, found) {
160
+ if moreThanOne(hash, size, format != defaultStatFormat) {
161
return "", formatError
162
}
163
@@ -235,6 +236,7 @@ var FilesCpCmd = &cmds.Command{
236
}
237
238
flush, _, _ := req.Option("flush").Bool()
239
+ fmt.Println("flush:", flush)
240
241
src, err := checkPath(req.Arguments()[0])
242
if err != nil {
@@ -636,7 +638,7 @@ stat' on the file or any of its ancestors.
638
hashOption,
639
},
640
Run: func(req cmds.Request, res cmds.Response) {
639
- path, err := checkPath(req.Arguments()[0])
641
+ path, err := checkPath(req.StringArguments()[0])
642
if err != nil {
643
res.SetError(err, cmdkit.ErrNormal)
644
return
core/commands/get.go
+3
-3
@@ -257,13 +257,13 @@ func (gw *getWriter) writeExtracted(r io.Reader, fpath string) error {
257
258
func getCompressOptions(req *cmds.Request) (int, error) {
259
cmprs, _ := req.Options["compress"].(bool)
260
- cmplvl, cmplvlFound := req.Options["compression-level"].(int)
260
+ cmplvl, _ := req.Options["compression-level"].(int)
261
switch {
262
case !cmprs:
263
return gzip.NoCompression, nil
264
- case cmprs && !cmplvlFound:
264
+ case cmprs && cmplvl == -1:
265
return gzip.DefaultCompression, nil
266
- case cmprs && cmplvlFound && (cmplvl < 1 || cmplvl > 9):
266
+ case cmprs && (cmplvl < 1 || cmplvl > 9):
267
return gzip.NoCompression, ErrInvalidCompressionLevel
268
}
269
return cmplvl, nil
core/commands/object/patch.go
+5
-2
@@ -13,9 +13,12 @@ import (
13
path "github.com/ipfs/go-ipfs/path"
14
ft "github.com/ipfs/go-ipfs/unixfs"
15
16
+ logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
17
cmdkit "gx/ipfs/QmVD1W3MC8Hk1WZgFQPWWmBECJ3X72BgUYf9eCQ4PGzPps/go-ipfs-cmdkit"
18
)
19
20
+var log = logging.Logger("core/commands/object")
21
+
22
var ObjectPatchCmd = &cmds.Command{
23
Helptext: cmdkit.HelpText{
24
Tagline: "Create a new merkledag object based on an existing one.",
@@ -74,7 +77,7 @@ the limit will not be respected by the network.
77
return
78
}
79
77
- root, err := path.ParsePath(req.Arguments()[0])
80
+ root, err := path.ParsePath(req.StringArguments()[0])
81
if err != nil {
82
res.SetError(err, cmdkit.ErrNormal)
83
return
@@ -142,7 +145,7 @@ Example:
145
return
146
}
147
145
- rp, err := path.ParsePath(req.Arguments()[0])
148
+ rp, err := path.ParsePath(req.StringArguments()[0])
149
if err != nil {
150
res.SetError(err, cmdkit.ErrNormal)
151
return
repo/config/init.go
+5
@@ -25,6 +25,11 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) {
25
datastore := DefaultDatastoreConfig()
26
27
conf := &Config{
28
+ API: API{
29
+ HTTPHeaders: map[string][]string{
30
+ "Server": {"go-ipfs/" + CurrentVersionNumber},
31
+ },
32
+ },
33
34
// setup the node's default addresses.
35
// NOTE: two swarm listen addrs, one tcp, one utp.