Browse code

Merge pull request #4314 from shykes/engine-commands

Engine: builtin command 'commands' returns a list of registered commands

Solomon Hykes authored on 2014/02/26 02:59:26
Showing 2 changed files
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"os"
10 10
 	"path/filepath"
11 11
 	"runtime"
12
+	"sort"
12 13
 	"strings"
13 14
 )
14 15
 
... ...
@@ -29,6 +30,10 @@ func Register(name string, handler Handler) error {
29 29
 	return nil
30 30
 }
31 31
 
32
+func unregister(name string) {
33
+	delete(globalHandlers, name)
34
+}
35
+
32 36
 // The Engine is the core of Docker.
33 37
 // It acts as a store for *containers*, and allows manipulation of these
34 38
 // containers by executing *jobs*.
... ...
@@ -106,6 +111,12 @@ func New(root string) (*Engine, error) {
106 106
 		Stderr:   os.Stderr,
107 107
 		Stdin:    os.Stdin,
108 108
 	}
109
+	eng.Register("commands", func(job *Job) Status {
110
+		for _, name := range eng.commands() {
111
+			job.Printf("%s\n", name)
112
+		}
113
+		return StatusOK
114
+	})
109 115
 	// Copy existing global handlers
110 116
 	for k, v := range globalHandlers {
111 117
 		eng.handlers[k] = v
... ...
@@ -117,6 +128,17 @@ func (eng *Engine) String() string {
117 117
 	return fmt.Sprintf("%s|%s", eng.Root(), eng.id[:8])
118 118
 }
119 119
 
120
+// Commands returns a list of all currently registered commands,
121
+// sorted alphabetically.
122
+func (eng *Engine) commands() []string {
123
+	names := make([]string, 0, len(eng.handlers))
124
+	for name := range eng.handlers {
125
+		names = append(names, name)
126
+	}
127
+	sort.Strings(names)
128
+	return names
129
+}
130
+
120 131
 // Job creates a new job which can later be executed.
121 132
 // This function mimics `Command` from the standard os/exec package.
122 133
 func (eng *Engine) Job(name string, args ...string) *Job {
... ...
@@ -1,6 +1,7 @@
1 1
 package engine
2 2
 
3 3
 import (
4
+	"bytes"
4 5
 	"io/ioutil"
5 6
 	"os"
6 7
 	"path"
... ...
@@ -17,6 +18,8 @@ func TestRegister(t *testing.T) {
17 17
 	if err := Register("dummy1", nil); err == nil {
18 18
 		t.Fatalf("Expecting error, got none")
19 19
 	}
20
+	// Register is global so let's cleanup to avoid conflicts
21
+	defer unregister("dummy1")
20 22
 
21 23
 	eng := newTestEngine(t)
22 24
 
... ...
@@ -33,6 +36,7 @@ func TestRegister(t *testing.T) {
33 33
 	if err := eng.Register("dummy2", nil); err == nil {
34 34
 		t.Fatalf("Expecting error, got none")
35 35
 	}
36
+	defer unregister("dummy2")
36 37
 }
37 38
 
38 39
 func TestJob(t *testing.T) {
... ...
@@ -49,6 +53,7 @@ func TestJob(t *testing.T) {
49 49
 	}
50 50
 
51 51
 	eng.Register("dummy2", h)
52
+	defer unregister("dummy2")
52 53
 	job2 := eng.Job("dummy2", "--level=awesome")
53 54
 
54 55
 	if job2.handler == nil {
... ...
@@ -60,6 +65,24 @@ func TestJob(t *testing.T) {
60 60
 	}
61 61
 }
62 62
 
63
+func TestEngineCommands(t *testing.T) {
64
+	eng := newTestEngine(t)
65
+	defer os.RemoveAll(eng.Root())
66
+	handler := func(job *Job) Status { return StatusOK }
67
+	eng.Register("foo", handler)
68
+	eng.Register("bar", handler)
69
+	eng.Register("echo", handler)
70
+	eng.Register("die", handler)
71
+	var output bytes.Buffer
72
+	commands := eng.Job("commands")
73
+	commands.Stdout.Add(&output)
74
+	commands.Run()
75
+	expected := "bar\ncommands\ndie\necho\nfoo\n"
76
+	if result := output.String(); result != expected {
77
+		t.Fatalf("Unexpected output:\nExpected = %v\nResult   = %v\n", expected, result)
78
+	}
79
+}
80
+
63 81
 func TestEngineRoot(t *testing.T) {
64 82
 	tmp, err := ioutil.TempDir("", "docker-test-TestEngineCreateDir")
65 83
 	if err != nil {