@cryptotaxi247 / kubo / commits / feef5c341

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.