mirror of
https://github.com/ipfs/kubo.git
synced 2025-05-21 08:56:37 +08:00
refactor: get rid of cmdDetails awkwardness
This commit is contained in:
@ -182,6 +182,8 @@ Headers.
|
||||
// cmds.StringOption(swarmAddrKwd, "Address for the swarm socket (overrides config)"),
|
||||
},
|
||||
Subcommands: map[string]*cmds.Command{},
|
||||
NoRemote: true,
|
||||
Extra: commands.CreateCmdExtras(commands.SetDoesNotUseConfigAsInput(true)),
|
||||
Run: daemonFunc,
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
assets "github.com/ipfs/go-ipfs/assets"
|
||||
oldcmds "github.com/ipfs/go-ipfs/commands"
|
||||
core "github.com/ipfs/go-ipfs/core"
|
||||
"github.com/ipfs/go-ipfs/core/commands"
|
||||
namesys "github.com/ipfs/go-ipfs/namesys"
|
||||
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
|
||||
|
||||
@ -66,6 +67,8 @@ environment variable:
|
||||
// name of the file?
|
||||
// TODO cmds.StringOption("event-logs", "l", "Location for machine-readable event logs."),
|
||||
},
|
||||
NoRemote: true,
|
||||
Extra: commands.CreateCmdExtras(commands.SetDoesNotUseRepo(true), commands.SetDoesNotUseConfigAsInput(true)),
|
||||
PreRun: func(req *cmds.Request, env cmds.Environment) error {
|
||||
cctx := env.(*oldcmds.Context)
|
||||
daemonLocked, err := fsrepo.LockedByOtherProcess(cctx.ConfigRoot)
|
||||
|
@ -1,8 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
commands "github.com/ipfs/go-ipfs/core/commands"
|
||||
|
||||
cmds "github.com/ipfs/go-ipfs-cmds"
|
||||
@ -39,59 +37,3 @@ func init() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NB: when necessary, properties are described using negatives in order to
|
||||
// provide desirable defaults
|
||||
type cmdDetails struct {
|
||||
cannotRunOnClient bool
|
||||
cannotRunOnDaemon bool
|
||||
doesNotUseRepo bool
|
||||
|
||||
// doesNotUseConfigAsInput describes commands that do not use the config as
|
||||
// input. These commands either initialize the config or perform operations
|
||||
// that don't require access to the config.
|
||||
//
|
||||
// pre-command hooks that require configs must not be run before these
|
||||
// commands.
|
||||
doesNotUseConfigAsInput bool
|
||||
|
||||
// preemptsAutoUpdate describes commands that must be executed without the
|
||||
// auto-update pre-command hook
|
||||
preemptsAutoUpdate bool
|
||||
}
|
||||
|
||||
func (d *cmdDetails) String() string {
|
||||
return fmt.Sprintf("on client? %t, on daemon? %t, uses repo? %t",
|
||||
d.canRunOnClient(), d.canRunOnDaemon(), d.usesRepo())
|
||||
}
|
||||
|
||||
func (d *cmdDetails) Loggable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"canRunOnClient": d.canRunOnClient(),
|
||||
"canRunOnDaemon": d.canRunOnDaemon(),
|
||||
"preemptsAutoUpdate": d.preemptsAutoUpdate,
|
||||
"usesConfigAsInput": d.usesConfigAsInput(),
|
||||
"usesRepo": d.usesRepo(),
|
||||
}
|
||||
}
|
||||
|
||||
func (d *cmdDetails) usesConfigAsInput() bool { return !d.doesNotUseConfigAsInput }
|
||||
func (d *cmdDetails) canRunOnClient() bool { return !d.cannotRunOnClient }
|
||||
func (d *cmdDetails) canRunOnDaemon() bool { return !d.cannotRunOnDaemon }
|
||||
func (d *cmdDetails) usesRepo() bool { return !d.doesNotUseRepo }
|
||||
|
||||
// "What is this madness!?" you ask. Our commands have the unfortunate problem of
|
||||
// not being able to run on all the same contexts. This map describes these
|
||||
// properties so that other code can make decisions about whether to invoke a
|
||||
// command or return an error to the user.
|
||||
var cmdDetailsMap = map[string]cmdDetails{
|
||||
"init": {doesNotUseConfigAsInput: true, cannotRunOnDaemon: true, doesNotUseRepo: true},
|
||||
"daemon": {doesNotUseConfigAsInput: true, cannotRunOnDaemon: true},
|
||||
"commands": {doesNotUseRepo: true},
|
||||
"version": {doesNotUseConfigAsInput: true, doesNotUseRepo: true}, // must be permitted to run before init
|
||||
"log": {cannotRunOnClient: true},
|
||||
"diag/cmds": {cannotRunOnClient: true},
|
||||
"repo/fsck": {cannotRunOnDaemon: true},
|
||||
"config/edit": {cannotRunOnDaemon: true, doesNotUseRepo: true},
|
||||
"cid": {doesNotUseRepo: true},
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime/pprof"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
util "github.com/ipfs/go-ipfs/cmd/ipfs/util"
|
||||
@ -202,16 +201,17 @@ func apiAddrOption(req *cmds.Request) (ma.Multiaddr, error) {
|
||||
func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
|
||||
exe := cmds.NewExecutor(req.Root)
|
||||
cctx := env.(*oldcmds.Context)
|
||||
details := commandDetails(req.Path)
|
||||
|
||||
// Check if the command is disabled.
|
||||
if details.cannotRunOnClient && details.cannotRunOnDaemon {
|
||||
if req.Command.NoLocal && req.Command.NoRemote {
|
||||
return nil, fmt.Errorf("command disabled: %v", req.Path)
|
||||
}
|
||||
|
||||
// Can we just run this locally?
|
||||
if !details.cannotRunOnClient && details.doesNotUseRepo {
|
||||
return exe, nil
|
||||
if !req.Command.NoLocal {
|
||||
if doesNotUseRepo, ok := corecmds.GetDoesNotUseRepo(req.Command.Extra); doesNotUseRepo && ok {
|
||||
return exe, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Get the API option from the commandline.
|
||||
@ -225,7 +225,7 @@ func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
|
||||
daemonRequested := apiAddr != nil && req.Command != daemonCmd
|
||||
|
||||
// Run this on the client if required.
|
||||
if details.cannotRunOnDaemon || req.Command.External {
|
||||
if req.Command.NoRemote {
|
||||
if daemonRequested {
|
||||
// User requested that the command be run on the daemon but we can't.
|
||||
// NOTE: We drop this check for the `ipfs daemon` command.
|
||||
@ -247,7 +247,7 @@ func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
|
||||
|
||||
// Still no api specified? Run it on the client or fail.
|
||||
if apiAddr == nil {
|
||||
if details.cannotRunOnClient {
|
||||
if req.Command.NoLocal {
|
||||
return nil, fmt.Errorf("command must be run on the daemon: %v", req.Path)
|
||||
}
|
||||
return exe, nil
|
||||
@ -293,22 +293,6 @@ func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
|
||||
return cmdhttp.NewClient(host, opts...), nil
|
||||
}
|
||||
|
||||
// commandDetails returns a command's details for the command given by |path|.
|
||||
func commandDetails(path []string) cmdDetails {
|
||||
if len(path) == 0 {
|
||||
// special case root command
|
||||
return cmdDetails{doesNotUseRepo: true}
|
||||
}
|
||||
var details cmdDetails
|
||||
// find the last command in path that has a cmdDetailsMap entry
|
||||
for i := range path {
|
||||
if cmdDetails, found := cmdDetailsMap[strings.Join(path[:i+1], "/")]; found {
|
||||
details = cmdDetails
|
||||
}
|
||||
}
|
||||
return details
|
||||
}
|
||||
|
||||
func getRepoPath(req *cmds.Request) (string, error) {
|
||||
repoOpt, found := req.Options["config"].(string)
|
||||
if found && repoOpt != "" {
|
||||
|
@ -36,6 +36,7 @@ environment variable:
|
||||
cmds.StringOption(algorithmOptionName, "a", "Cryptographic algorithm to use for key generation.").WithDefault(algorithmDefault),
|
||||
cmds.IntOption(bitsOptionName, "b", "Number of bits to use in the generated RSA private key."),
|
||||
},
|
||||
NoRemote: true,
|
||||
PreRun: func(req *cmds.Request, env cmds.Environment) error {
|
||||
cctx := env.(*oldcmds.Context)
|
||||
daemonLocked, err := fsrepo.LockedByOtherProcess(cctx.ConfigRoot)
|
||||
|
@ -23,6 +23,7 @@ var ActiveReqsCmd = &cmds.Command{
|
||||
Lists running and recently run commands.
|
||||
`,
|
||||
},
|
||||
NoLocal: true,
|
||||
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
|
||||
ctx := env.(*oldcmds.Context)
|
||||
return cmds.EmitOnce(res, ctx.ReqLog.Report())
|
||||
|
@ -26,6 +26,7 @@ var CidCmd = &cmds.Command{
|
||||
"codecs": codecsCmd,
|
||||
"hashes": hashesCmd,
|
||||
},
|
||||
Extra: CreateCmdExtras(SetDoesNotUseRepo(true)),
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -66,6 +66,7 @@ func CommandsCmd(root *cmds.Command) *cmds.Command {
|
||||
Options: []cmds.Option{
|
||||
cmds.BoolOption(flagsOptionName, "f", "Show command flags"),
|
||||
},
|
||||
Extra: CreateCmdExtras(SetDoesNotUseRepo(true)),
|
||||
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
|
||||
rootCmd := cmd2outputCmd("ipfs", root)
|
||||
rootCmd.showOpts, _ = req.Options[flagsOptionName].(bool)
|
||||
|
@ -239,7 +239,8 @@ To use 'ipfs config edit', you must have the $EDITOR environment
|
||||
variable set to your preferred text editor.
|
||||
`,
|
||||
},
|
||||
|
||||
NoRemote: true,
|
||||
Extra: CreateCmdExtras(SetDoesNotUseRepo(true)),
|
||||
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
|
||||
cfgRoot, err := cmdenv.GetConfigRoot(env)
|
||||
if err != nil {
|
||||
|
@ -17,6 +17,7 @@ func ExternalBinary(instructions string) *cmds.Command {
|
||||
cmds.StringArg("args", false, true, "Arguments for subcommand."),
|
||||
},
|
||||
External: true,
|
||||
NoRemote: true,
|
||||
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
|
||||
binname := strings.Join(append([]string{"ipfs"}, req.Path...), "-")
|
||||
_, err := exec.LookPath(binname)
|
||||
|
65
core/commands/extra.go
Normal file
65
core/commands/extra.go
Normal file
@ -0,0 +1,65 @@
|
||||
package commands
|
||||
|
||||
import cmds "github.com/ipfs/go-ipfs-cmds"
|
||||
|
||||
func CreateCmdExtras(opts ...func(e *cmds.Extra)) *cmds.Extra {
|
||||
e := new(cmds.Extra)
|
||||
for _, o := range opts {
|
||||
o(e)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
type doesNotUseRepo struct{}
|
||||
|
||||
func SetDoesNotUseRepo(val bool) func(e *cmds.Extra) {
|
||||
return func(e *cmds.Extra) {
|
||||
e.SetValue(doesNotUseRepo{}, val)
|
||||
}
|
||||
}
|
||||
|
||||
func GetDoesNotUseRepo(e *cmds.Extra) (val bool, found bool) {
|
||||
return getBoolFlag(e, doesNotUseRepo{})
|
||||
}
|
||||
|
||||
// doesNotUseConfigAsInput describes commands that do not use the config as
|
||||
// input. These commands either initialize the config or perform operations
|
||||
// that don't require access to the config.
|
||||
//
|
||||
// pre-command hooks that require configs must not be run before these
|
||||
// commands.
|
||||
type doesNotUseConfigAsInput struct{}
|
||||
|
||||
func SetDoesNotUseConfigAsInput(val bool) func(e *cmds.Extra) {
|
||||
return func(e *cmds.Extra) {
|
||||
e.SetValue(doesNotUseConfigAsInput{}, val)
|
||||
}
|
||||
}
|
||||
|
||||
func GetDoesNotUseConfigAsInput(e *cmds.Extra) (val bool, found bool) {
|
||||
return getBoolFlag(e, doesNotUseConfigAsInput{})
|
||||
}
|
||||
|
||||
// preemptsAutoUpdate describes commands that must be executed without the
|
||||
// auto-update pre-command hook
|
||||
type preemptsAutoUpdate struct{}
|
||||
|
||||
func SetPreemptsAutoUpdate(val bool) func(e *cmds.Extra) {
|
||||
return func(e *cmds.Extra) {
|
||||
e.SetValue(preemptsAutoUpdate{}, val)
|
||||
}
|
||||
}
|
||||
|
||||
func GetPreemptsAutoUpdate(e *cmds.Extra) (val bool, found bool) {
|
||||
return getBoolFlag(e, preemptsAutoUpdate{})
|
||||
}
|
||||
|
||||
func getBoolFlag(e *cmds.Extra, key interface{}) (val bool, found bool) {
|
||||
var ival interface{}
|
||||
ival, found = e.GetValue(key)
|
||||
if !found {
|
||||
return false, false
|
||||
}
|
||||
val = ival.(bool)
|
||||
return val, found
|
||||
}
|
@ -144,6 +144,7 @@ path can be specified with '--output=<path>' or '-o=<path>'.
|
||||
Options: []cmds.Option{
|
||||
cmds.StringOption(outputOptionName, "o", "The path where the output should be stored."),
|
||||
},
|
||||
NoRemote: true,
|
||||
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
|
||||
name := req.Arguments[0]
|
||||
|
||||
|
@ -55,6 +55,7 @@ the event log.
|
||||
One of: debug, info, warn, error, dpanic, panic, fatal.
|
||||
`),
|
||||
},
|
||||
NoLocal: true,
|
||||
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
|
||||
args := req.Arguments
|
||||
subsystem, level := args[0], args[1]
|
||||
|
@ -217,6 +217,7 @@ var repoFsckCmd = &cmds.Command{
|
||||
'ipfs repo fsck' is now a no-op.
|
||||
`,
|
||||
},
|
||||
NoRemote: true,
|
||||
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
|
||||
return cmds.EmitOnce(res, &MessageOutput{"`ipfs repo fsck` is deprecated and does nothing.\n"})
|
||||
},
|
||||
|
@ -43,6 +43,8 @@ var VersionCmd = &cmds.Command{
|
||||
cmds.BoolOption(versionRepoOptionName, "Show repo version."),
|
||||
cmds.BoolOption(versionAllOptionName, "Show all version information"),
|
||||
},
|
||||
// must be permitted to run before init
|
||||
Extra: CreateCmdExtras(SetDoesNotUseRepo(true), SetDoesNotUseConfigAsInput(true)),
|
||||
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
|
||||
return cmds.EmitOnce(res, &VersionOutput{
|
||||
Version: version.CurrentVersionNumber,
|
||||
|
2
go.mod
2
go.mod
@ -31,7 +31,7 @@ require (
|
||||
github.com/ipfs/go-graphsync v0.0.5
|
||||
github.com/ipfs/go-ipfs-blockstore v0.1.4
|
||||
github.com/ipfs/go-ipfs-chunker v0.0.5
|
||||
github.com/ipfs/go-ipfs-cmds v0.2.9
|
||||
github.com/ipfs/go-ipfs-cmds v0.3.0
|
||||
github.com/ipfs/go-ipfs-config v0.9.0
|
||||
github.com/ipfs/go-ipfs-ds-help v0.1.1
|
||||
github.com/ipfs/go-ipfs-exchange-interface v0.0.1
|
||||
|
4
go.sum
4
go.sum
@ -340,8 +340,8 @@ github.com/ipfs/go-ipfs-chunker v0.0.1 h1:cHUUxKFQ99pozdahi+uSC/3Y6HeRpi9oTeUHbE
|
||||
github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw=
|
||||
github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8=
|
||||
github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8=
|
||||
github.com/ipfs/go-ipfs-cmds v0.2.9 h1:zQTENe9UJrtCb2bOtRoDGjtuo3rQjmuPdPnVlqoBV/M=
|
||||
github.com/ipfs/go-ipfs-cmds v0.2.9/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk=
|
||||
github.com/ipfs/go-ipfs-cmds v0.3.0 h1:mi9oYrSCox5aBhutqAYqw6/9crlyGbw4E/aJtwS4zI4=
|
||||
github.com/ipfs/go-ipfs-cmds v0.3.0/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk=
|
||||
github.com/ipfs/go-ipfs-config v0.9.0 h1:qTXJ9CyOyQv1LFJUMysxz8fi6RxxnP9QqcmiobuANvw=
|
||||
github.com/ipfs/go-ipfs-config v0.9.0/go.mod h1:GQUxqb0NfkZmEU92PxqqqLVVFTLpoGGUlBaTyDaAqrE=
|
||||
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
|
||||
|
Reference in New Issue
Block a user