From 5c8950e84d2384919f45209f8cc4cbf00ff29015 Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Fri, 29 Apr 2016 11:16:34 -0400 Subject: [PATCH] Remove reflection on CLI init before: ``` $ time docker --help real 0m0.177s user 0m0.000s sys 0m0.040s ``` after: ``` $ time docker --help real 0m0.010s user 0m0.000s sys 0m0.000s ``` Signed-off-by: Brian Goff --- api/client/commands.go | 59 ++++++++++++++++++++++++++++++++++++++++++ cli/cli.go | 29 ++++++++++----------- cmd/docker/daemon.go | 7 +++++ 3 files changed, 80 insertions(+), 15 deletions(-) create mode 100644 api/client/commands.go diff --git a/api/client/commands.go b/api/client/commands.go new file mode 100644 index 0000000000..08346af7de --- /dev/null +++ b/api/client/commands.go @@ -0,0 +1,59 @@ +package client + +// Command returns a cli command handler if one exists +func (cli *DockerCli) Command(name string) func(...string) error { + return map[string]func(...string) error{ + "attach": cli.CmdAttach, + "build": cli.CmdBuild, + "commit": cli.CmdCommit, + "cp": cli.CmdCp, + "create": cli.CmdCreate, + "diff": cli.CmdDiff, + "events": cli.CmdEvents, + "exec": cli.CmdExec, + "export": cli.CmdExport, + "history": cli.CmdHistory, + "images": cli.CmdImages, + "import": cli.CmdImport, + "info": cli.CmdInfo, + "inspect": cli.CmdInspect, + "kill": cli.CmdKill, + "load": cli.CmdLoad, + "login": cli.CmdLogin, + "logout": cli.CmdLogout, + "logs": cli.CmdLogs, + "network": cli.CmdNetwork, + "network create": cli.CmdNetworkCreate, + "network connect": cli.CmdNetworkConnect, + "network disconnect": cli.CmdNetworkDisconnect, + "network inspect": cli.CmdNetworkInspect, + "network ls": cli.CmdNetworkLs, + "network rm": cli.CmdNetworkRm, + "pause": cli.CmdPause, + "port": cli.CmdPort, + "ps": cli.CmdPs, + "pull": cli.CmdPull, + "push": cli.CmdPush, + "rename": cli.CmdRename, + "restart": cli.CmdRestart, + "rm": cli.CmdRm, + "rmi": cli.CmdRmi, + "run": cli.CmdRun, + "save": cli.CmdSave, + "search": cli.CmdSearch, + "start": cli.CmdStart, + "stats": cli.CmdStats, + "stop": cli.CmdStop, + "tag": cli.CmdTag, + "top": cli.CmdTop, + "unpause": cli.CmdUnpause, + "update": cli.CmdUpdate, + "version": cli.CmdVersion, + "volume": cli.CmdVolume, + "volume create": cli.CmdVolumeCreate, + "volume inspect": cli.CmdVolumeInspect, + "volume ls": cli.CmdVolumeLs, + "volume rm": cli.CmdVolumeRm, + "wait": cli.CmdWait, + }[name] +} diff --git a/cli/cli.go b/cli/cli.go index 88c6e68c24..12649df6da 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -5,7 +5,6 @@ import ( "fmt" "io" "os" - "reflect" "strings" flag "github.com/docker/docker/pkg/mflag" @@ -21,7 +20,9 @@ type Cli struct { // Handler holds the different commands Cli will call // It should have methods with names starting with `Cmd` like: // func (h myHandler) CmdFoo(args ...string) error -type Handler interface{} +type Handler interface { + Command(name string) func(...string) error +} // Initializer can be optionally implemented by a Handler to // initialize before each call to one of its commands. @@ -50,22 +51,13 @@ func (cli *Cli) command(args ...string) (func(...string) error, error) { if c == nil { continue } - camelArgs := make([]string, len(args)) - for i, s := range args { - if len(s) == 0 { - return nil, errors.New("empty command") - } - camelArgs[i] = strings.ToUpper(s[:1]) + strings.ToLower(s[1:]) - } - methodName := "Cmd" + strings.Join(camelArgs, "") - method := reflect.ValueOf(c).MethodByName(methodName) - if method.IsValid() { - if c, ok := c.(Initializer); ok { - if err := c.Initialize(); err != nil { + if cmd := c.Command(strings.Join(args, " ")); cmd != nil { + if ci, ok := c.(Initializer); ok { + if err := ci.Initialize(); err != nil { return nil, initErr{err} } } - return method.Interface().(func(...string) error), nil + return cmd, nil } } return nil, errors.New("command not found") @@ -103,6 +95,13 @@ func (cli *Cli) noSuchCommand(command string) { os.Exit(1) } +// Command returns a command handler, or nil if the command does not exist +func (cli *Cli) Command(name string) func(...string) error { + return map[string]func(...string) error{ + "help": cli.CmdHelp, + }[name] +} + // CmdHelp displays information on a Docker command. // // If more than one command is specified, information is only shown for the first command. diff --git a/cmd/docker/daemon.go b/cmd/docker/daemon.go index 15dffbaefb..8fe3484761 100644 --- a/cmd/docker/daemon.go +++ b/cmd/docker/daemon.go @@ -9,3 +9,10 @@ type DaemonProxy struct{} func NewDaemonProxy() DaemonProxy { return DaemonProxy{} } + +// Command returns a cli command handler if one exists +func (p DaemonProxy) Command(name string) func(...string) error { + return map[string]func(...string) error{ + "daemon": p.CmdDaemon, + }[name] +}