@cryptotaxi247 / kubo / commits / 692e9f59f

refactor: get rid of cmdDetails awkwardness

Adin Schmahmann committed Jul 20, 2020 at 16:38 UTC 692e9f59ff985b7771df6cd63dbde16ff8078ee1
17 files changed +92 -85
cmd/ipfs/daemon.go
+2
@@ -182,6 +182,8 @@ Headers.
182 // cmds.StringOption(swarmAddrKwd, "Address for the swarm socket (overrides config)"),
183 },
184 Subcommands: map[string]*cmds.Command{},
185 + NoRemote: true,
186 + Extra: commands.CreateCmdExtras(commands.SetDoesNotUseConfigAsInput(true)),
187 Run: daemonFunc,
188 }
189
cmd/ipfs/init.go
+3
@@ -13,6 +13,7 @@ import (
13 assets "github.com/ipfs/go-ipfs/assets"
14 oldcmds "github.com/ipfs/go-ipfs/commands"
15 core "github.com/ipfs/go-ipfs/core"
16 + "github.com/ipfs/go-ipfs/core/commands"
17 namesys "github.com/ipfs/go-ipfs/namesys"
18 fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
19
@@ -66,6 +67,8 @@ environment variable:
67 // name of the file?
68 // TODO cmds.StringOption("event-logs", "l", "Location for machine-readable event logs."),
69 },
70 + NoRemote: true,
71 + Extra: commands.CreateCmdExtras(commands.SetDoesNotUseRepo(true), commands.SetDoesNotUseConfigAsInput(true)),
72 PreRun: func(req *cmds.Request, env cmds.Environment) error {
73 cctx := env.(*oldcmds.Context)
74 daemonLocked, err := fsrepo.LockedByOtherProcess(cctx.ConfigRoot)
cmd/ipfs/ipfs.go
-58
@@ -1,8 +1,6 @@
1 package main
2
3 import (
4 - "fmt"
5 -
4 commands "github.com/ipfs/go-ipfs/core/commands"
5
6 cmds "github.com/ipfs/go-ipfs-cmds"
@@ -39,59 +37,3 @@ func init() {
37 }
38 }
39 }
42 -
43 -// NB: when necessary, properties are described using negatives in order to
44 -// provide desirable defaults
45 -type cmdDetails struct {
46 - cannotRunOnClient bool
47 - cannotRunOnDaemon bool
48 - doesNotUseRepo bool
49 -
50 - // doesNotUseConfigAsInput describes commands that do not use the config as
51 - // input. These commands either initialize the config or perform operations
52 - // that don't require access to the config.
53 - //
54 - // pre-command hooks that require configs must not be run before these
55 - // commands.
56 - doesNotUseConfigAsInput bool
57 -
58 - // preemptsAutoUpdate describes commands that must be executed without the
59 - // auto-update pre-command hook
60 - preemptsAutoUpdate bool
61 -}
62 -
63 -func (d *cmdDetails) String() string {
64 - return fmt.Sprintf("on client? %t, on daemon? %t, uses repo? %t",
65 - d.canRunOnClient(), d.canRunOnDaemon(), d.usesRepo())
66 -}
67 -
68 -func (d *cmdDetails) Loggable() map[string]interface{} {
69 - return map[string]interface{}{
70 - "canRunOnClient": d.canRunOnClient(),
71 - "canRunOnDaemon": d.canRunOnDaemon(),
72 - "preemptsAutoUpdate": d.preemptsAutoUpdate,
73 - "usesConfigAsInput": d.usesConfigAsInput(),
74 - "usesRepo": d.usesRepo(),
75 - }
76 -}
77 -
78 -func (d *cmdDetails) usesConfigAsInput() bool { return !d.doesNotUseConfigAsInput }
79 -func (d *cmdDetails) canRunOnClient() bool { return !d.cannotRunOnClient }
80 -func (d *cmdDetails) canRunOnDaemon() bool { return !d.cannotRunOnDaemon }
81 -func (d *cmdDetails) usesRepo() bool { return !d.doesNotUseRepo }
82 -
83 -// "What is this madness!?" you ask. Our commands have the unfortunate problem of
84 -// not being able to run on all the same contexts. This map describes these
85 -// properties so that other code can make decisions about whether to invoke a
86 -// command or return an error to the user.
87 -var cmdDetailsMap = map[string]cmdDetails{
88 - "init": {doesNotUseConfigAsInput: true, cannotRunOnDaemon: true, doesNotUseRepo: true},
89 - "daemon": {doesNotUseConfigAsInput: true, cannotRunOnDaemon: true},
90 - "commands": {doesNotUseRepo: true},
91 - "version": {doesNotUseConfigAsInput: true, doesNotUseRepo: true}, // must be permitted to run before init
92 - "log": {cannotRunOnClient: true},
93 - "diag/cmds": {cannotRunOnClient: true},
94 - "repo/fsck": {cannotRunOnDaemon: true},
95 - "config/edit": {cannotRunOnDaemon: true, doesNotUseRepo: true},
96 - "cid": {doesNotUseRepo: true},
97 -}
cmd/ipfs/main.go
+7 -23
@@ -10,7 +10,6 @@ import (
10 "net/http"
11 "os"
12 "runtime/pprof"
13 - "strings"
13 "time"
14
15 util "github.com/ipfs/go-ipfs/cmd/ipfs/util"
@@ -202,16 +201,17 @@ func apiAddrOption(req *cmds.Request) (ma.Multiaddr, error) {
201 func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
202 exe := cmds.NewExecutor(req.Root)
203 cctx := env.(*oldcmds.Context)
205 - details := commandDetails(req.Path)
204
205 // Check if the command is disabled.
208 - if details.cannotRunOnClient && details.cannotRunOnDaemon {
206 + if req.Command.NoLocal && req.Command.NoRemote {
207 return nil, fmt.Errorf("command disabled: %v", req.Path)
208 }
209
210 // Can we just run this locally?
213 - if !details.cannotRunOnClient && details.doesNotUseRepo {
214 - return exe, nil
211 + if !req.Command.NoLocal {
212 + if doesNotUseRepo, ok := corecmds.GetDoesNotUseRepo(req.Command.Extra); doesNotUseRepo && ok {
213 + return exe, nil
214 + }
215 }
216
217 // Get the API option from the commandline.
@@ -225,7 +225,7 @@ func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
225 daemonRequested := apiAddr != nil && req.Command != daemonCmd
226
227 // Run this on the client if required.
228 - if details.cannotRunOnDaemon || req.Command.External {
228 + if req.Command.NoRemote {
229 if daemonRequested {
230 // User requested that the command be run on the daemon but we can't.
231 // NOTE: We drop this check for the `ipfs daemon` command.
@@ -247,7 +247,7 @@ func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
247
248 // Still no api specified? Run it on the client or fail.
249 if apiAddr == nil {
250 - if details.cannotRunOnClient {
250 + if req.Command.NoLocal {
251 return nil, fmt.Errorf("command must be run on the daemon: %v", req.Path)
252 }
253 return exe, nil
@@ -293,22 +293,6 @@ func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
293 return cmdhttp.NewClient(host, opts...), nil
294 }
295
296 -// commandDetails returns a command's details for the command given by |path|.
297 -func commandDetails(path []string) cmdDetails {
298 - if len(path) == 0 {
299 - // special case root command
300 - return cmdDetails{doesNotUseRepo: true}
301 - }
302 - var details cmdDetails
303 - // find the last command in path that has a cmdDetailsMap entry
304 - for i := range path {
305 - if cmdDetails, found := cmdDetailsMap[strings.Join(path[:i+1], "/")]; found {
306 - details = cmdDetails
307 - }
308 - }
309 - return details
310 -}
311 -
296 func getRepoPath(req *cmds.Request) (string, error) {
297 repoOpt, found := req.Options["config"].(string)
298 if found && repoOpt != "" {
cmd/ipfs/rotate.go
+1
@@ -36,6 +36,7 @@ environment variable:
36 cmds.StringOption(algorithmOptionName, "a", "Cryptographic algorithm to use for key generation.").WithDefault(algorithmDefault),
37 cmds.IntOption(bitsOptionName, "b", "Number of bits to use in the generated RSA private key."),
38 },
39 + NoRemote: true,
40 PreRun: func(req *cmds.Request, env cmds.Environment) error {
41 cctx := env.(*oldcmds.Context)
42 daemonLocked, err := fsrepo.LockedByOtherProcess(cctx.ConfigRoot)
core/commands/active.go
+1
@@ -23,6 +23,7 @@ var ActiveReqsCmd = &cmds.Command{
23 Lists running and recently run commands.
24 `,
25 },
26 + NoLocal: true,
27 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
28 ctx := env.(*oldcmds.Context)
29 return cmds.EmitOnce(res, ctx.ReqLog.Report())
core/commands/cid.go
+1
@@ -26,6 +26,7 @@ var CidCmd = &cmds.Command{
26 "codecs": codecsCmd,
27 "hashes": hashesCmd,
28 },
29 + Extra: CreateCmdExtras(SetDoesNotUseRepo(true)),
30 }
31
32 const (
core/commands/commands.go
+1
@@ -66,6 +66,7 @@ func CommandsCmd(root *cmds.Command) *cmds.Command {
66 Options: []cmds.Option{
67 cmds.BoolOption(flagsOptionName, "f", "Show command flags"),
68 },
69 + Extra: CreateCmdExtras(SetDoesNotUseRepo(true)),
70 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
71 rootCmd := cmd2outputCmd("ipfs", root)
72 rootCmd.showOpts, _ = req.Options[flagsOptionName].(bool)
core/commands/config.go
+2 -1
@@ -239,7 +239,8 @@ To use 'ipfs config edit', you must have the $EDITOR environment
239 variable set to your preferred text editor.
240 `,
241 },
242 -
242 + NoRemote: true,
243 + Extra: CreateCmdExtras(SetDoesNotUseRepo(true)),
244 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
245 cfgRoot, err := cmdenv.GetConfigRoot(env)
246 if err != nil {
core/commands/external.go
+1
@@ -17,6 +17,7 @@ func ExternalBinary(instructions string) *cmds.Command {
17 cmds.StringArg("args", false, true, "Arguments for subcommand."),
18 },
19 External: true,
20 + NoRemote: true,
21 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
22 binname := strings.Join(append([]string{"ipfs"}, req.Path...), "-")
23 _, err := exec.LookPath(binname)
core/commands/extra.go new
+65
@@ -0,0 +1,65 @@
1 +package commands
2 +
3 +import cmds "github.com/ipfs/go-ipfs-cmds"
4 +
5 +func CreateCmdExtras(opts ...func(e *cmds.Extra)) *cmds.Extra {
6 + e := new(cmds.Extra)
7 + for _, o := range opts {
8 + o(e)
9 + }
10 + return e
11 +}
12 +
13 +type doesNotUseRepo struct{}
14 +
15 +func SetDoesNotUseRepo(val bool) func(e *cmds.Extra) {
16 + return func(e *cmds.Extra) {
17 + e.SetValue(doesNotUseRepo{}, val)
18 + }
19 +}
20 +
21 +func GetDoesNotUseRepo(e *cmds.Extra) (val bool, found bool) {
22 + return getBoolFlag(e, doesNotUseRepo{})
23 +}
24 +
25 +// doesNotUseConfigAsInput describes commands that do not use the config as
26 +// input. These commands either initialize the config or perform operations
27 +// that don't require access to the config.
28 +//
29 +// pre-command hooks that require configs must not be run before these
30 +// commands.
31 +type doesNotUseConfigAsInput struct{}
32 +
33 +func SetDoesNotUseConfigAsInput(val bool) func(e *cmds.Extra) {
34 + return func(e *cmds.Extra) {
35 + e.SetValue(doesNotUseConfigAsInput{}, val)
36 + }
37 +}
38 +
39 +func GetDoesNotUseConfigAsInput(e *cmds.Extra) (val bool, found bool) {
40 + return getBoolFlag(e, doesNotUseConfigAsInput{})
41 +}
42 +
43 +// preemptsAutoUpdate describes commands that must be executed without the
44 +// auto-update pre-command hook
45 +type preemptsAutoUpdate struct{}
46 +
47 +func SetPreemptsAutoUpdate(val bool) func(e *cmds.Extra) {
48 + return func(e *cmds.Extra) {
49 + e.SetValue(preemptsAutoUpdate{}, val)
50 + }
51 +}
52 +
53 +func GetPreemptsAutoUpdate(e *cmds.Extra) (val bool, found bool) {
54 + return getBoolFlag(e, preemptsAutoUpdate{})
55 +}
56 +
57 +func getBoolFlag(e *cmds.Extra, key interface{}) (val bool, found bool) {
58 + var ival interface{}
59 + ival, found = e.GetValue(key)
60 + if !found {
61 + return false, false
62 + }
63 + val = ival.(bool)
64 + return val, found
65 +}
core/commands/keystore.go
+1
@@ -144,6 +144,7 @@ path can be specified with '--output=<path>' or '-o=<path>'.
144 Options: []cmds.Option{
145 cmds.StringOption(outputOptionName, "o", "The path where the output should be stored."),
146 },
147 + NoRemote: true,
148 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
149 name := req.Arguments[0]
150
core/commands/log.go
+1
@@ -55,6 +55,7 @@ the event log.
55 One of: debug, info, warn, error, dpanic, panic, fatal.
56 `),
57 },
58 + NoLocal: true,
59 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
60 args := req.Arguments
61 subsystem, level := args[0], args[1]
core/commands/repo.go
+1
@@ -217,6 +217,7 @@ var repoFsckCmd = &cmds.Command{
217 'ipfs repo fsck' is now a no-op.
218 `,
219 },
220 + NoRemote: true,
221 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
222 return cmds.EmitOnce(res, &MessageOutput{"`ipfs repo fsck` is deprecated and does nothing.\n"})
223 },
core/commands/version.go
+2
@@ -43,6 +43,8 @@ var VersionCmd = &cmds.Command{
43 cmds.BoolOption(versionRepoOptionName, "Show repo version."),
44 cmds.BoolOption(versionAllOptionName, "Show all version information"),
45 },
46 + // must be permitted to run before init
47 + Extra: CreateCmdExtras(SetDoesNotUseRepo(true), SetDoesNotUseConfigAsInput(true)),
48 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
49 return cmds.EmitOnce(res, &VersionOutput{
50 Version: version.CurrentVersionNumber,
go.mod
+1 -1
@@ -31,7 +31,7 @@ require (
31 github.com/ipfs/go-graphsync v0.0.5
32 github.com/ipfs/go-ipfs-blockstore v0.1.4
33 github.com/ipfs/go-ipfs-chunker v0.0.5
34 - github.com/ipfs/go-ipfs-cmds v0.2.9
34 + github.com/ipfs/go-ipfs-cmds v0.3.0
35 github.com/ipfs/go-ipfs-config v0.9.0
36 github.com/ipfs/go-ipfs-ds-help v0.1.1
37 github.com/ipfs/go-ipfs-exchange-interface v0.0.1
go.sum
+2 -2
@@ -340,8 +340,8 @@ github.com/ipfs/go-ipfs-chunker v0.0.1 h1:cHUUxKFQ99pozdahi+uSC/3Y6HeRpi9oTeUHbE
340 github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw=
341 github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8=
342 github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8=
343 -github.com/ipfs/go-ipfs-cmds v0.2.9 h1:zQTENe9UJrtCb2bOtRoDGjtuo3rQjmuPdPnVlqoBV/M=
344 -github.com/ipfs/go-ipfs-cmds v0.2.9/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk=
343 +github.com/ipfs/go-ipfs-cmds v0.3.0 h1:mi9oYrSCox5aBhutqAYqw6/9crlyGbw4E/aJtwS4zI4=
344 +github.com/ipfs/go-ipfs-cmds v0.3.0/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk=
345 github.com/ipfs/go-ipfs-config v0.9.0 h1:qTXJ9CyOyQv1LFJUMysxz8fi6RxxnP9QqcmiobuANvw=
346 github.com/ipfs/go-ipfs-config v0.9.0/go.mod h1:GQUxqb0NfkZmEU92PxqqqLVVFTLpoGGUlBaTyDaAqrE=
347 github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=