diff --git a/engine/engine.go b/engine/engine.go index 5814955fdd..68e109e7f2 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -9,6 +9,7 @@ import ( "os" "path/filepath" "runtime" + "sort" "strings" ) @@ -29,6 +30,10 @@ func Register(name string, handler Handler) error { return nil } +func unregister(name string) { + delete(globalHandlers, name) +} + // The Engine is the core of Docker. // It acts as a store for *containers*, and allows manipulation of these // containers by executing *jobs*. @@ -106,6 +111,12 @@ func New(root string) (*Engine, error) { Stderr: os.Stderr, Stdin: os.Stdin, } + eng.Register("commands", func(job *Job) Status { + for _, name := range eng.commands() { + job.Printf("%s\n", name) + } + return StatusOK + }) // Copy existing global handlers for k, v := range globalHandlers { eng.handlers[k] = v @@ -117,6 +128,17 @@ func (eng *Engine) String() string { return fmt.Sprintf("%s|%s", eng.Root(), eng.id[:8]) } +// Commands returns a list of all currently registered commands, +// sorted alphabetically. +func (eng *Engine) commands() []string { + names := make([]string, 0, len(eng.handlers)) + for name := range eng.handlers { + names = append(names, name) + } + sort.Strings(names) + return names +} + // Job creates a new job which can later be executed. // This function mimics `Command` from the standard os/exec package. func (eng *Engine) Job(name string, args ...string) *Job { diff --git a/engine/engine_test.go b/engine/engine_test.go index cb3b939cbc..a16c352678 100644 --- a/engine/engine_test.go +++ b/engine/engine_test.go @@ -1,6 +1,7 @@ package engine import ( + "bytes" "io/ioutil" "os" "path" @@ -17,6 +18,8 @@ func TestRegister(t *testing.T) { if err := Register("dummy1", nil); err == nil { t.Fatalf("Expecting error, got none") } + // Register is global so let's cleanup to avoid conflicts + defer unregister("dummy1") eng := newTestEngine(t) @@ -33,6 +36,7 @@ func TestRegister(t *testing.T) { if err := eng.Register("dummy2", nil); err == nil { t.Fatalf("Expecting error, got none") } + defer unregister("dummy2") } func TestJob(t *testing.T) { @@ -49,6 +53,7 @@ func TestJob(t *testing.T) { } eng.Register("dummy2", h) + defer unregister("dummy2") job2 := eng.Job("dummy2", "--level=awesome") if job2.handler == nil { @@ -60,6 +65,24 @@ func TestJob(t *testing.T) { } } +func TestEngineCommands(t *testing.T) { + eng := newTestEngine(t) + defer os.RemoveAll(eng.Root()) + handler := func(job *Job) Status { return StatusOK } + eng.Register("foo", handler) + eng.Register("bar", handler) + eng.Register("echo", handler) + eng.Register("die", handler) + var output bytes.Buffer + commands := eng.Job("commands") + commands.Stdout.Add(&output) + commands.Run() + expected := "bar\ncommands\ndie\necho\nfoo\n" + if result := output.String(); result != expected { + t.Fatalf("Unexpected output:\nExpected = %v\nResult = %v\n", expected, result) + } +} + func TestEngineRoot(t *testing.T) { tmp, err := ioutil.TempDir("", "docker-test-TestEngineCreateDir") if err != nil {