浏览代码

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 <cpuguy83@gmail.com>
Brian Goff 9 年之前
父节点
当前提交
5c8950e84d
共有 3 个文件被更改,包括 80 次插入15 次删除
  1. 59 0
      api/client/commands.go
  2. 14 15
      cli/cli.go
  3. 7 0
      cmd/docker/daemon.go

+ 59 - 0
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]
+}

+ 14 - 15
cli/cli.go

@@ -5,7 +5,6 @@ import (
 	"fmt"
 	"fmt"
 	"io"
 	"io"
 	"os"
 	"os"
-	"reflect"
 	"strings"
 	"strings"
 
 
 	flag "github.com/docker/docker/pkg/mflag"
 	flag "github.com/docker/docker/pkg/mflag"
@@ -21,7 +20,9 @@ type Cli struct {
 // Handler holds the different commands Cli will call
 // Handler holds the different commands Cli will call
 // It should have methods with names starting with `Cmd` like:
 // It should have methods with names starting with `Cmd` like:
 // 	func (h myHandler) CmdFoo(args ...string) error
 // 	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
 // Initializer can be optionally implemented by a Handler to
 // initialize before each call to one of its commands.
 // 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 {
 		if c == nil {
 			continue
 			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 nil, initErr{err}
 				}
 				}
 			}
 			}
-			return method.Interface().(func(...string) error), nil
+			return cmd, nil
 		}
 		}
 	}
 	}
 	return nil, errors.New("command not found")
 	return nil, errors.New("command not found")
@@ -103,6 +95,13 @@ func (cli *Cli) noSuchCommand(command string) {
 	os.Exit(1)
 	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.
 // CmdHelp displays information on a Docker command.
 //
 //
 // If more than one command is specified, information is only shown for the first command.
 // If more than one command is specified, information is only shown for the first command.

+ 7 - 0
cmd/docker/daemon.go

@@ -9,3 +9,10 @@ type DaemonProxy struct{}
 func NewDaemonProxy() DaemonProxy {
 func NewDaemonProxy() DaemonProxy {
 	return 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]
+}