Browse code

split client in 2 files

Docker-DCO-1.1-Signed-off-by: Victor Vieux <victor.vieux@docker.com> (github: vieux)

Victor Vieux authored on 2014/03/29 08:21:55
Showing 4 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,102 @@
0
+package client
1
+
2
+import (
3
+	"crypto/tls"
4
+	"encoding/json"
5
+	"fmt"
6
+	"io"
7
+	"os"
8
+	"reflect"
9
+	"strings"
10
+	"text/template"
11
+
12
+	flag "github.com/dotcloud/docker/pkg/mflag"
13
+	"github.com/dotcloud/docker/pkg/term"
14
+	"github.com/dotcloud/docker/registry"
15
+)
16
+
17
+var funcMap = template.FuncMap{
18
+	"json": func(v interface{}) string {
19
+		a, _ := json.Marshal(v)
20
+		return string(a)
21
+	},
22
+}
23
+
24
+func (cli *DockerCli) getMethod(name string) (func(...string) error, bool) {
25
+	methodName := "Cmd" + strings.ToUpper(name[:1]) + strings.ToLower(name[1:])
26
+	method := reflect.ValueOf(cli).MethodByName(methodName)
27
+	if !method.IsValid() {
28
+		return nil, false
29
+	}
30
+	return method.Interface().(func(...string) error), true
31
+}
32
+
33
+func (cli *DockerCli) ParseCommands(args ...string) error {
34
+	if len(args) > 0 {
35
+		method, exists := cli.getMethod(args[0])
36
+		if !exists {
37
+			fmt.Println("Error: Command not found:", args[0])
38
+			return cli.CmdHelp(args[1:]...)
39
+		}
40
+		return method(args[1:]...)
41
+	}
42
+	return cli.CmdHelp(args...)
43
+}
44
+
45
+func (cli *DockerCli) Subcmd(name, signature, description string) *flag.FlagSet {
46
+	flags := flag.NewFlagSet(name, flag.ContinueOnError)
47
+	flags.Usage = func() {
48
+		fmt.Fprintf(cli.err, "\nUsage: docker %s %s\n\n%s\n\n", name, signature, description)
49
+		flags.PrintDefaults()
50
+		os.Exit(2)
51
+	}
52
+	return flags
53
+}
54
+
55
+func (cli *DockerCli) LoadConfigFile() (err error) {
56
+	cli.configFile, err = registry.LoadConfig(os.Getenv("HOME"))
57
+	if err != nil {
58
+		fmt.Fprintf(cli.err, "WARNING: %s\n", err)
59
+	}
60
+	return err
61
+}
62
+
63
+func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string, tlsConfig *tls.Config) *DockerCli {
64
+	var (
65
+		isTerminal = false
66
+		terminalFd uintptr
67
+	)
68
+
69
+	if in != nil {
70
+		if file, ok := in.(*os.File); ok {
71
+			terminalFd = file.Fd()
72
+			isTerminal = term.IsTerminal(terminalFd)
73
+		}
74
+	}
75
+
76
+	if err == nil {
77
+		err = out
78
+	}
79
+	return &DockerCli{
80
+		proto:      proto,
81
+		addr:       addr,
82
+		in:         in,
83
+		out:        out,
84
+		err:        err,
85
+		isTerminal: isTerminal,
86
+		terminalFd: terminalFd,
87
+		tlsConfig:  tlsConfig,
88
+	}
89
+}
90
+
91
+type DockerCli struct {
92
+	proto      string
93
+	addr       string
94
+	configFile *registry.ConfigFile
95
+	in         io.ReadCloser
96
+	out        io.Writer
97
+	err        io.Writer
98
+	isTerminal bool
99
+	terminalFd uintptr
100
+	tlsConfig  *tls.Config
101
+}
0 102
deleted file mode 100644
... ...
@@ -1,2551 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"bufio"
5
-	"bytes"
6
-	"crypto/tls"
7
-	"encoding/base64"
8
-	"encoding/json"
9
-	"errors"
10
-	"fmt"
11
-	"github.com/dotcloud/docker/api"
12
-	"github.com/dotcloud/docker/archive"
13
-	"github.com/dotcloud/docker/dockerversion"
14
-	"github.com/dotcloud/docker/engine"
15
-	"github.com/dotcloud/docker/nat"
16
-	flag "github.com/dotcloud/docker/pkg/mflag"
17
-	"github.com/dotcloud/docker/pkg/signal"
18
-	"github.com/dotcloud/docker/pkg/term"
19
-	"github.com/dotcloud/docker/registry"
20
-	"github.com/dotcloud/docker/runconfig"
21
-	"github.com/dotcloud/docker/utils"
22
-	"io"
23
-	"io/ioutil"
24
-	"net"
25
-	"net/http"
26
-	"net/http/httputil"
27
-	"net/url"
28
-	"os"
29
-	"os/exec"
30
-	gosignal "os/signal"
31
-	"path"
32
-	"reflect"
33
-	"regexp"
34
-	goruntime "runtime"
35
-	"strconv"
36
-	"strings"
37
-	"syscall"
38
-	"text/tabwriter"
39
-	"text/template"
40
-	"time"
41
-)
42
-
43
-var funcMap = template.FuncMap{
44
-	"json": func(v interface{}) string {
45
-		a, _ := json.Marshal(v)
46
-		return string(a)
47
-	},
48
-}
49
-
50
-var (
51
-	ErrConnectionRefused = errors.New("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
52
-)
53
-
54
-func (cli *DockerCli) getMethod(name string) (func(...string) error, bool) {
55
-	methodName := "Cmd" + strings.ToUpper(name[:1]) + strings.ToLower(name[1:])
56
-	method := reflect.ValueOf(cli).MethodByName(methodName)
57
-	if !method.IsValid() {
58
-		return nil, false
59
-	}
60
-	return method.Interface().(func(...string) error), true
61
-}
62
-
63
-func (cli *DockerCli) ParseCommands(args ...string) error {
64
-	if len(args) > 0 {
65
-		method, exists := cli.getMethod(args[0])
66
-		if !exists {
67
-			fmt.Println("Error: Command not found:", args[0])
68
-			return cli.CmdHelp(args[1:]...)
69
-		}
70
-		return method(args[1:]...)
71
-	}
72
-	return cli.CmdHelp(args...)
73
-}
74
-
75
-func (cli *DockerCli) CmdHelp(args ...string) error {
76
-	if len(args) > 0 {
77
-		method, exists := cli.getMethod(args[0])
78
-		if !exists {
79
-			fmt.Fprintf(cli.err, "Error: Command not found: %s\n", args[0])
80
-		} else {
81
-			method("--help")
82
-			return nil
83
-		}
84
-	}
85
-	help := fmt.Sprintf("Usage: docker [OPTIONS] COMMAND [arg...]\n -H=[unix://%s]: tcp://host:port to bind/connect to or unix://path/to/socket to use\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n", api.DEFAULTUNIXSOCKET)
86
-	for _, command := range [][]string{
87
-		{"attach", "Attach to a running container"},
88
-		{"build", "Build a container from a Dockerfile"},
89
-		{"commit", "Create a new image from a container's changes"},
90
-		{"cp", "Copy files/folders from the containers filesystem to the host path"},
91
-		{"diff", "Inspect changes on a container's filesystem"},
92
-		{"events", "Get real time events from the server"},
93
-		{"export", "Stream the contents of a container as a tar archive"},
94
-		{"history", "Show the history of an image"},
95
-		{"images", "List images"},
96
-		{"import", "Create a new filesystem image from the contents of a tarball"},
97
-		{"info", "Display system-wide information"},
98
-		{"insert", "Insert a file in an image"},
99
-		{"inspect", "Return low-level information on a container"},
100
-		{"kill", "Kill a running container"},
101
-		{"load", "Load an image from a tar archive"},
102
-		{"login", "Register or Login to the docker registry server"},
103
-		{"logs", "Fetch the logs of a container"},
104
-		{"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"},
105
-		{"ps", "List containers"},
106
-		{"pull", "Pull an image or a repository from the docker registry server"},
107
-		{"push", "Push an image or a repository to the docker registry server"},
108
-		{"restart", "Restart a running container"},
109
-		{"rm", "Remove one or more containers"},
110
-		{"rmi", "Remove one or more images"},
111
-		{"run", "Run a command in a new container"},
112
-		{"save", "Save an image to a tar archive"},
113
-		{"search", "Search for an image in the docker index"},
114
-		{"start", "Start a stopped container"},
115
-		{"stop", "Stop a running container"},
116
-		{"tag", "Tag an image into a repository"},
117
-		{"top", "Lookup the running processes of a container"},
118
-		{"version", "Show the docker version information"},
119
-		{"wait", "Block until a container stops, then print its exit code"},
120
-	} {
121
-		help += fmt.Sprintf("    %-10.10s%s\n", command[0], command[1])
122
-	}
123
-	fmt.Fprintf(cli.err, "%s\n", help)
124
-	return nil
125
-}
126
-
127
-func (cli *DockerCli) CmdInsert(args ...string) error {
128
-	cmd := cli.Subcmd("insert", "IMAGE URL PATH", "Insert a file from URL in the IMAGE at PATH")
129
-	if err := cmd.Parse(args); err != nil {
130
-		return nil
131
-	}
132
-	if cmd.NArg() != 3 {
133
-		cmd.Usage()
134
-		return nil
135
-	}
136
-
137
-	v := url.Values{}
138
-	v.Set("url", cmd.Arg(1))
139
-	v.Set("path", cmd.Arg(2))
140
-
141
-	return cli.stream("POST", "/images/"+cmd.Arg(0)+"/insert?"+v.Encode(), nil, cli.out, nil)
142
-}
143
-
144
-func (cli *DockerCli) CmdBuild(args ...string) error {
145
-	cmd := cli.Subcmd("build", "[OPTIONS] PATH | URL | -", "Build a new container image from the source code at PATH")
146
-	tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) to be applied to the resulting image in case of success")
147
-	suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers")
148
-	noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image")
149
-	rm := cmd.Bool([]string{"#rm", "-rm"}, true, "Remove intermediate containers after a successful build")
150
-	if err := cmd.Parse(args); err != nil {
151
-		return nil
152
-	}
153
-	if cmd.NArg() != 1 {
154
-		cmd.Usage()
155
-		return nil
156
-	}
157
-
158
-	var (
159
-		context  archive.Archive
160
-		isRemote bool
161
-		err      error
162
-	)
163
-
164
-	_, err = exec.LookPath("git")
165
-	hasGit := err == nil
166
-	if cmd.Arg(0) == "-" {
167
-		// As a special case, 'docker build -' will build from an empty context with the
168
-		// contents of stdin as a Dockerfile
169
-		dockerfile, err := ioutil.ReadAll(cli.in)
170
-		if err != nil {
171
-			return err
172
-		}
173
-		context, err = archive.Generate("Dockerfile", string(dockerfile))
174
-	} else if utils.IsURL(cmd.Arg(0)) && (!utils.IsGIT(cmd.Arg(0)) || !hasGit) {
175
-		isRemote = true
176
-	} else {
177
-		root := cmd.Arg(0)
178
-		if utils.IsGIT(root) {
179
-			remoteURL := cmd.Arg(0)
180
-			if !strings.HasPrefix(remoteURL, "git://") && !strings.HasPrefix(remoteURL, "git@") && !utils.IsURL(remoteURL) {
181
-				remoteURL = "https://" + remoteURL
182
-			}
183
-
184
-			root, err = ioutil.TempDir("", "docker-build-git")
185
-			if err != nil {
186
-				return err
187
-			}
188
-			defer os.RemoveAll(root)
189
-
190
-			if output, err := exec.Command("git", "clone", "--recursive", remoteURL, root).CombinedOutput(); err != nil {
191
-				return fmt.Errorf("Error trying to use git: %s (%s)", err, output)
192
-			}
193
-		}
194
-		if _, err := os.Stat(root); err != nil {
195
-			return err
196
-		}
197
-		filename := path.Join(root, "Dockerfile")
198
-		if _, err = os.Stat(filename); os.IsNotExist(err) {
199
-			return fmt.Errorf("no Dockerfile found in %s", cmd.Arg(0))
200
-		}
201
-		context, err = archive.Tar(root, archive.Uncompressed)
202
-	}
203
-	var body io.Reader
204
-	// Setup an upload progress bar
205
-	// FIXME: ProgressReader shouldn't be this annoying to use
206
-	if context != nil {
207
-		sf := utils.NewStreamFormatter(false)
208
-		body = utils.ProgressReader(context, 0, cli.err, sf, true, "", "Uploading context")
209
-	}
210
-	// Upload the build context
211
-	v := &url.Values{}
212
-
213
-	//Check if the given image name can be resolved
214
-	if *tag != "" {
215
-		repository, _ := utils.ParseRepositoryTag(*tag)
216
-		if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
217
-			return err
218
-		}
219
-	}
220
-
221
-	v.Set("t", *tag)
222
-
223
-	if *suppressOutput {
224
-		v.Set("q", "1")
225
-	}
226
-	if isRemote {
227
-		v.Set("remote", cmd.Arg(0))
228
-	}
229
-	if *noCache {
230
-		v.Set("nocache", "1")
231
-	}
232
-	if *rm {
233
-		v.Set("rm", "1")
234
-	}
235
-
236
-	cli.LoadConfigFile()
237
-
238
-	headers := http.Header(make(map[string][]string))
239
-	buf, err := json.Marshal(cli.configFile)
240
-	if err != nil {
241
-		return err
242
-	}
243
-	headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
244
-
245
-	if context != nil {
246
-		headers.Set("Content-Type", "application/tar")
247
-	}
248
-	err = cli.stream("POST", fmt.Sprintf("/build?%s", v.Encode()), body, cli.out, headers)
249
-	if jerr, ok := err.(*utils.JSONError); ok {
250
-		// If no error code is set, default to 1
251
-		if jerr.Code == 0 {
252
-			jerr.Code = 1
253
-		}
254
-		return &utils.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
255
-	}
256
-	return err
257
-}
258
-
259
-// 'docker login': login / register a user to registry service.
260
-func (cli *DockerCli) CmdLogin(args ...string) error {
261
-	cmd := cli.Subcmd("login", "[OPTIONS] [SERVER]", "Register or Login to a docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.")
262
-
263
-	var username, password, email string
264
-
265
-	cmd.StringVar(&username, []string{"u", "-username"}, "", "Username")
266
-	cmd.StringVar(&password, []string{"p", "-password"}, "", "Password")
267
-	cmd.StringVar(&email, []string{"e", "-email"}, "", "Email")
268
-	err := cmd.Parse(args)
269
-	if err != nil {
270
-		return nil
271
-	}
272
-	serverAddress := registry.IndexServerAddress()
273
-	if len(cmd.Args()) > 0 {
274
-		serverAddress = cmd.Arg(0)
275
-	}
276
-
277
-	promptDefault := func(prompt string, configDefault string) {
278
-		if configDefault == "" {
279
-			fmt.Fprintf(cli.out, "%s: ", prompt)
280
-		} else {
281
-			fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
282
-		}
283
-	}
284
-
285
-	readInput := func(in io.Reader, out io.Writer) string {
286
-		reader := bufio.NewReader(in)
287
-		line, _, err := reader.ReadLine()
288
-		if err != nil {
289
-			fmt.Fprintln(out, err.Error())
290
-			os.Exit(1)
291
-		}
292
-		return string(line)
293
-	}
294
-
295
-	cli.LoadConfigFile()
296
-	authconfig, ok := cli.configFile.Configs[serverAddress]
297
-	if !ok {
298
-		authconfig = registry.AuthConfig{}
299
-	}
300
-
301
-	if username == "" {
302
-		promptDefault("Username", authconfig.Username)
303
-		username = readInput(cli.in, cli.out)
304
-		if username == "" {
305
-			username = authconfig.Username
306
-		}
307
-	}
308
-	if username != authconfig.Username {
309
-		if password == "" {
310
-			oldState, _ := term.SaveState(cli.terminalFd)
311
-			fmt.Fprintf(cli.out, "Password: ")
312
-			term.DisableEcho(cli.terminalFd, oldState)
313
-
314
-			password = readInput(cli.in, cli.out)
315
-			fmt.Fprint(cli.out, "\n")
316
-
317
-			term.RestoreTerminal(cli.terminalFd, oldState)
318
-			if password == "" {
319
-				return fmt.Errorf("Error : Password Required")
320
-			}
321
-		}
322
-
323
-		if email == "" {
324
-			promptDefault("Email", authconfig.Email)
325
-			email = readInput(cli.in, cli.out)
326
-			if email == "" {
327
-				email = authconfig.Email
328
-			}
329
-		}
330
-	} else {
331
-		password = authconfig.Password
332
-		email = authconfig.Email
333
-	}
334
-	authconfig.Username = username
335
-	authconfig.Password = password
336
-	authconfig.Email = email
337
-	authconfig.ServerAddress = serverAddress
338
-	cli.configFile.Configs[serverAddress] = authconfig
339
-
340
-	stream, statusCode, err := cli.call("POST", "/auth", cli.configFile.Configs[serverAddress], false)
341
-	if statusCode == 401 {
342
-		delete(cli.configFile.Configs, serverAddress)
343
-		registry.SaveConfig(cli.configFile)
344
-		return err
345
-	}
346
-	if err != nil {
347
-		return err
348
-	}
349
-	var out2 engine.Env
350
-	err = out2.Decode(stream)
351
-	if err != nil {
352
-		cli.configFile, _ = registry.LoadConfig(os.Getenv("HOME"))
353
-		return err
354
-	}
355
-	registry.SaveConfig(cli.configFile)
356
-	if out2.Get("Status") != "" {
357
-		fmt.Fprintf(cli.out, "%s\n", out2.Get("Status"))
358
-	}
359
-	return nil
360
-}
361
-
362
-// 'docker wait': block until a container stops
363
-func (cli *DockerCli) CmdWait(args ...string) error {
364
-	cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.")
365
-	if err := cmd.Parse(args); err != nil {
366
-		return nil
367
-	}
368
-	if cmd.NArg() < 1 {
369
-		cmd.Usage()
370
-		return nil
371
-	}
372
-	var encounteredError error
373
-	for _, name := range cmd.Args() {
374
-		status, err := waitForExit(cli, name)
375
-		if err != nil {
376
-			fmt.Fprintf(cli.err, "%s\n", err)
377
-			encounteredError = fmt.Errorf("Error: failed to wait one or more containers")
378
-		} else {
379
-			fmt.Fprintf(cli.out, "%d\n", status)
380
-		}
381
-	}
382
-	return encounteredError
383
-}
384
-
385
-// 'docker version': show version information
386
-func (cli *DockerCli) CmdVersion(args ...string) error {
387
-	cmd := cli.Subcmd("version", "", "Show the docker version information.")
388
-	if err := cmd.Parse(args); err != nil {
389
-		return nil
390
-	}
391
-
392
-	if cmd.NArg() > 0 {
393
-		cmd.Usage()
394
-		return nil
395
-	}
396
-	if dockerversion.VERSION != "" {
397
-		fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
398
-	}
399
-	fmt.Fprintf(cli.out, "Go version (client): %s\n", goruntime.Version())
400
-	if dockerversion.GITCOMMIT != "" {
401
-		fmt.Fprintf(cli.out, "Git commit (client): %s\n", dockerversion.GITCOMMIT)
402
-	}
403
-
404
-	body, _, err := readBody(cli.call("GET", "/version", nil, false))
405
-	if err != nil {
406
-		return err
407
-	}
408
-
409
-	out := engine.NewOutput()
410
-	remoteVersion, err := out.AddEnv()
411
-	if err != nil {
412
-		utils.Errorf("Error reading remote version: %s\n", err)
413
-		return err
414
-	}
415
-	if _, err := out.Write(body); err != nil {
416
-		utils.Errorf("Error reading remote version: %s\n", err)
417
-		return err
418
-	}
419
-	out.Close()
420
-	fmt.Fprintf(cli.out, "Server version: %s\n", remoteVersion.Get("Version"))
421
-	fmt.Fprintf(cli.out, "Git commit (server): %s\n", remoteVersion.Get("GitCommit"))
422
-	fmt.Fprintf(cli.out, "Go version (server): %s\n", remoteVersion.Get("GoVersion"))
423
-	release := utils.GetReleaseVersion()
424
-	if release != "" {
425
-		fmt.Fprintf(cli.out, "Last stable version: %s", release)
426
-		if (dockerversion.VERSION != "" || remoteVersion.Exists("Version")) && (strings.Trim(dockerversion.VERSION, "-dev") != release || strings.Trim(remoteVersion.Get("Version"), "-dev") != release) {
427
-			fmt.Fprintf(cli.out, ", please update docker")
428
-		}
429
-		fmt.Fprintf(cli.out, "\n")
430
-	}
431
-	return nil
432
-}
433
-
434
-// 'docker info': display system-wide information.
435
-func (cli *DockerCli) CmdInfo(args ...string) error {
436
-	cmd := cli.Subcmd("info", "", "Display system-wide information")
437
-	if err := cmd.Parse(args); err != nil {
438
-		return nil
439
-	}
440
-	if cmd.NArg() > 0 {
441
-		cmd.Usage()
442
-		return nil
443
-	}
444
-
445
-	body, _, err := readBody(cli.call("GET", "/info", nil, false))
446
-	if err != nil {
447
-		return err
448
-	}
449
-
450
-	out := engine.NewOutput()
451
-	remoteInfo, err := out.AddEnv()
452
-	if err != nil {
453
-		return err
454
-	}
455
-
456
-	if _, err := out.Write(body); err != nil {
457
-		utils.Errorf("Error reading remote info: %s\n", err)
458
-		return err
459
-	}
460
-	out.Close()
461
-
462
-	fmt.Fprintf(cli.out, "Containers: %d\n", remoteInfo.GetInt("Containers"))
463
-	fmt.Fprintf(cli.out, "Images: %d\n", remoteInfo.GetInt("Images"))
464
-	fmt.Fprintf(cli.out, "Storage Driver: %s\n", remoteInfo.Get("Driver"))
465
-	var driverStatus [][2]string
466
-	if err := remoteInfo.GetJson("DriverStatus", &driverStatus); err != nil {
467
-		return err
468
-	}
469
-	for _, pair := range driverStatus {
470
-		fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1])
471
-	}
472
-	fmt.Fprintf(cli.out, "Execution Driver: %s\n", remoteInfo.Get("ExecutionDriver"))
473
-	fmt.Fprintf(cli.out, "Kernel Version: %s\n", remoteInfo.Get("KernelVersion"))
474
-
475
-	if remoteInfo.GetBool("Debug") || os.Getenv("DEBUG") != "" {
476
-		fmt.Fprintf(cli.out, "Debug mode (server): %v\n", remoteInfo.GetBool("Debug"))
477
-		fmt.Fprintf(cli.out, "Debug mode (client): %v\n", os.Getenv("DEBUG") != "")
478
-		fmt.Fprintf(cli.out, "Fds: %d\n", remoteInfo.GetInt("NFd"))
479
-		fmt.Fprintf(cli.out, "Goroutines: %d\n", remoteInfo.GetInt("NGoroutines"))
480
-		fmt.Fprintf(cli.out, "EventsListeners: %d\n", remoteInfo.GetInt("NEventsListener"))
481
-
482
-		if initSha1 := remoteInfo.Get("InitSha1"); initSha1 != "" {
483
-			fmt.Fprintf(cli.out, "Init SHA1: %s\n", initSha1)
484
-		}
485
-		if initPath := remoteInfo.Get("InitPath"); initPath != "" {
486
-			fmt.Fprintf(cli.out, "Init Path: %s\n", initPath)
487
-		}
488
-	}
489
-
490
-	if len(remoteInfo.GetList("IndexServerAddress")) != 0 {
491
-		cli.LoadConfigFile()
492
-		u := cli.configFile.Configs[remoteInfo.Get("IndexServerAddress")].Username
493
-		if len(u) > 0 {
494
-			fmt.Fprintf(cli.out, "Username: %v\n", u)
495
-			fmt.Fprintf(cli.out, "Registry: %v\n", remoteInfo.GetList("IndexServerAddress"))
496
-		}
497
-	}
498
-	if !remoteInfo.GetBool("MemoryLimit") {
499
-		fmt.Fprintf(cli.err, "WARNING: No memory limit support\n")
500
-	}
501
-	if !remoteInfo.GetBool("SwapLimit") {
502
-		fmt.Fprintf(cli.err, "WARNING: No swap limit support\n")
503
-	}
504
-	if !remoteInfo.GetBool("IPv4Forwarding") {
505
-		fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled.\n")
506
-	}
507
-	return nil
508
-}
509
-
510
-func (cli *DockerCli) CmdStop(args ...string) error {
511
-	cmd := cli.Subcmd("stop", "[OPTIONS] CONTAINER [CONTAINER...]", "Stop a running container (Send SIGTERM, and then SIGKILL after grace period)")
512
-	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it.")
513
-	if err := cmd.Parse(args); err != nil {
514
-		return nil
515
-	}
516
-	if cmd.NArg() < 1 {
517
-		cmd.Usage()
518
-		return nil
519
-	}
520
-
521
-	v := url.Values{}
522
-	v.Set("t", strconv.Itoa(*nSeconds))
523
-
524
-	var encounteredError error
525
-	for _, name := range cmd.Args() {
526
-		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/stop?"+v.Encode(), nil, false))
527
-		if err != nil {
528
-			fmt.Fprintf(cli.err, "%s\n", err)
529
-			encounteredError = fmt.Errorf("Error: failed to stop one or more containers")
530
-		} else {
531
-			fmt.Fprintf(cli.out, "%s\n", name)
532
-		}
533
-	}
534
-	return encounteredError
535
-}
536
-
537
-func (cli *DockerCli) CmdRestart(args ...string) error {
538
-	cmd := cli.Subcmd("restart", "[OPTIONS] CONTAINER [CONTAINER...]", "Restart a running container")
539
-	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default=10")
540
-	if err := cmd.Parse(args); err != nil {
541
-		return nil
542
-	}
543
-	if cmd.NArg() < 1 {
544
-		cmd.Usage()
545
-		return nil
546
-	}
547
-
548
-	v := url.Values{}
549
-	v.Set("t", strconv.Itoa(*nSeconds))
550
-
551
-	var encounteredError error
552
-	for _, name := range cmd.Args() {
553
-		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/restart?"+v.Encode(), nil, false))
554
-		if err != nil {
555
-			fmt.Fprintf(cli.err, "%s\n", err)
556
-			encounteredError = fmt.Errorf("Error: failed to restart one or more containers")
557
-		} else {
558
-			fmt.Fprintf(cli.out, "%s\n", name)
559
-		}
560
-	}
561
-	return encounteredError
562
-}
563
-
564
-func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
565
-	sigc := make(chan os.Signal, 1)
566
-	signal.CatchAll(sigc)
567
-	go func() {
568
-		for s := range sigc {
569
-			if s == syscall.SIGCHLD {
570
-				continue
571
-			}
572
-			var sig string
573
-			for sigStr, sigN := range signal.SignalMap {
574
-				if sigN == s {
575
-					sig = sigStr
576
-					break
577
-				}
578
-			}
579
-			if sig == "" {
580
-				utils.Errorf("Unsupported signal: %d. Discarding.", s)
581
-			}
582
-			if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", cid, sig), nil, false)); err != nil {
583
-				utils.Debugf("Error sending signal: %s", err)
584
-			}
585
-		}
586
-	}()
587
-	return sigc
588
-}
589
-
590
-func (cli *DockerCli) CmdStart(args ...string) error {
591
-	cmd := cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container")
592
-	attach := cmd.Bool([]string{"a", "-attach"}, false, "Attach container's stdout/stderr and forward all signals to the process")
593
-	openStdin := cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's stdin")
594
-	if err := cmd.Parse(args); err != nil {
595
-		return nil
596
-	}
597
-	if cmd.NArg() < 1 {
598
-		cmd.Usage()
599
-		return nil
600
-	}
601
-
602
-	var cErr chan error
603
-	var tty bool
604
-	if *attach || *openStdin {
605
-		if cmd.NArg() > 1 {
606
-			return fmt.Errorf("You cannot start and attach multiple containers at once.")
607
-		}
608
-
609
-		body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false))
610
-		if err != nil {
611
-			return err
612
-		}
613
-
614
-		container := &api.Container{}
615
-		err = json.Unmarshal(body, container)
616
-		if err != nil {
617
-			return err
618
-		}
619
-
620
-		tty = container.Config.Tty
621
-
622
-		if !container.Config.Tty {
623
-			sigc := cli.forwardAllSignals(cmd.Arg(0))
624
-			defer signal.StopCatch(sigc)
625
-		}
626
-
627
-		var in io.ReadCloser
628
-
629
-		v := url.Values{}
630
-		v.Set("stream", "1")
631
-		if *openStdin && container.Config.OpenStdin {
632
-			v.Set("stdin", "1")
633
-			in = cli.in
634
-		}
635
-		v.Set("stdout", "1")
636
-		v.Set("stderr", "1")
637
-
638
-		cErr = utils.Go(func() error {
639
-			return cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), container.Config.Tty, in, cli.out, cli.err, nil)
640
-		})
641
-	}
642
-
643
-	var encounteredError error
644
-	for _, name := range cmd.Args() {
645
-		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/start", nil, false))
646
-		if err != nil {
647
-			if !*attach || !*openStdin {
648
-				fmt.Fprintf(cli.err, "%s\n", err)
649
-				encounteredError = fmt.Errorf("Error: failed to start one or more containers")
650
-			}
651
-		} else {
652
-			if !*attach || !*openStdin {
653
-				fmt.Fprintf(cli.out, "%s\n", name)
654
-			}
655
-		}
656
-	}
657
-	if encounteredError != nil {
658
-		if *openStdin || *attach {
659
-			cli.in.Close()
660
-			<-cErr
661
-		}
662
-		return encounteredError
663
-	}
664
-
665
-	if *openStdin || *attach {
666
-		if tty && cli.isTerminal {
667
-			if err := cli.monitorTtySize(cmd.Arg(0)); err != nil {
668
-				utils.Errorf("Error monitoring TTY size: %s\n", err)
669
-			}
670
-		}
671
-		return <-cErr
672
-	}
673
-	return nil
674
-}
675
-
676
-func (cli *DockerCli) CmdInspect(args ...string) error {
677
-	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container/image")
678
-	tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
679
-	if err := cmd.Parse(args); err != nil {
680
-		return nil
681
-	}
682
-	if cmd.NArg() < 1 {
683
-		cmd.Usage()
684
-		return nil
685
-	}
686
-
687
-	var tmpl *template.Template
688
-	if *tmplStr != "" {
689
-		var err error
690
-		if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil {
691
-			fmt.Fprintf(cli.err, "Template parsing error: %v\n", err)
692
-			return &utils.StatusError{StatusCode: 64,
693
-				Status: "Template parsing error: " + err.Error()}
694
-		}
695
-	}
696
-
697
-	indented := new(bytes.Buffer)
698
-	indented.WriteByte('[')
699
-	status := 0
700
-
701
-	for _, name := range cmd.Args() {
702
-		obj, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, false))
703
-		if err != nil {
704
-			obj, _, err = readBody(cli.call("GET", "/images/"+name+"/json", nil, false))
705
-			if err != nil {
706
-				if strings.Contains(err.Error(), "No such") {
707
-					fmt.Fprintf(cli.err, "Error: No such image or container: %s\n", name)
708
-				} else {
709
-					fmt.Fprintf(cli.err, "%s", err)
710
-				}
711
-				status = 1
712
-				continue
713
-			}
714
-		}
715
-
716
-		if tmpl == nil {
717
-			if err = json.Indent(indented, obj, "", "    "); err != nil {
718
-				fmt.Fprintf(cli.err, "%s\n", err)
719
-				status = 1
720
-				continue
721
-			}
722
-		} else {
723
-			// Has template, will render
724
-			var value interface{}
725
-			if err := json.Unmarshal(obj, &value); err != nil {
726
-				fmt.Fprintf(cli.err, "%s\n", err)
727
-				status = 1
728
-				continue
729
-			}
730
-			if err := tmpl.Execute(cli.out, value); err != nil {
731
-				return err
732
-			}
733
-			cli.out.Write([]byte{'\n'})
734
-		}
735
-		indented.WriteString(",")
736
-	}
737
-
738
-	if indented.Len() > 1 {
739
-		// Remove trailing ','
740
-		indented.Truncate(indented.Len() - 1)
741
-	}
742
-	indented.WriteByte(']')
743
-
744
-	if tmpl == nil {
745
-		if _, err := io.Copy(cli.out, indented); err != nil {
746
-			return err
747
-		}
748
-	}
749
-
750
-	if status != 0 {
751
-		return &utils.StatusError{StatusCode: status}
752
-	}
753
-	return nil
754
-}
755
-
756
-func (cli *DockerCli) CmdTop(args ...string) error {
757
-	cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Lookup the running processes of a container")
758
-	if err := cmd.Parse(args); err != nil {
759
-		return nil
760
-	}
761
-	if cmd.NArg() == 0 {
762
-		cmd.Usage()
763
-		return nil
764
-	}
765
-	val := url.Values{}
766
-	if cmd.NArg() > 1 {
767
-		val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
768
-	}
769
-
770
-	stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil, false)
771
-	if err != nil {
772
-		return err
773
-	}
774
-	var procs engine.Env
775
-	if err := procs.Decode(stream); err != nil {
776
-		return err
777
-	}
778
-	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
779
-	fmt.Fprintln(w, strings.Join(procs.GetList("Titles"), "\t"))
780
-	processes := [][]string{}
781
-	if err := procs.GetJson("Processes", &processes); err != nil {
782
-		return err
783
-	}
784
-	for _, proc := range processes {
785
-		fmt.Fprintln(w, strings.Join(proc, "\t"))
786
-	}
787
-	w.Flush()
788
-	return nil
789
-}
790
-
791
-func (cli *DockerCli) CmdPort(args ...string) error {
792
-	cmd := cli.Subcmd("port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT")
793
-	if err := cmd.Parse(args); err != nil {
794
-		return nil
795
-	}
796
-	if cmd.NArg() != 2 {
797
-		cmd.Usage()
798
-		return nil
799
-	}
800
-
801
-	var (
802
-		port      = cmd.Arg(1)
803
-		proto     = "tcp"
804
-		parts     = strings.SplitN(port, "/", 2)
805
-		container api.Container
806
-	)
807
-
808
-	if len(parts) == 2 && len(parts[1]) != 0 {
809
-		port = parts[0]
810
-		proto = parts[1]
811
-	}
812
-	body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false))
813
-	if err != nil {
814
-		return err
815
-	}
816
-
817
-	err = json.Unmarshal(body, &container)
818
-	if err != nil {
819
-		return err
820
-	}
821
-
822
-	if frontends, exists := container.NetworkSettings.Ports[nat.Port(port+"/"+proto)]; exists && frontends != nil {
823
-		for _, frontend := range frontends {
824
-			fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort)
825
-		}
826
-	} else {
827
-		return fmt.Errorf("Error: No public port '%s' published for %s", cmd.Arg(1), cmd.Arg(0))
828
-	}
829
-	return nil
830
-}
831
-
832
-// 'docker rmi IMAGE' removes all images with the name IMAGE
833
-func (cli *DockerCli) CmdRmi(args ...string) error {
834
-	var (
835
-		cmd     = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images")
836
-		force   = cmd.Bool([]string{"f", "-force"}, false, "Force")
837
-		noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
838
-	)
839
-	if err := cmd.Parse(args); err != nil {
840
-		return nil
841
-	}
842
-	if cmd.NArg() < 1 {
843
-		cmd.Usage()
844
-		return nil
845
-	}
846
-
847
-	v := url.Values{}
848
-	if *force {
849
-		v.Set("force", "1")
850
-	}
851
-	if *noprune {
852
-		v.Set("noprune", "1")
853
-	}
854
-
855
-	var encounteredError error
856
-	for _, name := range cmd.Args() {
857
-		body, _, err := readBody(cli.call("DELETE", "/images/"+name+"?"+v.Encode(), nil, false))
858
-		if err != nil {
859
-			fmt.Fprintf(cli.err, "%s\n", err)
860
-			encounteredError = fmt.Errorf("Error: failed to remove one or more images")
861
-		} else {
862
-			outs := engine.NewTable("Created", 0)
863
-			if _, err := outs.ReadListFrom(body); err != nil {
864
-				fmt.Fprintf(cli.err, "%s\n", err)
865
-				encounteredError = fmt.Errorf("Error: failed to remove one or more images")
866
-				continue
867
-			}
868
-			for _, out := range outs.Data {
869
-				if out.Get("Deleted") != "" {
870
-					fmt.Fprintf(cli.out, "Deleted: %s\n", out.Get("Deleted"))
871
-				} else {
872
-					fmt.Fprintf(cli.out, "Untagged: %s\n", out.Get("Untagged"))
873
-				}
874
-			}
875
-		}
876
-	}
877
-	return encounteredError
878
-}
879
-
880
-func (cli *DockerCli) CmdHistory(args ...string) error {
881
-	cmd := cli.Subcmd("history", "[OPTIONS] IMAGE", "Show the history of an image")
882
-	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
883
-	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
884
-
885
-	if err := cmd.Parse(args); err != nil {
886
-		return nil
887
-	}
888
-	if cmd.NArg() != 1 {
889
-		cmd.Usage()
890
-		return nil
891
-	}
892
-
893
-	body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, false))
894
-	if err != nil {
895
-		return err
896
-	}
897
-
898
-	outs := engine.NewTable("Created", 0)
899
-	if _, err := outs.ReadListFrom(body); err != nil {
900
-		return err
901
-	}
902
-
903
-	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
904
-	if !*quiet {
905
-		fmt.Fprintln(w, "IMAGE\tCREATED\tCREATED BY\tSIZE")
906
-	}
907
-
908
-	for _, out := range outs.Data {
909
-		outID := out.Get("Id")
910
-		if !*quiet {
911
-			if *noTrunc {
912
-				fmt.Fprintf(w, "%s\t", outID)
913
-			} else {
914
-				fmt.Fprintf(w, "%s\t", utils.TruncateID(outID))
915
-			}
916
-
917
-			fmt.Fprintf(w, "%s ago\t", utils.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))))
918
-
919
-			if *noTrunc {
920
-				fmt.Fprintf(w, "%s\t", out.Get("CreatedBy"))
921
-			} else {
922
-				fmt.Fprintf(w, "%s\t", utils.Trunc(out.Get("CreatedBy"), 45))
923
-			}
924
-			fmt.Fprintf(w, "%s\n", utils.HumanSize(out.GetInt64("Size")))
925
-		} else {
926
-			if *noTrunc {
927
-				fmt.Fprintln(w, outID)
928
-			} else {
929
-				fmt.Fprintln(w, utils.TruncateID(outID))
930
-			}
931
-		}
932
-	}
933
-	w.Flush()
934
-	return nil
935
-}
936
-
937
-func (cli *DockerCli) CmdRm(args ...string) error {
938
-	cmd := cli.Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove one or more containers")
939
-	v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated to the container")
940
-	link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
941
-	force := cmd.Bool([]string{"f", "-force"}, false, "Force removal of running container")
942
-
943
-	if err := cmd.Parse(args); err != nil {
944
-		return nil
945
-	}
946
-	if cmd.NArg() < 1 {
947
-		cmd.Usage()
948
-		return nil
949
-	}
950
-	val := url.Values{}
951
-	if *v {
952
-		val.Set("v", "1")
953
-	}
954
-	if *link {
955
-		val.Set("link", "1")
956
-	}
957
-	if *force {
958
-		val.Set("force", "1")
959
-	}
960
-
961
-	var encounteredError error
962
-	for _, name := range cmd.Args() {
963
-		_, _, err := readBody(cli.call("DELETE", "/containers/"+name+"?"+val.Encode(), nil, false))
964
-		if err != nil {
965
-			fmt.Fprintf(cli.err, "%s\n", err)
966
-			encounteredError = fmt.Errorf("Error: failed to remove one or more containers")
967
-		} else {
968
-			fmt.Fprintf(cli.out, "%s\n", name)
969
-		}
970
-	}
971
-	return encounteredError
972
-}
973
-
974
-// 'docker kill NAME' kills a running container
975
-func (cli *DockerCli) CmdKill(args ...string) error {
976
-	cmd := cli.Subcmd("kill", "[OPTIONS] CONTAINER [CONTAINER...]", "Kill a running container (send SIGKILL, or specified signal)")
977
-	signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
978
-
979
-	if err := cmd.Parse(args); err != nil {
980
-		return nil
981
-	}
982
-	if cmd.NArg() < 1 {
983
-		cmd.Usage()
984
-		return nil
985
-	}
986
-
987
-	var encounteredError error
988
-	for _, name := range cmd.Args() {
989
-		if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", name, *signal), nil, false)); err != nil {
990
-			fmt.Fprintf(cli.err, "%s\n", err)
991
-			encounteredError = fmt.Errorf("Error: failed to kill one or more containers")
992
-		} else {
993
-			fmt.Fprintf(cli.out, "%s\n", name)
994
-		}
995
-	}
996
-	return encounteredError
997
-}
998
-
999
-func (cli *DockerCli) CmdImport(args ...string) error {
1000
-	cmd := cli.Subcmd("import", "URL|- [REPOSITORY[:TAG]]", "Create an empty filesystem image and import the contents of the tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it.")
1001
-
1002
-	if err := cmd.Parse(args); err != nil {
1003
-		return nil
1004
-	}
1005
-	if cmd.NArg() < 1 {
1006
-		cmd.Usage()
1007
-		return nil
1008
-	}
1009
-
1010
-	var src, repository, tag string
1011
-
1012
-	if cmd.NArg() == 3 {
1013
-		fmt.Fprintf(cli.err, "[DEPRECATED] The format 'URL|- [REPOSITORY [TAG]]' as been deprecated. Please use URL|- [REPOSITORY[:TAG]]\n")
1014
-		src, repository, tag = cmd.Arg(0), cmd.Arg(1), cmd.Arg(2)
1015
-	} else {
1016
-		src = cmd.Arg(0)
1017
-		repository, tag = utils.ParseRepositoryTag(cmd.Arg(1))
1018
-	}
1019
-	v := url.Values{}
1020
-
1021
-	if repository != "" {
1022
-		//Check if the given image name can be resolved
1023
-		if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
1024
-			return err
1025
-		}
1026
-	}
1027
-
1028
-	v.Set("repo", repository)
1029
-	v.Set("tag", tag)
1030
-	v.Set("fromSrc", src)
1031
-
1032
-	var in io.Reader
1033
-
1034
-	if src == "-" {
1035
-		in = cli.in
1036
-	}
1037
-
1038
-	return cli.stream("POST", "/images/create?"+v.Encode(), in, cli.out, nil)
1039
-}
1040
-
1041
-func (cli *DockerCli) CmdPush(args ...string) error {
1042
-	cmd := cli.Subcmd("push", "NAME", "Push an image or a repository to the registry")
1043
-	if err := cmd.Parse(args); err != nil {
1044
-		return nil
1045
-	}
1046
-	name := cmd.Arg(0)
1047
-
1048
-	if name == "" {
1049
-		cmd.Usage()
1050
-		return nil
1051
-	}
1052
-
1053
-	cli.LoadConfigFile()
1054
-
1055
-	// Resolve the Repository name from fqn to hostname + name
1056
-	hostname, _, err := registry.ResolveRepositoryName(name)
1057
-	if err != nil {
1058
-		return err
1059
-	}
1060
-	// Resolve the Auth config relevant for this server
1061
-	authConfig := cli.configFile.ResolveAuthConfig(hostname)
1062
-	// If we're not using a custom registry, we know the restrictions
1063
-	// applied to repository names and can warn the user in advance.
1064
-	// Custom repositories can have different rules, and we must also
1065
-	// allow pushing by image ID.
1066
-	if len(strings.SplitN(name, "/", 2)) == 1 {
1067
-		username := cli.configFile.Configs[registry.IndexServerAddress()].Username
1068
-		if username == "" {
1069
-			username = "<user>"
1070
-		}
1071
-		return fmt.Errorf("You cannot push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", username, name)
1072
-	}
1073
-
1074
-	v := url.Values{}
1075
-	push := func(authConfig registry.AuthConfig) error {
1076
-		buf, err := json.Marshal(authConfig)
1077
-		if err != nil {
1078
-			return err
1079
-		}
1080
-		registryAuthHeader := []string{
1081
-			base64.URLEncoding.EncodeToString(buf),
1082
-		}
1083
-
1084
-		return cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), nil, cli.out, map[string][]string{
1085
-			"X-Registry-Auth": registryAuthHeader,
1086
-		})
1087
-	}
1088
-
1089
-	if err := push(authConfig); err != nil {
1090
-		if strings.Contains(err.Error(), "Status 401") {
1091
-			fmt.Fprintln(cli.out, "\nPlease login prior to push:")
1092
-			if err := cli.CmdLogin(hostname); err != nil {
1093
-				return err
1094
-			}
1095
-			authConfig := cli.configFile.ResolveAuthConfig(hostname)
1096
-			return push(authConfig)
1097
-		}
1098
-		return err
1099
-	}
1100
-	return nil
1101
-}
1102
-
1103
-func (cli *DockerCli) CmdPull(args ...string) error {
1104
-	cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry")
1105
-	tag := cmd.String([]string{"#t", "#-tag"}, "", "Download tagged image in repository")
1106
-	if err := cmd.Parse(args); err != nil {
1107
-		return nil
1108
-	}
1109
-
1110
-	if cmd.NArg() != 1 {
1111
-		cmd.Usage()
1112
-		return nil
1113
-	}
1114
-
1115
-	remote, parsedTag := utils.ParseRepositoryTag(cmd.Arg(0))
1116
-	if *tag == "" {
1117
-		*tag = parsedTag
1118
-	}
1119
-
1120
-	// Resolve the Repository name from fqn to hostname + name
1121
-	hostname, _, err := registry.ResolveRepositoryName(remote)
1122
-	if err != nil {
1123
-		return err
1124
-	}
1125
-
1126
-	cli.LoadConfigFile()
1127
-
1128
-	// Resolve the Auth config relevant for this server
1129
-	authConfig := cli.configFile.ResolveAuthConfig(hostname)
1130
-	v := url.Values{}
1131
-	v.Set("fromImage", remote)
1132
-	v.Set("tag", *tag)
1133
-
1134
-	pull := func(authConfig registry.AuthConfig) error {
1135
-		buf, err := json.Marshal(authConfig)
1136
-		if err != nil {
1137
-			return err
1138
-		}
1139
-		registryAuthHeader := []string{
1140
-			base64.URLEncoding.EncodeToString(buf),
1141
-		}
1142
-
1143
-		return cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.out, map[string][]string{
1144
-			"X-Registry-Auth": registryAuthHeader,
1145
-		})
1146
-	}
1147
-
1148
-	if err := pull(authConfig); err != nil {
1149
-		if strings.Contains(err.Error(), "Status 401") {
1150
-			fmt.Fprintln(cli.out, "\nPlease login prior to pull:")
1151
-			if err := cli.CmdLogin(hostname); err != nil {
1152
-				return err
1153
-			}
1154
-			authConfig := cli.configFile.ResolveAuthConfig(hostname)
1155
-			return pull(authConfig)
1156
-		}
1157
-		return err
1158
-	}
1159
-
1160
-	return nil
1161
-}
1162
-
1163
-func (cli *DockerCli) CmdImages(args ...string) error {
1164
-	cmd := cli.Subcmd("images", "[OPTIONS] [NAME]", "List images")
1165
-	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
1166
-	all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (by default filter out the intermediate images used to build)")
1167
-	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
1168
-	flViz := cmd.Bool([]string{"v", "#viz", "-viz"}, false, "Output graph in graphviz format")
1169
-	flTree := cmd.Bool([]string{"t", "#tree", "-tree"}, false, "Output graph in tree format")
1170
-
1171
-	if err := cmd.Parse(args); err != nil {
1172
-		return nil
1173
-	}
1174
-	if cmd.NArg() > 1 {
1175
-		cmd.Usage()
1176
-		return nil
1177
-	}
1178
-
1179
-	filter := cmd.Arg(0)
1180
-
1181
-	if *flViz || *flTree {
1182
-		body, _, err := readBody(cli.call("GET", "/images/json?all=1", nil, false))
1183
-		if err != nil {
1184
-			return err
1185
-		}
1186
-
1187
-		outs := engine.NewTable("Created", 0)
1188
-		if _, err := outs.ReadListFrom(body); err != nil {
1189
-			return err
1190
-		}
1191
-
1192
-		var (
1193
-			printNode  func(cli *DockerCli, noTrunc bool, image *engine.Env, prefix string)
1194
-			startImage *engine.Env
1195
-
1196
-			roots    = engine.NewTable("Created", outs.Len())
1197
-			byParent = make(map[string]*engine.Table)
1198
-		)
1199
-
1200
-		for _, image := range outs.Data {
1201
-			if image.Get("ParentId") == "" {
1202
-				roots.Add(image)
1203
-			} else {
1204
-				if children, exists := byParent[image.Get("ParentId")]; exists {
1205
-					children.Add(image)
1206
-				} else {
1207
-					byParent[image.Get("ParentId")] = engine.NewTable("Created", 1)
1208
-					byParent[image.Get("ParentId")].Add(image)
1209
-				}
1210
-			}
1211
-
1212
-			if filter != "" {
1213
-				if filter == image.Get("Id") || filter == utils.TruncateID(image.Get("Id")) {
1214
-					startImage = image
1215
-				}
1216
-
1217
-				for _, repotag := range image.GetList("RepoTags") {
1218
-					if repotag == filter {
1219
-						startImage = image
1220
-					}
1221
-				}
1222
-			}
1223
-		}
1224
-
1225
-		if *flViz {
1226
-			fmt.Fprintf(cli.out, "digraph docker {\n")
1227
-			printNode = (*DockerCli).printVizNode
1228
-		} else {
1229
-			printNode = (*DockerCli).printTreeNode
1230
-		}
1231
-
1232
-		if startImage != nil {
1233
-			root := engine.NewTable("Created", 1)
1234
-			root.Add(startImage)
1235
-			cli.WalkTree(*noTrunc, root, byParent, "", printNode)
1236
-		} else if filter == "" {
1237
-			cli.WalkTree(*noTrunc, roots, byParent, "", printNode)
1238
-		}
1239
-		if *flViz {
1240
-			fmt.Fprintf(cli.out, " base [style=invisible]\n}\n")
1241
-		}
1242
-	} else {
1243
-		v := url.Values{}
1244
-		if cmd.NArg() == 1 {
1245
-			v.Set("filter", filter)
1246
-		}
1247
-		if *all {
1248
-			v.Set("all", "1")
1249
-		}
1250
-
1251
-		body, _, err := readBody(cli.call("GET", "/images/json?"+v.Encode(), nil, false))
1252
-
1253
-		if err != nil {
1254
-			return err
1255
-		}
1256
-
1257
-		outs := engine.NewTable("Created", 0)
1258
-		if _, err := outs.ReadListFrom(body); err != nil {
1259
-			return err
1260
-		}
1261
-
1262
-		w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
1263
-		if !*quiet {
1264
-			fmt.Fprintln(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tVIRTUAL SIZE")
1265
-		}
1266
-
1267
-		for _, out := range outs.Data {
1268
-			for _, repotag := range out.GetList("RepoTags") {
1269
-
1270
-				repo, tag := utils.ParseRepositoryTag(repotag)
1271
-				outID := out.Get("Id")
1272
-				if !*noTrunc {
1273
-					outID = utils.TruncateID(outID)
1274
-				}
1275
-
1276
-				if !*quiet {
1277
-					fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, outID, utils.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), utils.HumanSize(out.GetInt64("VirtualSize")))
1278
-				} else {
1279
-					fmt.Fprintln(w, outID)
1280
-				}
1281
-			}
1282
-		}
1283
-
1284
-		if !*quiet {
1285
-			w.Flush()
1286
-		}
1287
-	}
1288
-	return nil
1289
-}
1290
-
1291
-func (cli *DockerCli) WalkTree(noTrunc bool, images *engine.Table, byParent map[string]*engine.Table, prefix string, printNode func(cli *DockerCli, noTrunc bool, image *engine.Env, prefix string)) {
1292
-	length := images.Len()
1293
-	if length > 1 {
1294
-		for index, image := range images.Data {
1295
-			if index+1 == length {
1296
-				printNode(cli, noTrunc, image, prefix+"└─")
1297
-				if subimages, exists := byParent[image.Get("Id")]; exists {
1298
-					cli.WalkTree(noTrunc, subimages, byParent, prefix+"  ", printNode)
1299
-				}
1300
-			} else {
1301
-				printNode(cli, noTrunc, image, prefix+"\u251C─")
1302
-				if subimages, exists := byParent[image.Get("Id")]; exists {
1303
-					cli.WalkTree(noTrunc, subimages, byParent, prefix+"\u2502 ", printNode)
1304
-				}
1305
-			}
1306
-		}
1307
-	} else {
1308
-		for _, image := range images.Data {
1309
-			printNode(cli, noTrunc, image, prefix+"└─")
1310
-			if subimages, exists := byParent[image.Get("Id")]; exists {
1311
-				cli.WalkTree(noTrunc, subimages, byParent, prefix+"  ", printNode)
1312
-			}
1313
-		}
1314
-	}
1315
-}
1316
-
1317
-func (cli *DockerCli) printVizNode(noTrunc bool, image *engine.Env, prefix string) {
1318
-	var (
1319
-		imageID  string
1320
-		parentID string
1321
-	)
1322
-	if noTrunc {
1323
-		imageID = image.Get("Id")
1324
-		parentID = image.Get("ParentId")
1325
-	} else {
1326
-		imageID = utils.TruncateID(image.Get("Id"))
1327
-		parentID = utils.TruncateID(image.Get("ParentId"))
1328
-	}
1329
-	if parentID == "" {
1330
-		fmt.Fprintf(cli.out, " base -> \"%s\" [style=invis]\n", imageID)
1331
-	} else {
1332
-		fmt.Fprintf(cli.out, " \"%s\" -> \"%s\"\n", parentID, imageID)
1333
-	}
1334
-	if image.GetList("RepoTags")[0] != "<none>:<none>" {
1335
-		fmt.Fprintf(cli.out, " \"%s\" [label=\"%s\\n%s\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n",
1336
-			imageID, imageID, strings.Join(image.GetList("RepoTags"), "\\n"))
1337
-	}
1338
-}
1339
-
1340
-func (cli *DockerCli) printTreeNode(noTrunc bool, image *engine.Env, prefix string) {
1341
-	var imageID string
1342
-	if noTrunc {
1343
-		imageID = image.Get("Id")
1344
-	} else {
1345
-		imageID = utils.TruncateID(image.Get("Id"))
1346
-	}
1347
-
1348
-	fmt.Fprintf(cli.out, "%s%s Virtual Size: %s", prefix, imageID, utils.HumanSize(image.GetInt64("VirtualSize")))
1349
-	if image.GetList("RepoTags")[0] != "<none>:<none>" {
1350
-		fmt.Fprintf(cli.out, " Tags: %s\n", strings.Join(image.GetList("RepoTags"), ", "))
1351
-	} else {
1352
-		fmt.Fprint(cli.out, "\n")
1353
-	}
1354
-}
1355
-
1356
-func (cli *DockerCli) CmdPs(args ...string) error {
1357
-	cmd := cli.Subcmd("ps", "[OPTIONS]", "List containers")
1358
-	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
1359
-	size := cmd.Bool([]string{"s", "-size"}, false, "Display sizes")
1360
-	all := cmd.Bool([]string{"a", "-all"}, false, "Show all containers. Only running containers are shown by default.")
1361
-	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
1362
-	nLatest := cmd.Bool([]string{"l", "-latest"}, false, "Show only the latest created container, include non-running ones.")
1363
-	since := cmd.String([]string{"#sinceId", "#-since-id", "-since"}, "", "Show only containers created since Id or Name, include non-running ones.")
1364
-	before := cmd.String([]string{"#beforeId", "#-before-id", "-before"}, "", "Show only container created before Id or Name, include non-running ones.")
1365
-	last := cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.")
1366
-
1367
-	if err := cmd.Parse(args); err != nil {
1368
-		return nil
1369
-	}
1370
-	v := url.Values{}
1371
-	if *last == -1 && *nLatest {
1372
-		*last = 1
1373
-	}
1374
-	if *all {
1375
-		v.Set("all", "1")
1376
-	}
1377
-	if *last != -1 {
1378
-		v.Set("limit", strconv.Itoa(*last))
1379
-	}
1380
-	if *since != "" {
1381
-		v.Set("since", *since)
1382
-	}
1383
-	if *before != "" {
1384
-		v.Set("before", *before)
1385
-	}
1386
-	if *size {
1387
-		v.Set("size", "1")
1388
-	}
1389
-
1390
-	body, _, err := readBody(cli.call("GET", "/containers/json?"+v.Encode(), nil, false))
1391
-	if err != nil {
1392
-		return err
1393
-	}
1394
-
1395
-	outs := engine.NewTable("Created", 0)
1396
-	if _, err := outs.ReadListFrom(body); err != nil {
1397
-		return err
1398
-	}
1399
-	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
1400
-	if !*quiet {
1401
-		fmt.Fprint(w, "CONTAINER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES")
1402
-		if *size {
1403
-			fmt.Fprintln(w, "\tSIZE")
1404
-		} else {
1405
-			fmt.Fprint(w, "\n")
1406
-		}
1407
-	}
1408
-
1409
-	for _, out := range outs.Data {
1410
-		var (
1411
-			outID    = out.Get("Id")
1412
-			outNames = out.GetList("Names")
1413
-		)
1414
-
1415
-		if !*noTrunc {
1416
-			outID = utils.TruncateID(outID)
1417
-		}
1418
-
1419
-		// Remove the leading / from the names
1420
-		for i := 0; i < len(outNames); i++ {
1421
-			outNames[i] = outNames[i][1:]
1422
-		}
1423
-
1424
-		if !*quiet {
1425
-			var (
1426
-				outCommand = out.Get("Command")
1427
-				ports      = engine.NewTable("", 0)
1428
-			)
1429
-			if !*noTrunc {
1430
-				outCommand = utils.Trunc(outCommand, 20)
1431
-			}
1432
-			ports.ReadListFrom([]byte(out.Get("Ports")))
1433
-			fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", outID, out.Get("Image"), outCommand, utils.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), out.Get("Status"), api.DisplayablePorts(ports), strings.Join(outNames, ","))
1434
-			if *size {
1435
-				if out.GetInt("SizeRootFs") > 0 {
1436
-					fmt.Fprintf(w, "%s (virtual %s)\n", utils.HumanSize(out.GetInt64("SizeRw")), utils.HumanSize(out.GetInt64("SizeRootFs")))
1437
-				} else {
1438
-					fmt.Fprintf(w, "%s\n", utils.HumanSize(out.GetInt64("SizeRw")))
1439
-				}
1440
-			} else {
1441
-				fmt.Fprint(w, "\n")
1442
-			}
1443
-		} else {
1444
-			fmt.Fprintln(w, outID)
1445
-		}
1446
-	}
1447
-
1448
-	if !*quiet {
1449
-		w.Flush()
1450
-	}
1451
-	return nil
1452
-}
1453
-
1454
-func (cli *DockerCli) CmdCommit(args ...string) error {
1455
-	cmd := cli.Subcmd("commit", "[OPTIONS] CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes")
1456
-	flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
1457
-	flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\"")
1458
-	flConfig := cmd.String([]string{"#run", "-run"}, "", "Config automatically applied when the image is run. "+`(ex: --run='{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')`)
1459
-	if err := cmd.Parse(args); err != nil {
1460
-		return nil
1461
-	}
1462
-
1463
-	var name, repository, tag string
1464
-
1465
-	if cmd.NArg() == 3 {
1466
-		fmt.Fprintf(cli.err, "[DEPRECATED] The format 'CONTAINER [REPOSITORY [TAG]]' as been deprecated. Please use CONTAINER [REPOSITORY[:TAG]]\n")
1467
-		name, repository, tag = cmd.Arg(0), cmd.Arg(1), cmd.Arg(2)
1468
-	} else {
1469
-		name = cmd.Arg(0)
1470
-		repository, tag = utils.ParseRepositoryTag(cmd.Arg(1))
1471
-	}
1472
-
1473
-	if name == "" {
1474
-		cmd.Usage()
1475
-		return nil
1476
-	}
1477
-
1478
-	//Check if the given image name can be resolved
1479
-	if repository != "" {
1480
-		if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
1481
-			return err
1482
-		}
1483
-	}
1484
-
1485
-	v := url.Values{}
1486
-	v.Set("container", name)
1487
-	v.Set("repo", repository)
1488
-	v.Set("tag", tag)
1489
-	v.Set("comment", *flComment)
1490
-	v.Set("author", *flAuthor)
1491
-	var (
1492
-		config *runconfig.Config
1493
-		env    engine.Env
1494
-	)
1495
-	if *flConfig != "" {
1496
-		config = &runconfig.Config{}
1497
-		if err := json.Unmarshal([]byte(*flConfig), config); err != nil {
1498
-			return err
1499
-		}
1500
-	}
1501
-	stream, _, err := cli.call("POST", "/commit?"+v.Encode(), config, false)
1502
-	if err != nil {
1503
-		return err
1504
-	}
1505
-	if err := env.Decode(stream); err != nil {
1506
-		return err
1507
-	}
1508
-
1509
-	fmt.Fprintf(cli.out, "%s\n", env.Get("Id"))
1510
-	return nil
1511
-}
1512
-
1513
-func (cli *DockerCli) CmdEvents(args ...string) error {
1514
-	cmd := cli.Subcmd("events", "[OPTIONS]", "Get real time events from the server")
1515
-	since := cmd.String([]string{"#since", "-since"}, "", "Show previously created events and then stream.")
1516
-	if err := cmd.Parse(args); err != nil {
1517
-		return nil
1518
-	}
1519
-
1520
-	if cmd.NArg() != 0 {
1521
-		cmd.Usage()
1522
-		return nil
1523
-	}
1524
-
1525
-	v := url.Values{}
1526
-	if *since != "" {
1527
-		loc := time.FixedZone(time.Now().Zone())
1528
-		format := "2006-01-02 15:04:05 -0700 MST"
1529
-		if len(*since) < len(format) {
1530
-			format = format[:len(*since)]
1531
-		}
1532
-
1533
-		if t, err := time.ParseInLocation(format, *since, loc); err == nil {
1534
-			v.Set("since", strconv.FormatInt(t.Unix(), 10))
1535
-		} else {
1536
-			v.Set("since", *since)
1537
-		}
1538
-	}
1539
-
1540
-	if err := cli.stream("GET", "/events?"+v.Encode(), nil, cli.out, nil); err != nil {
1541
-		return err
1542
-	}
1543
-	return nil
1544
-}
1545
-
1546
-func (cli *DockerCli) CmdExport(args ...string) error {
1547
-	cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT")
1548
-	if err := cmd.Parse(args); err != nil {
1549
-		return nil
1550
-	}
1551
-
1552
-	if cmd.NArg() != 1 {
1553
-		cmd.Usage()
1554
-		return nil
1555
-	}
1556
-
1557
-	if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, cli.out, nil); err != nil {
1558
-		return err
1559
-	}
1560
-	return nil
1561
-}
1562
-
1563
-func (cli *DockerCli) CmdDiff(args ...string) error {
1564
-	cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem")
1565
-	if err := cmd.Parse(args); err != nil {
1566
-		return nil
1567
-	}
1568
-	if cmd.NArg() != 1 {
1569
-		cmd.Usage()
1570
-		return nil
1571
-	}
1572
-
1573
-	body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, false))
1574
-
1575
-	if err != nil {
1576
-		return err
1577
-	}
1578
-
1579
-	outs := engine.NewTable("", 0)
1580
-	if _, err := outs.ReadListFrom(body); err != nil {
1581
-		return err
1582
-	}
1583
-	for _, change := range outs.Data {
1584
-		var kind string
1585
-		switch change.GetInt("Kind") {
1586
-		case archive.ChangeModify:
1587
-			kind = "C"
1588
-		case archive.ChangeAdd:
1589
-			kind = "A"
1590
-		case archive.ChangeDelete:
1591
-			kind = "D"
1592
-		}
1593
-		fmt.Fprintf(cli.out, "%s %s\n", kind, change.Get("Path"))
1594
-	}
1595
-	return nil
1596
-}
1597
-
1598
-func (cli *DockerCli) CmdLogs(args ...string) error {
1599
-	cmd := cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container")
1600
-	follow := cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
1601
-	if err := cmd.Parse(args); err != nil {
1602
-		return nil
1603
-	}
1604
-	if cmd.NArg() != 1 {
1605
-		cmd.Usage()
1606
-		return nil
1607
-	}
1608
-	name := cmd.Arg(0)
1609
-	body, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, false))
1610
-	if err != nil {
1611
-		return err
1612
-	}
1613
-
1614
-	container := &api.Container{}
1615
-	err = json.Unmarshal(body, container)
1616
-	if err != nil {
1617
-		return err
1618
-	}
1619
-
1620
-	v := url.Values{}
1621
-	v.Set("logs", "1")
1622
-	v.Set("stdout", "1")
1623
-	v.Set("stderr", "1")
1624
-	if *follow && container.State.Running {
1625
-		v.Set("stream", "1")
1626
-	}
1627
-
1628
-	if err := cli.hijack("POST", "/containers/"+name+"/attach?"+v.Encode(), container.Config.Tty, nil, cli.out, cli.err, nil); err != nil {
1629
-		return err
1630
-	}
1631
-	return nil
1632
-}
1633
-
1634
-func (cli *DockerCli) CmdAttach(args ...string) error {
1635
-	cmd := cli.Subcmd("attach", "[OPTIONS] CONTAINER", "Attach to a running container")
1636
-	noStdin := cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach stdin")
1637
-	proxy := cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxify all received signal to the process (even in non-tty mode)")
1638
-	if err := cmd.Parse(args); err != nil {
1639
-		return nil
1640
-	}
1641
-	if cmd.NArg() != 1 {
1642
-		cmd.Usage()
1643
-		return nil
1644
-	}
1645
-	name := cmd.Arg(0)
1646
-	body, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, false))
1647
-	if err != nil {
1648
-		return err
1649
-	}
1650
-
1651
-	container := &api.Container{}
1652
-	err = json.Unmarshal(body, container)
1653
-	if err != nil {
1654
-		return err
1655
-	}
1656
-
1657
-	if !container.State.Running {
1658
-		return fmt.Errorf("You cannot attach to a stopped container, start it first")
1659
-	}
1660
-
1661
-	if container.Config.Tty && cli.isTerminal {
1662
-		if err := cli.monitorTtySize(cmd.Arg(0)); err != nil {
1663
-			utils.Debugf("Error monitoring TTY size: %s", err)
1664
-		}
1665
-	}
1666
-
1667
-	var in io.ReadCloser
1668
-
1669
-	v := url.Values{}
1670
-	v.Set("stream", "1")
1671
-	if !*noStdin && container.Config.OpenStdin {
1672
-		v.Set("stdin", "1")
1673
-		in = cli.in
1674
-	}
1675
-	v.Set("stdout", "1")
1676
-	v.Set("stderr", "1")
1677
-
1678
-	if *proxy && !container.Config.Tty {
1679
-		sigc := cli.forwardAllSignals(cmd.Arg(0))
1680
-		defer signal.StopCatch(sigc)
1681
-	}
1682
-
1683
-	if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), container.Config.Tty, in, cli.out, cli.err, nil); err != nil {
1684
-		return err
1685
-	}
1686
-
1687
-	_, status, err := getExitCode(cli, cmd.Arg(0))
1688
-	if err != nil {
1689
-		return err
1690
-	}
1691
-	if status != 0 {
1692
-		return &utils.StatusError{StatusCode: status}
1693
-	}
1694
-
1695
-	return nil
1696
-}
1697
-
1698
-func (cli *DockerCli) CmdSearch(args ...string) error {
1699
-	cmd := cli.Subcmd("search", "TERM", "Search the docker index for images")
1700
-	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
1701
-	trusted := cmd.Bool([]string{"t", "#trusted", "-trusted"}, false, "Only show trusted builds")
1702
-	stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least xxx stars")
1703
-	if err := cmd.Parse(args); err != nil {
1704
-		return nil
1705
-	}
1706
-	if cmd.NArg() != 1 {
1707
-		cmd.Usage()
1708
-		return nil
1709
-	}
1710
-
1711
-	v := url.Values{}
1712
-	v.Set("term", cmd.Arg(0))
1713
-
1714
-	body, _, err := readBody(cli.call("GET", "/images/search?"+v.Encode(), nil, true))
1715
-
1716
-	if err != nil {
1717
-		return err
1718
-	}
1719
-	outs := engine.NewTable("star_count", 0)
1720
-	if _, err := outs.ReadListFrom(body); err != nil {
1721
-		return err
1722
-	}
1723
-	w := tabwriter.NewWriter(cli.out, 10, 1, 3, ' ', 0)
1724
-	fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tTRUSTED\n")
1725
-	for _, out := range outs.Data {
1726
-		if (*trusted && !out.GetBool("is_trusted")) || (*stars > out.GetInt("star_count")) {
1727
-			continue
1728
-		}
1729
-		desc := strings.Replace(out.Get("description"), "\n", " ", -1)
1730
-		desc = strings.Replace(desc, "\r", " ", -1)
1731
-		if !*noTrunc && len(desc) > 45 {
1732
-			desc = utils.Trunc(desc, 42) + "..."
1733
-		}
1734
-		fmt.Fprintf(w, "%s\t%s\t%d\t", out.Get("name"), desc, out.GetInt("star_count"))
1735
-		if out.GetBool("is_official") {
1736
-			fmt.Fprint(w, "[OK]")
1737
-
1738
-		}
1739
-		fmt.Fprint(w, "\t")
1740
-		if out.GetBool("is_trusted") {
1741
-			fmt.Fprint(w, "[OK]")
1742
-		}
1743
-		fmt.Fprint(w, "\n")
1744
-	}
1745
-	w.Flush()
1746
-	return nil
1747
-}
1748
-
1749
-// Ports type - Used to parse multiple -p flags
1750
-type ports []int
1751
-
1752
-func (cli *DockerCli) CmdTag(args ...string) error {
1753
-	cmd := cli.Subcmd("tag", "[OPTIONS] IMAGE [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository")
1754
-	force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
1755
-	if err := cmd.Parse(args); err != nil {
1756
-		return nil
1757
-	}
1758
-	if cmd.NArg() != 2 && cmd.NArg() != 3 {
1759
-		cmd.Usage()
1760
-		return nil
1761
-	}
1762
-
1763
-	var repository, tag string
1764
-
1765
-	if cmd.NArg() == 3 {
1766
-		fmt.Fprintf(cli.err, "[DEPRECATED] The format 'IMAGE [REPOSITORY [TAG]]' as been deprecated. Please use IMAGE [REGISTRYHOST/][USERNAME/]NAME[:TAG]]\n")
1767
-		repository, tag = cmd.Arg(1), cmd.Arg(2)
1768
-	} else {
1769
-		repository, tag = utils.ParseRepositoryTag(cmd.Arg(1))
1770
-	}
1771
-
1772
-	v := url.Values{}
1773
-
1774
-	//Check if the given image name can be resolved
1775
-	if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
1776
-		return err
1777
-	}
1778
-	v.Set("repo", repository)
1779
-	v.Set("tag", tag)
1780
-
1781
-	if *force {
1782
-		v.Set("force", "1")
1783
-	}
1784
-
1785
-	if _, _, err := readBody(cli.call("POST", "/images/"+cmd.Arg(0)+"/tag?"+v.Encode(), nil, false)); err != nil {
1786
-		return err
1787
-	}
1788
-	return nil
1789
-}
1790
-
1791
-func (cli *DockerCli) CmdRun(args ...string) error {
1792
-	// FIXME: just use runconfig.Parse already
1793
-	config, hostConfig, cmd, err := runconfig.ParseSubcommand(cli.Subcmd("run", "[OPTIONS] IMAGE [COMMAND] [ARG...]", "Run a command in a new container"), args, nil)
1794
-	if err != nil {
1795
-		return err
1796
-	}
1797
-	if config.Image == "" {
1798
-		cmd.Usage()
1799
-		return nil
1800
-	}
1801
-
1802
-	// Retrieve relevant client-side config
1803
-	var (
1804
-		flName        = cmd.Lookup("name")
1805
-		flRm          = cmd.Lookup("rm")
1806
-		flSigProxy    = cmd.Lookup("sig-proxy")
1807
-		autoRemove, _ = strconv.ParseBool(flRm.Value.String())
1808
-		sigProxy, _   = strconv.ParseBool(flSigProxy.Value.String())
1809
-	)
1810
-
1811
-	// Disable sigProxy in case on TTY
1812
-	if config.Tty {
1813
-		sigProxy = false
1814
-	}
1815
-
1816
-	var containerIDFile io.WriteCloser
1817
-	if len(hostConfig.ContainerIDFile) > 0 {
1818
-		if _, err := os.Stat(hostConfig.ContainerIDFile); err == nil {
1819
-			return fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", hostConfig.ContainerIDFile)
1820
-		}
1821
-		if containerIDFile, err = os.Create(hostConfig.ContainerIDFile); err != nil {
1822
-			return fmt.Errorf("Failed to create the container ID file: %s", err)
1823
-		}
1824
-		defer func() {
1825
-			containerIDFile.Close()
1826
-			var (
1827
-				cidFileInfo os.FileInfo
1828
-				err         error
1829
-			)
1830
-			if cidFileInfo, err = os.Stat(hostConfig.ContainerIDFile); err != nil {
1831
-				return
1832
-			}
1833
-			if cidFileInfo.Size() == 0 {
1834
-				if err := os.Remove(hostConfig.ContainerIDFile); err != nil {
1835
-					fmt.Printf("failed to remove CID file '%s': %s \n", hostConfig.ContainerIDFile, err)
1836
-				}
1837
-			}
1838
-		}()
1839
-	}
1840
-
1841
-	containerValues := url.Values{}
1842
-	if name := flName.Value.String(); name != "" {
1843
-		containerValues.Set("name", name)
1844
-	}
1845
-
1846
-	//create the container
1847
-	stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), config, false)
1848
-	//if image not found try to pull it
1849
-	if statusCode == 404 {
1850
-		fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", config.Image)
1851
-
1852
-		v := url.Values{}
1853
-		repos, tag := utils.ParseRepositoryTag(config.Image)
1854
-		v.Set("fromImage", repos)
1855
-		v.Set("tag", tag)
1856
-
1857
-		// Resolve the Repository name from fqn to hostname + name
1858
-		hostname, _, err := registry.ResolveRepositoryName(repos)
1859
-		if err != nil {
1860
-			return err
1861
-		}
1862
-
1863
-		// Load the auth config file, to be able to pull the image
1864
-		cli.LoadConfigFile()
1865
-
1866
-		// Resolve the Auth config relevant for this server
1867
-		authConfig := cli.configFile.ResolveAuthConfig(hostname)
1868
-		buf, err := json.Marshal(authConfig)
1869
-		if err != nil {
1870
-			return err
1871
-		}
1872
-
1873
-		registryAuthHeader := []string{
1874
-			base64.URLEncoding.EncodeToString(buf),
1875
-		}
1876
-		if err = cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.err, map[string][]string{"X-Registry-Auth": registryAuthHeader}); err != nil {
1877
-			return err
1878
-		}
1879
-		if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), config, false); err != nil {
1880
-			return err
1881
-		}
1882
-	} else if err != nil {
1883
-		return err
1884
-	}
1885
-
1886
-	var runResult engine.Env
1887
-	if err := runResult.Decode(stream); err != nil {
1888
-		return err
1889
-	}
1890
-
1891
-	for _, warning := range runResult.GetList("Warnings") {
1892
-		fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
1893
-	}
1894
-
1895
-	if len(hostConfig.ContainerIDFile) > 0 {
1896
-		if _, err = containerIDFile.Write([]byte(runResult.Get("Id"))); err != nil {
1897
-			return fmt.Errorf("Failed to write the container ID to the file: %s", err)
1898
-		}
1899
-	}
1900
-
1901
-	if sigProxy {
1902
-		sigc := cli.forwardAllSignals(runResult.Get("Id"))
1903
-		defer signal.StopCatch(sigc)
1904
-	}
1905
-
1906
-	var (
1907
-		waitDisplayId chan struct{}
1908
-		errCh         chan error
1909
-	)
1910
-
1911
-	if !config.AttachStdout && !config.AttachStderr {
1912
-		// Make this asynchrone in order to let the client write to stdin before having to read the ID
1913
-		waitDisplayId = make(chan struct{})
1914
-		go func() {
1915
-			defer close(waitDisplayId)
1916
-			fmt.Fprintf(cli.out, "%s\n", runResult.Get("Id"))
1917
-		}()
1918
-	}
1919
-
1920
-	// We need to instanciate the chan because the select needs it. It can
1921
-	// be closed but can't be uninitialized.
1922
-	hijacked := make(chan io.Closer)
1923
-
1924
-	// Block the return until the chan gets closed
1925
-	defer func() {
1926
-		utils.Debugf("End of CmdRun(), Waiting for hijack to finish.")
1927
-		if _, ok := <-hijacked; ok {
1928
-			utils.Errorf("Hijack did not finish (chan still open)")
1929
-		}
1930
-	}()
1931
-
1932
-	if config.AttachStdin || config.AttachStdout || config.AttachStderr {
1933
-		var (
1934
-			out, stderr io.Writer
1935
-			in          io.ReadCloser
1936
-			v           = url.Values{}
1937
-		)
1938
-		v.Set("stream", "1")
1939
-
1940
-		if config.AttachStdin {
1941
-			v.Set("stdin", "1")
1942
-			in = cli.in
1943
-		}
1944
-		if config.AttachStdout {
1945
-			v.Set("stdout", "1")
1946
-			out = cli.out
1947
-		}
1948
-		if config.AttachStderr {
1949
-			v.Set("stderr", "1")
1950
-			if config.Tty {
1951
-				stderr = cli.out
1952
-			} else {
1953
-				stderr = cli.err
1954
-			}
1955
-		}
1956
-
1957
-		errCh = utils.Go(func() error {
1958
-			return cli.hijack("POST", "/containers/"+runResult.Get("Id")+"/attach?"+v.Encode(), config.Tty, in, out, stderr, hijacked)
1959
-		})
1960
-	} else {
1961
-		close(hijacked)
1962
-	}
1963
-
1964
-	// Acknowledge the hijack before starting
1965
-	select {
1966
-	case closer := <-hijacked:
1967
-		// Make sure that hijack gets closed when returning. (result
1968
-		// in closing hijack chan and freeing server's goroutines.
1969
-		if closer != nil {
1970
-			defer closer.Close()
1971
-		}
1972
-	case err := <-errCh:
1973
-		if err != nil {
1974
-			utils.Debugf("Error hijack: %s", err)
1975
-			return err
1976
-		}
1977
-	}
1978
-
1979
-	//start the container
1980
-	if _, _, err = readBody(cli.call("POST", "/containers/"+runResult.Get("Id")+"/start", hostConfig, false)); err != nil {
1981
-		return err
1982
-	}
1983
-
1984
-	if (config.AttachStdin || config.AttachStdout || config.AttachStderr) && config.Tty && cli.isTerminal {
1985
-		if err := cli.monitorTtySize(runResult.Get("Id")); err != nil {
1986
-			utils.Errorf("Error monitoring TTY size: %s\n", err)
1987
-		}
1988
-	}
1989
-
1990
-	if errCh != nil {
1991
-		if err := <-errCh; err != nil {
1992
-			utils.Debugf("Error hijack: %s", err)
1993
-			return err
1994
-		}
1995
-	}
1996
-
1997
-	// Detached mode: wait for the id to be displayed and return.
1998
-	if !config.AttachStdout && !config.AttachStderr {
1999
-		// Detached mode
2000
-		<-waitDisplayId
2001
-		return nil
2002
-	}
2003
-
2004
-	var status int
2005
-
2006
-	// Attached mode
2007
-	if autoRemove {
2008
-		// Autoremove: wait for the container to finish, retrieve
2009
-		// the exit code and remove the container
2010
-		if _, _, err := readBody(cli.call("POST", "/containers/"+runResult.Get("Id")+"/wait", nil, false)); err != nil {
2011
-			return err
2012
-		}
2013
-		if _, status, err = getExitCode(cli, runResult.Get("Id")); err != nil {
2014
-			return err
2015
-		}
2016
-		if _, _, err := readBody(cli.call("DELETE", "/containers/"+runResult.Get("Id")+"?v=1", nil, false)); err != nil {
2017
-			return err
2018
-		}
2019
-	} else {
2020
-		if !config.Tty {
2021
-			// In non-tty mode, we can't dettach, so we know we need to wait.
2022
-			if status, err = waitForExit(cli, runResult.Get("Id")); err != nil {
2023
-				return err
2024
-			}
2025
-		} else {
2026
-			// In TTY mode, there is a race. If the process dies too slowly, the state can be update after the getExitCode call
2027
-			// and result in a wrong exit code.
2028
-			// No Autoremove: Simply retrieve the exit code
2029
-			if _, status, err = getExitCode(cli, runResult.Get("Id")); err != nil {
2030
-				return err
2031
-			}
2032
-		}
2033
-	}
2034
-	if status != 0 {
2035
-		return &utils.StatusError{StatusCode: status}
2036
-	}
2037
-	return nil
2038
-}
2039
-
2040
-func (cli *DockerCli) CmdCp(args ...string) error {
2041
-	cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH")
2042
-	if err := cmd.Parse(args); err != nil {
2043
-		return nil
2044
-	}
2045
-
2046
-	if cmd.NArg() != 2 {
2047
-		cmd.Usage()
2048
-		return nil
2049
-	}
2050
-
2051
-	var copyData engine.Env
2052
-	info := strings.Split(cmd.Arg(0), ":")
2053
-
2054
-	if len(info) != 2 {
2055
-		return fmt.Errorf("Error: Path not specified")
2056
-	}
2057
-
2058
-	copyData.Set("Resource", info[1])
2059
-	copyData.Set("HostPath", cmd.Arg(1))
2060
-
2061
-	stream, statusCode, err := cli.call("POST", "/containers/"+info[0]+"/copy", copyData, false)
2062
-	if stream != nil {
2063
-		defer stream.Close()
2064
-	}
2065
-	if statusCode == 404 {
2066
-		return fmt.Errorf("No such container: %v", info[0])
2067
-	}
2068
-	if err != nil {
2069
-		return err
2070
-	}
2071
-
2072
-	if statusCode == 200 {
2073
-		if err := archive.Untar(stream, copyData.Get("HostPath"), nil); err != nil {
2074
-			return err
2075
-		}
2076
-	}
2077
-	return nil
2078
-}
2079
-
2080
-func (cli *DockerCli) CmdSave(args ...string) error {
2081
-	cmd := cli.Subcmd("save", "IMAGE", "Save an image to a tar archive (streamed to stdout by default)")
2082
-	outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
2083
-
2084
-	if err := cmd.Parse(args); err != nil {
2085
-		return err
2086
-	}
2087
-
2088
-	if cmd.NArg() != 1 {
2089
-		cmd.Usage()
2090
-		return nil
2091
-	}
2092
-
2093
-	var (
2094
-		output io.Writer = cli.out
2095
-		err    error
2096
-	)
2097
-	if *outfile != "" {
2098
-		output, err = os.Create(*outfile)
2099
-		if err != nil {
2100
-			return err
2101
-		}
2102
-	}
2103
-	image := cmd.Arg(0)
2104
-	if err := cli.stream("GET", "/images/"+image+"/get", nil, output, nil); err != nil {
2105
-		return err
2106
-	}
2107
-	return nil
2108
-}
2109
-
2110
-func (cli *DockerCli) CmdLoad(args ...string) error {
2111
-	cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN")
2112
-	infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
2113
-
2114
-	if err := cmd.Parse(args); err != nil {
2115
-		return err
2116
-	}
2117
-
2118
-	if cmd.NArg() != 0 {
2119
-		cmd.Usage()
2120
-		return nil
2121
-	}
2122
-
2123
-	var (
2124
-		input io.Reader = cli.in
2125
-		err   error
2126
-	)
2127
-	if *infile != "" {
2128
-		input, err = os.Open(*infile)
2129
-		if err != nil {
2130
-			return err
2131
-		}
2132
-	}
2133
-	if err := cli.stream("POST", "/images/load", input, cli.out, nil); err != nil {
2134
-		return err
2135
-	}
2136
-	return nil
2137
-}
2138
-
2139
-func (cli *DockerCli) dial() (net.Conn, error) {
2140
-	if cli.tlsConfig != nil && cli.proto != "unix" {
2141
-		return tls.Dial(cli.proto, cli.addr, cli.tlsConfig)
2142
-	}
2143
-	return net.Dial(cli.proto, cli.addr)
2144
-}
2145
-
2146
-func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo bool) (io.ReadCloser, int, error) {
2147
-	params := bytes.NewBuffer(nil)
2148
-	if data != nil {
2149
-		if env, ok := data.(engine.Env); ok {
2150
-			if err := env.Encode(params); err != nil {
2151
-				return nil, -1, err
2152
-			}
2153
-		} else {
2154
-			buf, err := json.Marshal(data)
2155
-			if err != nil {
2156
-				return nil, -1, err
2157
-			}
2158
-			if _, err := params.Write(buf); err != nil {
2159
-				return nil, -1, err
2160
-			}
2161
-		}
2162
-	}
2163
-	// fixme: refactor client to support redirect
2164
-	re := regexp.MustCompile("/+")
2165
-	path = re.ReplaceAllString(path, "/")
2166
-
2167
-	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), params)
2168
-	if err != nil {
2169
-		return nil, -1, err
2170
-	}
2171
-	if passAuthInfo {
2172
-		cli.LoadConfigFile()
2173
-		// Resolve the Auth config relevant for this server
2174
-		authConfig := cli.configFile.ResolveAuthConfig(registry.IndexServerAddress())
2175
-		getHeaders := func(authConfig registry.AuthConfig) (map[string][]string, error) {
2176
-			buf, err := json.Marshal(authConfig)
2177
-			if err != nil {
2178
-				return nil, err
2179
-			}
2180
-			registryAuthHeader := []string{
2181
-				base64.URLEncoding.EncodeToString(buf),
2182
-			}
2183
-			return map[string][]string{"X-Registry-Auth": registryAuthHeader}, nil
2184
-		}
2185
-		if headers, err := getHeaders(authConfig); err == nil && headers != nil {
2186
-			for k, v := range headers {
2187
-				req.Header[k] = v
2188
-			}
2189
-		}
2190
-	}
2191
-	req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION)
2192
-	req.Host = cli.addr
2193
-	if data != nil {
2194
-		req.Header.Set("Content-Type", "application/json")
2195
-	} else if method == "POST" {
2196
-		req.Header.Set("Content-Type", "plain/text")
2197
-	}
2198
-	dial, err := cli.dial()
2199
-	if err != nil {
2200
-		if strings.Contains(err.Error(), "connection refused") {
2201
-			return nil, -1, ErrConnectionRefused
2202
-		}
2203
-		return nil, -1, err
2204
-	}
2205
-	clientconn := httputil.NewClientConn(dial, nil)
2206
-	resp, err := clientconn.Do(req)
2207
-	if err != nil {
2208
-		clientconn.Close()
2209
-		if strings.Contains(err.Error(), "connection refused") {
2210
-			return nil, -1, ErrConnectionRefused
2211
-		}
2212
-		return nil, -1, err
2213
-	}
2214
-
2215
-	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
2216
-		body, err := ioutil.ReadAll(resp.Body)
2217
-		if err != nil {
2218
-			return nil, -1, err
2219
-		}
2220
-		if len(body) == 0 {
2221
-			return nil, resp.StatusCode, fmt.Errorf("Error: request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(resp.StatusCode), req.URL)
2222
-		}
2223
-		return nil, resp.StatusCode, fmt.Errorf("Error: %s", bytes.TrimSpace(body))
2224
-	}
2225
-
2226
-	wrapper := utils.NewReadCloserWrapper(resp.Body, func() error {
2227
-		if resp != nil && resp.Body != nil {
2228
-			resp.Body.Close()
2229
-		}
2230
-		return clientconn.Close()
2231
-	})
2232
-	return wrapper, resp.StatusCode, nil
2233
-}
2234
-
2235
-func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, headers map[string][]string) error {
2236
-	if (method == "POST" || method == "PUT") && in == nil {
2237
-		in = bytes.NewReader([]byte{})
2238
-	}
2239
-
2240
-	// fixme: refactor client to support redirect
2241
-	re := regexp.MustCompile("/+")
2242
-	path = re.ReplaceAllString(path, "/")
2243
-
2244
-	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), in)
2245
-	if err != nil {
2246
-		return err
2247
-	}
2248
-	req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION)
2249
-	req.Host = cli.addr
2250
-	if method == "POST" {
2251
-		req.Header.Set("Content-Type", "plain/text")
2252
-	}
2253
-
2254
-	if headers != nil {
2255
-		for k, v := range headers {
2256
-			req.Header[k] = v
2257
-		}
2258
-	}
2259
-
2260
-	dial, err := cli.dial()
2261
-	if err != nil {
2262
-		if strings.Contains(err.Error(), "connection refused") {
2263
-			return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
2264
-		}
2265
-		return err
2266
-	}
2267
-	clientconn := httputil.NewClientConn(dial, nil)
2268
-	resp, err := clientconn.Do(req)
2269
-	defer clientconn.Close()
2270
-	if err != nil {
2271
-		if strings.Contains(err.Error(), "connection refused") {
2272
-			return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
2273
-		}
2274
-		return err
2275
-	}
2276
-	defer resp.Body.Close()
2277
-
2278
-	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
2279
-		body, err := ioutil.ReadAll(resp.Body)
2280
-		if err != nil {
2281
-			return err
2282
-		}
2283
-		if len(body) == 0 {
2284
-			return fmt.Errorf("Error :%s", http.StatusText(resp.StatusCode))
2285
-		}
2286
-		return fmt.Errorf("Error: %s", bytes.TrimSpace(body))
2287
-	}
2288
-
2289
-	if api.MatchesContentType(resp.Header.Get("Content-Type"), "application/json") {
2290
-		return utils.DisplayJSONMessagesStream(resp.Body, out, cli.terminalFd, cli.isTerminal)
2291
-	}
2292
-	if _, err := io.Copy(out, resp.Body); err != nil {
2293
-		return err
2294
-	}
2295
-	return nil
2296
-}
2297
-
2298
-func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, stdout, stderr io.Writer, started chan io.Closer) error {
2299
-	defer func() {
2300
-		if started != nil {
2301
-			close(started)
2302
-		}
2303
-	}()
2304
-	// fixme: refactor client to support redirect
2305
-	re := regexp.MustCompile("/+")
2306
-	path = re.ReplaceAllString(path, "/")
2307
-
2308
-	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), nil)
2309
-	if err != nil {
2310
-		return err
2311
-	}
2312
-	req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION)
2313
-	req.Header.Set("Content-Type", "plain/text")
2314
-	req.Host = cli.addr
2315
-
2316
-	dial, err := cli.dial()
2317
-	if err != nil {
2318
-		if strings.Contains(err.Error(), "connection refused") {
2319
-			return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
2320
-		}
2321
-		return err
2322
-	}
2323
-	clientconn := httputil.NewClientConn(dial, nil)
2324
-	defer clientconn.Close()
2325
-
2326
-	// Server hijacks the connection, error 'connection closed' expected
2327
-	clientconn.Do(req)
2328
-
2329
-	rwc, br := clientconn.Hijack()
2330
-	defer rwc.Close()
2331
-
2332
-	if started != nil {
2333
-		started <- rwc
2334
-	}
2335
-
2336
-	var receiveStdout chan error
2337
-
2338
-	var oldState *term.State
2339
-
2340
-	if in != nil && setRawTerminal && cli.isTerminal && os.Getenv("NORAW") == "" {
2341
-		oldState, err = term.SetRawTerminal(cli.terminalFd)
2342
-		if err != nil {
2343
-			return err
2344
-		}
2345
-		defer term.RestoreTerminal(cli.terminalFd, oldState)
2346
-	}
2347
-
2348
-	if stdout != nil || stderr != nil {
2349
-		receiveStdout = utils.Go(func() (err error) {
2350
-			defer func() {
2351
-				if in != nil {
2352
-					if setRawTerminal && cli.isTerminal {
2353
-						term.RestoreTerminal(cli.terminalFd, oldState)
2354
-					}
2355
-					// For some reason this Close call blocks on darwin..
2356
-					// As the client exists right after, simply discard the close
2357
-					// until we find a better solution.
2358
-					if goruntime.GOOS != "darwin" {
2359
-						in.Close()
2360
-					}
2361
-				}
2362
-			}()
2363
-
2364
-			// When TTY is ON, use regular copy
2365
-			if setRawTerminal {
2366
-				_, err = io.Copy(stdout, br)
2367
-			} else {
2368
-				_, err = utils.StdCopy(stdout, stderr, br)
2369
-			}
2370
-			utils.Debugf("[hijack] End of stdout")
2371
-			return err
2372
-		})
2373
-	}
2374
-
2375
-	sendStdin := utils.Go(func() error {
2376
-		if in != nil {
2377
-			io.Copy(rwc, in)
2378
-			utils.Debugf("[hijack] End of stdin")
2379
-		}
2380
-		if tcpc, ok := rwc.(*net.TCPConn); ok {
2381
-			if err := tcpc.CloseWrite(); err != nil {
2382
-				utils.Debugf("Couldn't send EOF: %s\n", err)
2383
-			}
2384
-		} else if unixc, ok := rwc.(*net.UnixConn); ok {
2385
-			if err := unixc.CloseWrite(); err != nil {
2386
-				utils.Debugf("Couldn't send EOF: %s\n", err)
2387
-			}
2388
-		}
2389
-		// Discard errors due to pipe interruption
2390
-		return nil
2391
-	})
2392
-
2393
-	if stdout != nil || stderr != nil {
2394
-		if err := <-receiveStdout; err != nil {
2395
-			utils.Debugf("Error receiveStdout: %s", err)
2396
-			return err
2397
-		}
2398
-	}
2399
-
2400
-	if !cli.isTerminal {
2401
-		if err := <-sendStdin; err != nil {
2402
-			utils.Debugf("Error sendStdin: %s", err)
2403
-			return err
2404
-		}
2405
-	}
2406
-	return nil
2407
-
2408
-}
2409
-
2410
-func (cli *DockerCli) getTtySize() (int, int) {
2411
-	if !cli.isTerminal {
2412
-		return 0, 0
2413
-	}
2414
-	ws, err := term.GetWinsize(cli.terminalFd)
2415
-	if err != nil {
2416
-		utils.Debugf("Error getting size: %s", err)
2417
-		if ws == nil {
2418
-			return 0, 0
2419
-		}
2420
-	}
2421
-	return int(ws.Height), int(ws.Width)
2422
-}
2423
-
2424
-func (cli *DockerCli) resizeTty(id string) {
2425
-	height, width := cli.getTtySize()
2426
-	if height == 0 && width == 0 {
2427
-		return
2428
-	}
2429
-	v := url.Values{}
2430
-	v.Set("h", strconv.Itoa(height))
2431
-	v.Set("w", strconv.Itoa(width))
2432
-	if _, _, err := readBody(cli.call("POST", "/containers/"+id+"/resize?"+v.Encode(), nil, false)); err != nil {
2433
-		utils.Debugf("Error resize: %s", err)
2434
-	}
2435
-}
2436
-
2437
-func (cli *DockerCli) monitorTtySize(id string) error {
2438
-	cli.resizeTty(id)
2439
-
2440
-	sigchan := make(chan os.Signal, 1)
2441
-	gosignal.Notify(sigchan, syscall.SIGWINCH)
2442
-	go func() {
2443
-		for _ = range sigchan {
2444
-			cli.resizeTty(id)
2445
-		}
2446
-	}()
2447
-	return nil
2448
-}
2449
-
2450
-func (cli *DockerCli) Subcmd(name, signature, description string) *flag.FlagSet {
2451
-	flags := flag.NewFlagSet(name, flag.ContinueOnError)
2452
-	flags.Usage = func() {
2453
-		fmt.Fprintf(cli.err, "\nUsage: docker %s %s\n\n%s\n\n", name, signature, description)
2454
-		flags.PrintDefaults()
2455
-		os.Exit(2)
2456
-	}
2457
-	return flags
2458
-}
2459
-
2460
-func (cli *DockerCli) LoadConfigFile() (err error) {
2461
-	cli.configFile, err = registry.LoadConfig(os.Getenv("HOME"))
2462
-	if err != nil {
2463
-		fmt.Fprintf(cli.err, "WARNING: %s\n", err)
2464
-	}
2465
-	return err
2466
-}
2467
-
2468
-func waitForExit(cli *DockerCli, containerId string) (int, error) {
2469
-	stream, _, err := cli.call("POST", "/containers/"+containerId+"/wait", nil, false)
2470
-	if err != nil {
2471
-		return -1, err
2472
-	}
2473
-
2474
-	var out engine.Env
2475
-	if err := out.Decode(stream); err != nil {
2476
-		return -1, err
2477
-	}
2478
-	return out.GetInt("StatusCode"), nil
2479
-}
2480
-
2481
-// getExitCode perform an inspect on the container. It returns
2482
-// the running state and the exit code.
2483
-func getExitCode(cli *DockerCli, containerId string) (bool, int, error) {
2484
-	body, _, err := readBody(cli.call("GET", "/containers/"+containerId+"/json", nil, false))
2485
-	if err != nil {
2486
-		// If we can't connect, then the daemon probably died.
2487
-		if err != ErrConnectionRefused {
2488
-			return false, -1, err
2489
-		}
2490
-		return false, -1, nil
2491
-	}
2492
-	c := &api.Container{}
2493
-	if err := json.Unmarshal(body, c); err != nil {
2494
-		return false, -1, err
2495
-	}
2496
-	return c.State.Running, c.State.ExitCode, nil
2497
-}
2498
-
2499
-func readBody(stream io.ReadCloser, statusCode int, err error) ([]byte, int, error) {
2500
-	if stream != nil {
2501
-		defer stream.Close()
2502
-	}
2503
-	if err != nil {
2504
-		return nil, statusCode, err
2505
-	}
2506
-	body, err := ioutil.ReadAll(stream)
2507
-	if err != nil {
2508
-		return nil, -1, err
2509
-	}
2510
-	return body, statusCode, nil
2511
-}
2512
-
2513
-func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string, tlsConfig *tls.Config) *DockerCli {
2514
-	var (
2515
-		isTerminal = false
2516
-		terminalFd uintptr
2517
-	)
2518
-
2519
-	if in != nil {
2520
-		if file, ok := in.(*os.File); ok {
2521
-			terminalFd = file.Fd()
2522
-			isTerminal = term.IsTerminal(terminalFd)
2523
-		}
2524
-	}
2525
-
2526
-	if err == nil {
2527
-		err = out
2528
-	}
2529
-	return &DockerCli{
2530
-		proto:      proto,
2531
-		addr:       addr,
2532
-		in:         in,
2533
-		out:        out,
2534
-		err:        err,
2535
-		isTerminal: isTerminal,
2536
-		terminalFd: terminalFd,
2537
-		tlsConfig:  tlsConfig,
2538
-	}
2539
-}
2540
-
2541
-type DockerCli struct {
2542
-	proto      string
2543
-	addr       string
2544
-	configFile *registry.ConfigFile
2545
-	in         io.ReadCloser
2546
-	out        io.Writer
2547
-	err        io.Writer
2548
-	isTerminal bool
2549
-	terminalFd uintptr
2550
-	tlsConfig  *tls.Config
2551
-}
2552 1
new file mode 100644
... ...
@@ -0,0 +1,2098 @@
0
+package client
1
+
2
+import (
3
+	"bufio"
4
+	"bytes"
5
+	"encoding/base64"
6
+	"encoding/json"
7
+	"fmt"
8
+	"io"
9
+	"io/ioutil"
10
+	"net/http"
11
+	"net/url"
12
+	"os"
13
+	"os/exec"
14
+	"path"
15
+	goruntime "runtime"
16
+	"strconv"
17
+	"strings"
18
+	"syscall"
19
+	"text/tabwriter"
20
+	"text/template"
21
+	"time"
22
+
23
+	"github.com/dotcloud/docker/api"
24
+	"github.com/dotcloud/docker/archive"
25
+	"github.com/dotcloud/docker/dockerversion"
26
+	"github.com/dotcloud/docker/engine"
27
+	"github.com/dotcloud/docker/nat"
28
+	"github.com/dotcloud/docker/pkg/signal"
29
+	"github.com/dotcloud/docker/pkg/term"
30
+	"github.com/dotcloud/docker/registry"
31
+	"github.com/dotcloud/docker/runconfig"
32
+	"github.com/dotcloud/docker/utils"
33
+)
34
+
35
+func (cli *DockerCli) CmdHelp(args ...string) error {
36
+	if len(args) > 0 {
37
+		method, exists := cli.getMethod(args[0])
38
+		if !exists {
39
+			fmt.Fprintf(cli.err, "Error: Command not found: %s\n", args[0])
40
+		} else {
41
+			method("--help")
42
+			return nil
43
+		}
44
+	}
45
+	help := fmt.Sprintf("Usage: docker [OPTIONS] COMMAND [arg...]\n -H=[unix://%s]: tcp://host:port to bind/connect to or unix://path/to/socket to use\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n", api.DEFAULTUNIXSOCKET)
46
+	for _, command := range [][]string{
47
+		{"attach", "Attach to a running container"},
48
+		{"build", "Build a container from a Dockerfile"},
49
+		{"commit", "Create a new image from a container's changes"},
50
+		{"cp", "Copy files/folders from the containers filesystem to the host path"},
51
+		{"diff", "Inspect changes on a container's filesystem"},
52
+		{"events", "Get real time events from the server"},
53
+		{"export", "Stream the contents of a container as a tar archive"},
54
+		{"history", "Show the history of an image"},
55
+		{"images", "List images"},
56
+		{"import", "Create a new filesystem image from the contents of a tarball"},
57
+		{"info", "Display system-wide information"},
58
+		{"insert", "Insert a file in an image"},
59
+		{"inspect", "Return low-level information on a container"},
60
+		{"kill", "Kill a running container"},
61
+		{"load", "Load an image from a tar archive"},
62
+		{"login", "Register or Login to the docker registry server"},
63
+		{"logs", "Fetch the logs of a container"},
64
+		{"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"},
65
+		{"ps", "List containers"},
66
+		{"pull", "Pull an image or a repository from the docker registry server"},
67
+		{"push", "Push an image or a repository to the docker registry server"},
68
+		{"restart", "Restart a running container"},
69
+		{"rm", "Remove one or more containers"},
70
+		{"rmi", "Remove one or more images"},
71
+		{"run", "Run a command in a new container"},
72
+		{"save", "Save an image to a tar archive"},
73
+		{"search", "Search for an image in the docker index"},
74
+		{"start", "Start a stopped container"},
75
+		{"stop", "Stop a running container"},
76
+		{"tag", "Tag an image into a repository"},
77
+		{"top", "Lookup the running processes of a container"},
78
+		{"version", "Show the docker version information"},
79
+		{"wait", "Block until a container stops, then print its exit code"},
80
+	} {
81
+		help += fmt.Sprintf("    %-10.10s%s\n", command[0], command[1])
82
+	}
83
+	fmt.Fprintf(cli.err, "%s\n", help)
84
+	return nil
85
+}
86
+
87
+func (cli *DockerCli) CmdInsert(args ...string) error {
88
+	cmd := cli.Subcmd("insert", "IMAGE URL PATH", "Insert a file from URL in the IMAGE at PATH")
89
+	if err := cmd.Parse(args); err != nil {
90
+		return nil
91
+	}
92
+	if cmd.NArg() != 3 {
93
+		cmd.Usage()
94
+		return nil
95
+	}
96
+
97
+	v := url.Values{}
98
+	v.Set("url", cmd.Arg(1))
99
+	v.Set("path", cmd.Arg(2))
100
+
101
+	return cli.stream("POST", "/images/"+cmd.Arg(0)+"/insert?"+v.Encode(), nil, cli.out, nil)
102
+}
103
+
104
+func (cli *DockerCli) CmdBuild(args ...string) error {
105
+	cmd := cli.Subcmd("build", "[OPTIONS] PATH | URL | -", "Build a new container image from the source code at PATH")
106
+	tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) to be applied to the resulting image in case of success")
107
+	suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers")
108
+	noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image")
109
+	rm := cmd.Bool([]string{"#rm", "-rm"}, true, "Remove intermediate containers after a successful build")
110
+	if err := cmd.Parse(args); err != nil {
111
+		return nil
112
+	}
113
+	if cmd.NArg() != 1 {
114
+		cmd.Usage()
115
+		return nil
116
+	}
117
+
118
+	var (
119
+		context  archive.Archive
120
+		isRemote bool
121
+		err      error
122
+	)
123
+
124
+	_, err = exec.LookPath("git")
125
+	hasGit := err == nil
126
+	if cmd.Arg(0) == "-" {
127
+		// As a special case, 'docker build -' will build from an empty context with the
128
+		// contents of stdin as a Dockerfile
129
+		dockerfile, err := ioutil.ReadAll(cli.in)
130
+		if err != nil {
131
+			return err
132
+		}
133
+		context, err = archive.Generate("Dockerfile", string(dockerfile))
134
+	} else if utils.IsURL(cmd.Arg(0)) && (!utils.IsGIT(cmd.Arg(0)) || !hasGit) {
135
+		isRemote = true
136
+	} else {
137
+		root := cmd.Arg(0)
138
+		if utils.IsGIT(root) {
139
+			remoteURL := cmd.Arg(0)
140
+			if !strings.HasPrefix(remoteURL, "git://") && !strings.HasPrefix(remoteURL, "git@") && !utils.IsURL(remoteURL) {
141
+				remoteURL = "https://" + remoteURL
142
+			}
143
+
144
+			root, err = ioutil.TempDir("", "docker-build-git")
145
+			if err != nil {
146
+				return err
147
+			}
148
+			defer os.RemoveAll(root)
149
+
150
+			if output, err := exec.Command("git", "clone", "--recursive", remoteURL, root).CombinedOutput(); err != nil {
151
+				return fmt.Errorf("Error trying to use git: %s (%s)", err, output)
152
+			}
153
+		}
154
+		if _, err := os.Stat(root); err != nil {
155
+			return err
156
+		}
157
+		filename := path.Join(root, "Dockerfile")
158
+		if _, err = os.Stat(filename); os.IsNotExist(err) {
159
+			return fmt.Errorf("no Dockerfile found in %s", cmd.Arg(0))
160
+		}
161
+		context, err = archive.Tar(root, archive.Uncompressed)
162
+	}
163
+	var body io.Reader
164
+	// Setup an upload progress bar
165
+	// FIXME: ProgressReader shouldn't be this annoying to use
166
+	if context != nil {
167
+		sf := utils.NewStreamFormatter(false)
168
+		body = utils.ProgressReader(context, 0, cli.err, sf, true, "", "Uploading context")
169
+	}
170
+	// Upload the build context
171
+	v := &url.Values{}
172
+
173
+	//Check if the given image name can be resolved
174
+	if *tag != "" {
175
+		repository, _ := utils.ParseRepositoryTag(*tag)
176
+		if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
177
+			return err
178
+		}
179
+	}
180
+
181
+	v.Set("t", *tag)
182
+
183
+	if *suppressOutput {
184
+		v.Set("q", "1")
185
+	}
186
+	if isRemote {
187
+		v.Set("remote", cmd.Arg(0))
188
+	}
189
+	if *noCache {
190
+		v.Set("nocache", "1")
191
+	}
192
+	if *rm {
193
+		v.Set("rm", "1")
194
+	}
195
+
196
+	cli.LoadConfigFile()
197
+
198
+	headers := http.Header(make(map[string][]string))
199
+	buf, err := json.Marshal(cli.configFile)
200
+	if err != nil {
201
+		return err
202
+	}
203
+	headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
204
+
205
+	if context != nil {
206
+		headers.Set("Content-Type", "application/tar")
207
+	}
208
+	err = cli.stream("POST", fmt.Sprintf("/build?%s", v.Encode()), body, cli.out, headers)
209
+	if jerr, ok := err.(*utils.JSONError); ok {
210
+		// If no error code is set, default to 1
211
+		if jerr.Code == 0 {
212
+			jerr.Code = 1
213
+		}
214
+		return &utils.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
215
+	}
216
+	return err
217
+}
218
+
219
+// 'docker login': login / register a user to registry service.
220
+func (cli *DockerCli) CmdLogin(args ...string) error {
221
+	cmd := cli.Subcmd("login", "[OPTIONS] [SERVER]", "Register or Login to a docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.")
222
+
223
+	var username, password, email string
224
+
225
+	cmd.StringVar(&username, []string{"u", "-username"}, "", "Username")
226
+	cmd.StringVar(&password, []string{"p", "-password"}, "", "Password")
227
+	cmd.StringVar(&email, []string{"e", "-email"}, "", "Email")
228
+	err := cmd.Parse(args)
229
+	if err != nil {
230
+		return nil
231
+	}
232
+	serverAddress := registry.IndexServerAddress()
233
+	if len(cmd.Args()) > 0 {
234
+		serverAddress = cmd.Arg(0)
235
+	}
236
+
237
+	promptDefault := func(prompt string, configDefault string) {
238
+		if configDefault == "" {
239
+			fmt.Fprintf(cli.out, "%s: ", prompt)
240
+		} else {
241
+			fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
242
+		}
243
+	}
244
+
245
+	readInput := func(in io.Reader, out io.Writer) string {
246
+		reader := bufio.NewReader(in)
247
+		line, _, err := reader.ReadLine()
248
+		if err != nil {
249
+			fmt.Fprintln(out, err.Error())
250
+			os.Exit(1)
251
+		}
252
+		return string(line)
253
+	}
254
+
255
+	cli.LoadConfigFile()
256
+	authconfig, ok := cli.configFile.Configs[serverAddress]
257
+	if !ok {
258
+		authconfig = registry.AuthConfig{}
259
+	}
260
+
261
+	if username == "" {
262
+		promptDefault("Username", authconfig.Username)
263
+		username = readInput(cli.in, cli.out)
264
+		if username == "" {
265
+			username = authconfig.Username
266
+		}
267
+	}
268
+	if username != authconfig.Username {
269
+		if password == "" {
270
+			oldState, _ := term.SaveState(cli.terminalFd)
271
+			fmt.Fprintf(cli.out, "Password: ")
272
+			term.DisableEcho(cli.terminalFd, oldState)
273
+
274
+			password = readInput(cli.in, cli.out)
275
+			fmt.Fprint(cli.out, "\n")
276
+
277
+			term.RestoreTerminal(cli.terminalFd, oldState)
278
+			if password == "" {
279
+				return fmt.Errorf("Error : Password Required")
280
+			}
281
+		}
282
+
283
+		if email == "" {
284
+			promptDefault("Email", authconfig.Email)
285
+			email = readInput(cli.in, cli.out)
286
+			if email == "" {
287
+				email = authconfig.Email
288
+			}
289
+		}
290
+	} else {
291
+		password = authconfig.Password
292
+		email = authconfig.Email
293
+	}
294
+	authconfig.Username = username
295
+	authconfig.Password = password
296
+	authconfig.Email = email
297
+	authconfig.ServerAddress = serverAddress
298
+	cli.configFile.Configs[serverAddress] = authconfig
299
+
300
+	stream, statusCode, err := cli.call("POST", "/auth", cli.configFile.Configs[serverAddress], false)
301
+	if statusCode == 401 {
302
+		delete(cli.configFile.Configs, serverAddress)
303
+		registry.SaveConfig(cli.configFile)
304
+		return err
305
+	}
306
+	if err != nil {
307
+		return err
308
+	}
309
+	var out2 engine.Env
310
+	err = out2.Decode(stream)
311
+	if err != nil {
312
+		cli.configFile, _ = registry.LoadConfig(os.Getenv("HOME"))
313
+		return err
314
+	}
315
+	registry.SaveConfig(cli.configFile)
316
+	if out2.Get("Status") != "" {
317
+		fmt.Fprintf(cli.out, "%s\n", out2.Get("Status"))
318
+	}
319
+	return nil
320
+}
321
+
322
+// 'docker wait': block until a container stops
323
+func (cli *DockerCli) CmdWait(args ...string) error {
324
+	cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.")
325
+	if err := cmd.Parse(args); err != nil {
326
+		return nil
327
+	}
328
+	if cmd.NArg() < 1 {
329
+		cmd.Usage()
330
+		return nil
331
+	}
332
+	var encounteredError error
333
+	for _, name := range cmd.Args() {
334
+		status, err := waitForExit(cli, name)
335
+		if err != nil {
336
+			fmt.Fprintf(cli.err, "%s\n", err)
337
+			encounteredError = fmt.Errorf("Error: failed to wait one or more containers")
338
+		} else {
339
+			fmt.Fprintf(cli.out, "%d\n", status)
340
+		}
341
+	}
342
+	return encounteredError
343
+}
344
+
345
+// 'docker version': show version information
346
+func (cli *DockerCli) CmdVersion(args ...string) error {
347
+	cmd := cli.Subcmd("version", "", "Show the docker version information.")
348
+	if err := cmd.Parse(args); err != nil {
349
+		return nil
350
+	}
351
+
352
+	if cmd.NArg() > 0 {
353
+		cmd.Usage()
354
+		return nil
355
+	}
356
+	if dockerversion.VERSION != "" {
357
+		fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
358
+	}
359
+	fmt.Fprintf(cli.out, "Go version (client): %s\n", goruntime.Version())
360
+	if dockerversion.GITCOMMIT != "" {
361
+		fmt.Fprintf(cli.out, "Git commit (client): %s\n", dockerversion.GITCOMMIT)
362
+	}
363
+
364
+	body, _, err := readBody(cli.call("GET", "/version", nil, false))
365
+	if err != nil {
366
+		return err
367
+	}
368
+
369
+	out := engine.NewOutput()
370
+	remoteVersion, err := out.AddEnv()
371
+	if err != nil {
372
+		utils.Errorf("Error reading remote version: %s\n", err)
373
+		return err
374
+	}
375
+	if _, err := out.Write(body); err != nil {
376
+		utils.Errorf("Error reading remote version: %s\n", err)
377
+		return err
378
+	}
379
+	out.Close()
380
+	fmt.Fprintf(cli.out, "Server version: %s\n", remoteVersion.Get("Version"))
381
+	fmt.Fprintf(cli.out, "Git commit (server): %s\n", remoteVersion.Get("GitCommit"))
382
+	fmt.Fprintf(cli.out, "Go version (server): %s\n", remoteVersion.Get("GoVersion"))
383
+	release := utils.GetReleaseVersion()
384
+	if release != "" {
385
+		fmt.Fprintf(cli.out, "Last stable version: %s", release)
386
+		if (dockerversion.VERSION != "" || remoteVersion.Exists("Version")) && (strings.Trim(dockerversion.VERSION, "-dev") != release || strings.Trim(remoteVersion.Get("Version"), "-dev") != release) {
387
+			fmt.Fprintf(cli.out, ", please update docker")
388
+		}
389
+		fmt.Fprintf(cli.out, "\n")
390
+	}
391
+	return nil
392
+}
393
+
394
+// 'docker info': display system-wide information.
395
+func (cli *DockerCli) CmdInfo(args ...string) error {
396
+	cmd := cli.Subcmd("info", "", "Display system-wide information")
397
+	if err := cmd.Parse(args); err != nil {
398
+		return nil
399
+	}
400
+	if cmd.NArg() > 0 {
401
+		cmd.Usage()
402
+		return nil
403
+	}
404
+
405
+	body, _, err := readBody(cli.call("GET", "/info", nil, false))
406
+	if err != nil {
407
+		return err
408
+	}
409
+
410
+	out := engine.NewOutput()
411
+	remoteInfo, err := out.AddEnv()
412
+	if err != nil {
413
+		return err
414
+	}
415
+
416
+	if _, err := out.Write(body); err != nil {
417
+		utils.Errorf("Error reading remote info: %s\n", err)
418
+		return err
419
+	}
420
+	out.Close()
421
+
422
+	fmt.Fprintf(cli.out, "Containers: %d\n", remoteInfo.GetInt("Containers"))
423
+	fmt.Fprintf(cli.out, "Images: %d\n", remoteInfo.GetInt("Images"))
424
+	fmt.Fprintf(cli.out, "Storage Driver: %s\n", remoteInfo.Get("Driver"))
425
+	var driverStatus [][2]string
426
+	if err := remoteInfo.GetJson("DriverStatus", &driverStatus); err != nil {
427
+		return err
428
+	}
429
+	for _, pair := range driverStatus {
430
+		fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1])
431
+	}
432
+	fmt.Fprintf(cli.out, "Execution Driver: %s\n", remoteInfo.Get("ExecutionDriver"))
433
+	fmt.Fprintf(cli.out, "Kernel Version: %s\n", remoteInfo.Get("KernelVersion"))
434
+
435
+	if remoteInfo.GetBool("Debug") || os.Getenv("DEBUG") != "" {
436
+		fmt.Fprintf(cli.out, "Debug mode (server): %v\n", remoteInfo.GetBool("Debug"))
437
+		fmt.Fprintf(cli.out, "Debug mode (client): %v\n", os.Getenv("DEBUG") != "")
438
+		fmt.Fprintf(cli.out, "Fds: %d\n", remoteInfo.GetInt("NFd"))
439
+		fmt.Fprintf(cli.out, "Goroutines: %d\n", remoteInfo.GetInt("NGoroutines"))
440
+		fmt.Fprintf(cli.out, "EventsListeners: %d\n", remoteInfo.GetInt("NEventsListener"))
441
+
442
+		if initSha1 := remoteInfo.Get("InitSha1"); initSha1 != "" {
443
+			fmt.Fprintf(cli.out, "Init SHA1: %s\n", initSha1)
444
+		}
445
+		if initPath := remoteInfo.Get("InitPath"); initPath != "" {
446
+			fmt.Fprintf(cli.out, "Init Path: %s\n", initPath)
447
+		}
448
+	}
449
+
450
+	if len(remoteInfo.GetList("IndexServerAddress")) != 0 {
451
+		cli.LoadConfigFile()
452
+		u := cli.configFile.Configs[remoteInfo.Get("IndexServerAddress")].Username
453
+		if len(u) > 0 {
454
+			fmt.Fprintf(cli.out, "Username: %v\n", u)
455
+			fmt.Fprintf(cli.out, "Registry: %v\n", remoteInfo.GetList("IndexServerAddress"))
456
+		}
457
+	}
458
+	if !remoteInfo.GetBool("MemoryLimit") {
459
+		fmt.Fprintf(cli.err, "WARNING: No memory limit support\n")
460
+	}
461
+	if !remoteInfo.GetBool("SwapLimit") {
462
+		fmt.Fprintf(cli.err, "WARNING: No swap limit support\n")
463
+	}
464
+	if !remoteInfo.GetBool("IPv4Forwarding") {
465
+		fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled.\n")
466
+	}
467
+	return nil
468
+}
469
+
470
+func (cli *DockerCli) CmdStop(args ...string) error {
471
+	cmd := cli.Subcmd("stop", "[OPTIONS] CONTAINER [CONTAINER...]", "Stop a running container (Send SIGTERM, and then SIGKILL after grace period)")
472
+	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it.")
473
+	if err := cmd.Parse(args); err != nil {
474
+		return nil
475
+	}
476
+	if cmd.NArg() < 1 {
477
+		cmd.Usage()
478
+		return nil
479
+	}
480
+
481
+	v := url.Values{}
482
+	v.Set("t", strconv.Itoa(*nSeconds))
483
+
484
+	var encounteredError error
485
+	for _, name := range cmd.Args() {
486
+		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/stop?"+v.Encode(), nil, false))
487
+		if err != nil {
488
+			fmt.Fprintf(cli.err, "%s\n", err)
489
+			encounteredError = fmt.Errorf("Error: failed to stop one or more containers")
490
+		} else {
491
+			fmt.Fprintf(cli.out, "%s\n", name)
492
+		}
493
+	}
494
+	return encounteredError
495
+}
496
+
497
+func (cli *DockerCli) CmdRestart(args ...string) error {
498
+	cmd := cli.Subcmd("restart", "[OPTIONS] CONTAINER [CONTAINER...]", "Restart a running container")
499
+	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default=10")
500
+	if err := cmd.Parse(args); err != nil {
501
+		return nil
502
+	}
503
+	if cmd.NArg() < 1 {
504
+		cmd.Usage()
505
+		return nil
506
+	}
507
+
508
+	v := url.Values{}
509
+	v.Set("t", strconv.Itoa(*nSeconds))
510
+
511
+	var encounteredError error
512
+	for _, name := range cmd.Args() {
513
+		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/restart?"+v.Encode(), nil, false))
514
+		if err != nil {
515
+			fmt.Fprintf(cli.err, "%s\n", err)
516
+			encounteredError = fmt.Errorf("Error: failed to restart one or more containers")
517
+		} else {
518
+			fmt.Fprintf(cli.out, "%s\n", name)
519
+		}
520
+	}
521
+	return encounteredError
522
+}
523
+
524
+func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
525
+	sigc := make(chan os.Signal, 1)
526
+	signal.CatchAll(sigc)
527
+	go func() {
528
+		for s := range sigc {
529
+			if s == syscall.SIGCHLD {
530
+				continue
531
+			}
532
+			var sig string
533
+			for sigStr, sigN := range signal.SignalMap {
534
+				if sigN == s {
535
+					sig = sigStr
536
+					break
537
+				}
538
+			}
539
+			if sig == "" {
540
+				utils.Errorf("Unsupported signal: %d. Discarding.", s)
541
+			}
542
+			if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", cid, sig), nil, false)); err != nil {
543
+				utils.Debugf("Error sending signal: %s", err)
544
+			}
545
+		}
546
+	}()
547
+	return sigc
548
+}
549
+
550
+func (cli *DockerCli) CmdStart(args ...string) error {
551
+	cmd := cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container")
552
+	attach := cmd.Bool([]string{"a", "-attach"}, false, "Attach container's stdout/stderr and forward all signals to the process")
553
+	openStdin := cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's stdin")
554
+	if err := cmd.Parse(args); err != nil {
555
+		return nil
556
+	}
557
+	if cmd.NArg() < 1 {
558
+		cmd.Usage()
559
+		return nil
560
+	}
561
+
562
+	var cErr chan error
563
+	var tty bool
564
+	if *attach || *openStdin {
565
+		if cmd.NArg() > 1 {
566
+			return fmt.Errorf("You cannot start and attach multiple containers at once.")
567
+		}
568
+
569
+		body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false))
570
+		if err != nil {
571
+			return err
572
+		}
573
+
574
+		container := &api.Container{}
575
+		err = json.Unmarshal(body, container)
576
+		if err != nil {
577
+			return err
578
+		}
579
+
580
+		tty = container.Config.Tty
581
+
582
+		if !container.Config.Tty {
583
+			sigc := cli.forwardAllSignals(cmd.Arg(0))
584
+			defer signal.StopCatch(sigc)
585
+		}
586
+
587
+		var in io.ReadCloser
588
+
589
+		v := url.Values{}
590
+		v.Set("stream", "1")
591
+		if *openStdin && container.Config.OpenStdin {
592
+			v.Set("stdin", "1")
593
+			in = cli.in
594
+		}
595
+		v.Set("stdout", "1")
596
+		v.Set("stderr", "1")
597
+
598
+		cErr = utils.Go(func() error {
599
+			return cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), container.Config.Tty, in, cli.out, cli.err, nil)
600
+		})
601
+	}
602
+
603
+	var encounteredError error
604
+	for _, name := range cmd.Args() {
605
+		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/start", nil, false))
606
+		if err != nil {
607
+			if !*attach || !*openStdin {
608
+				fmt.Fprintf(cli.err, "%s\n", err)
609
+				encounteredError = fmt.Errorf("Error: failed to start one or more containers")
610
+			}
611
+		} else {
612
+			if !*attach || !*openStdin {
613
+				fmt.Fprintf(cli.out, "%s\n", name)
614
+			}
615
+		}
616
+	}
617
+	if encounteredError != nil {
618
+		if *openStdin || *attach {
619
+			cli.in.Close()
620
+			<-cErr
621
+		}
622
+		return encounteredError
623
+	}
624
+
625
+	if *openStdin || *attach {
626
+		if tty && cli.isTerminal {
627
+			if err := cli.monitorTtySize(cmd.Arg(0)); err != nil {
628
+				utils.Errorf("Error monitoring TTY size: %s\n", err)
629
+			}
630
+		}
631
+		return <-cErr
632
+	}
633
+	return nil
634
+}
635
+
636
+func (cli *DockerCli) CmdInspect(args ...string) error {
637
+	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container/image")
638
+	tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
639
+	if err := cmd.Parse(args); err != nil {
640
+		return nil
641
+	}
642
+	if cmd.NArg() < 1 {
643
+		cmd.Usage()
644
+		return nil
645
+	}
646
+
647
+	var tmpl *template.Template
648
+	if *tmplStr != "" {
649
+		var err error
650
+		if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil {
651
+			fmt.Fprintf(cli.err, "Template parsing error: %v\n", err)
652
+			return &utils.StatusError{StatusCode: 64,
653
+				Status: "Template parsing error: " + err.Error()}
654
+		}
655
+	}
656
+
657
+	indented := new(bytes.Buffer)
658
+	indented.WriteByte('[')
659
+	status := 0
660
+
661
+	for _, name := range cmd.Args() {
662
+		obj, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, false))
663
+		if err != nil {
664
+			obj, _, err = readBody(cli.call("GET", "/images/"+name+"/json", nil, false))
665
+			if err != nil {
666
+				if strings.Contains(err.Error(), "No such") {
667
+					fmt.Fprintf(cli.err, "Error: No such image or container: %s\n", name)
668
+				} else {
669
+					fmt.Fprintf(cli.err, "%s", err)
670
+				}
671
+				status = 1
672
+				continue
673
+			}
674
+		}
675
+
676
+		if tmpl == nil {
677
+			if err = json.Indent(indented, obj, "", "    "); err != nil {
678
+				fmt.Fprintf(cli.err, "%s\n", err)
679
+				status = 1
680
+				continue
681
+			}
682
+		} else {
683
+			// Has template, will render
684
+			var value interface{}
685
+			if err := json.Unmarshal(obj, &value); err != nil {
686
+				fmt.Fprintf(cli.err, "%s\n", err)
687
+				status = 1
688
+				continue
689
+			}
690
+			if err := tmpl.Execute(cli.out, value); err != nil {
691
+				return err
692
+			}
693
+			cli.out.Write([]byte{'\n'})
694
+		}
695
+		indented.WriteString(",")
696
+	}
697
+
698
+	if indented.Len() > 1 {
699
+		// Remove trailing ','
700
+		indented.Truncate(indented.Len() - 1)
701
+	}
702
+	indented.WriteByte(']')
703
+
704
+	if tmpl == nil {
705
+		if _, err := io.Copy(cli.out, indented); err != nil {
706
+			return err
707
+		}
708
+	}
709
+
710
+	if status != 0 {
711
+		return &utils.StatusError{StatusCode: status}
712
+	}
713
+	return nil
714
+}
715
+
716
+func (cli *DockerCli) CmdTop(args ...string) error {
717
+	cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Lookup the running processes of a container")
718
+	if err := cmd.Parse(args); err != nil {
719
+		return nil
720
+	}
721
+	if cmd.NArg() == 0 {
722
+		cmd.Usage()
723
+		return nil
724
+	}
725
+	val := url.Values{}
726
+	if cmd.NArg() > 1 {
727
+		val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
728
+	}
729
+
730
+	stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil, false)
731
+	if err != nil {
732
+		return err
733
+	}
734
+	var procs engine.Env
735
+	if err := procs.Decode(stream); err != nil {
736
+		return err
737
+	}
738
+	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
739
+	fmt.Fprintln(w, strings.Join(procs.GetList("Titles"), "\t"))
740
+	processes := [][]string{}
741
+	if err := procs.GetJson("Processes", &processes); err != nil {
742
+		return err
743
+	}
744
+	for _, proc := range processes {
745
+		fmt.Fprintln(w, strings.Join(proc, "\t"))
746
+	}
747
+	w.Flush()
748
+	return nil
749
+}
750
+
751
+func (cli *DockerCli) CmdPort(args ...string) error {
752
+	cmd := cli.Subcmd("port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT")
753
+	if err := cmd.Parse(args); err != nil {
754
+		return nil
755
+	}
756
+	if cmd.NArg() != 2 {
757
+		cmd.Usage()
758
+		return nil
759
+	}
760
+
761
+	var (
762
+		port      = cmd.Arg(1)
763
+		proto     = "tcp"
764
+		parts     = strings.SplitN(port, "/", 2)
765
+		container api.Container
766
+	)
767
+
768
+	if len(parts) == 2 && len(parts[1]) != 0 {
769
+		port = parts[0]
770
+		proto = parts[1]
771
+	}
772
+	body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false))
773
+	if err != nil {
774
+		return err
775
+	}
776
+
777
+	err = json.Unmarshal(body, &container)
778
+	if err != nil {
779
+		return err
780
+	}
781
+
782
+	if frontends, exists := container.NetworkSettings.Ports[nat.Port(port+"/"+proto)]; exists && frontends != nil {
783
+		for _, frontend := range frontends {
784
+			fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort)
785
+		}
786
+	} else {
787
+		return fmt.Errorf("Error: No public port '%s' published for %s", cmd.Arg(1), cmd.Arg(0))
788
+	}
789
+	return nil
790
+}
791
+
792
+// 'docker rmi IMAGE' removes all images with the name IMAGE
793
+func (cli *DockerCli) CmdRmi(args ...string) error {
794
+	var (
795
+		cmd     = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images")
796
+		force   = cmd.Bool([]string{"f", "-force"}, false, "Force")
797
+		noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
798
+	)
799
+	if err := cmd.Parse(args); err != nil {
800
+		return nil
801
+	}
802
+	if cmd.NArg() < 1 {
803
+		cmd.Usage()
804
+		return nil
805
+	}
806
+
807
+	v := url.Values{}
808
+	if *force {
809
+		v.Set("force", "1")
810
+	}
811
+	if *noprune {
812
+		v.Set("noprune", "1")
813
+	}
814
+
815
+	var encounteredError error
816
+	for _, name := range cmd.Args() {
817
+		body, _, err := readBody(cli.call("DELETE", "/images/"+name+"?"+v.Encode(), nil, false))
818
+		if err != nil {
819
+			fmt.Fprintf(cli.err, "%s\n", err)
820
+			encounteredError = fmt.Errorf("Error: failed to remove one or more images")
821
+		} else {
822
+			outs := engine.NewTable("Created", 0)
823
+			if _, err := outs.ReadListFrom(body); err != nil {
824
+				fmt.Fprintf(cli.err, "%s\n", err)
825
+				encounteredError = fmt.Errorf("Error: failed to remove one or more images")
826
+				continue
827
+			}
828
+			for _, out := range outs.Data {
829
+				if out.Get("Deleted") != "" {
830
+					fmt.Fprintf(cli.out, "Deleted: %s\n", out.Get("Deleted"))
831
+				} else {
832
+					fmt.Fprintf(cli.out, "Untagged: %s\n", out.Get("Untagged"))
833
+				}
834
+			}
835
+		}
836
+	}
837
+	return encounteredError
838
+}
839
+
840
+func (cli *DockerCli) CmdHistory(args ...string) error {
841
+	cmd := cli.Subcmd("history", "[OPTIONS] IMAGE", "Show the history of an image")
842
+	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
843
+	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
844
+
845
+	if err := cmd.Parse(args); err != nil {
846
+		return nil
847
+	}
848
+	if cmd.NArg() != 1 {
849
+		cmd.Usage()
850
+		return nil
851
+	}
852
+
853
+	body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, false))
854
+	if err != nil {
855
+		return err
856
+	}
857
+
858
+	outs := engine.NewTable("Created", 0)
859
+	if _, err := outs.ReadListFrom(body); err != nil {
860
+		return err
861
+	}
862
+
863
+	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
864
+	if !*quiet {
865
+		fmt.Fprintln(w, "IMAGE\tCREATED\tCREATED BY\tSIZE")
866
+	}
867
+
868
+	for _, out := range outs.Data {
869
+		outID := out.Get("Id")
870
+		if !*quiet {
871
+			if *noTrunc {
872
+				fmt.Fprintf(w, "%s\t", outID)
873
+			} else {
874
+				fmt.Fprintf(w, "%s\t", utils.TruncateID(outID))
875
+			}
876
+
877
+			fmt.Fprintf(w, "%s ago\t", utils.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))))
878
+
879
+			if *noTrunc {
880
+				fmt.Fprintf(w, "%s\t", out.Get("CreatedBy"))
881
+			} else {
882
+				fmt.Fprintf(w, "%s\t", utils.Trunc(out.Get("CreatedBy"), 45))
883
+			}
884
+			fmt.Fprintf(w, "%s\n", utils.HumanSize(out.GetInt64("Size")))
885
+		} else {
886
+			if *noTrunc {
887
+				fmt.Fprintln(w, outID)
888
+			} else {
889
+				fmt.Fprintln(w, utils.TruncateID(outID))
890
+			}
891
+		}
892
+	}
893
+	w.Flush()
894
+	return nil
895
+}
896
+
897
+func (cli *DockerCli) CmdRm(args ...string) error {
898
+	cmd := cli.Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove one or more containers")
899
+	v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated to the container")
900
+	link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
901
+	force := cmd.Bool([]string{"f", "-force"}, false, "Force removal of running container")
902
+
903
+	if err := cmd.Parse(args); err != nil {
904
+		return nil
905
+	}
906
+	if cmd.NArg() < 1 {
907
+		cmd.Usage()
908
+		return nil
909
+	}
910
+	val := url.Values{}
911
+	if *v {
912
+		val.Set("v", "1")
913
+	}
914
+	if *link {
915
+		val.Set("link", "1")
916
+	}
917
+	if *force {
918
+		val.Set("force", "1")
919
+	}
920
+
921
+	var encounteredError error
922
+	for _, name := range cmd.Args() {
923
+		_, _, err := readBody(cli.call("DELETE", "/containers/"+name+"?"+val.Encode(), nil, false))
924
+		if err != nil {
925
+			fmt.Fprintf(cli.err, "%s\n", err)
926
+			encounteredError = fmt.Errorf("Error: failed to remove one or more containers")
927
+		} else {
928
+			fmt.Fprintf(cli.out, "%s\n", name)
929
+		}
930
+	}
931
+	return encounteredError
932
+}
933
+
934
+// 'docker kill NAME' kills a running container
935
+func (cli *DockerCli) CmdKill(args ...string) error {
936
+	cmd := cli.Subcmd("kill", "[OPTIONS] CONTAINER [CONTAINER...]", "Kill a running container (send SIGKILL, or specified signal)")
937
+	signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
938
+
939
+	if err := cmd.Parse(args); err != nil {
940
+		return nil
941
+	}
942
+	if cmd.NArg() < 1 {
943
+		cmd.Usage()
944
+		return nil
945
+	}
946
+
947
+	var encounteredError error
948
+	for _, name := range cmd.Args() {
949
+		if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", name, *signal), nil, false)); err != nil {
950
+			fmt.Fprintf(cli.err, "%s\n", err)
951
+			encounteredError = fmt.Errorf("Error: failed to kill one or more containers")
952
+		} else {
953
+			fmt.Fprintf(cli.out, "%s\n", name)
954
+		}
955
+	}
956
+	return encounteredError
957
+}
958
+
959
+func (cli *DockerCli) CmdImport(args ...string) error {
960
+	cmd := cli.Subcmd("import", "URL|- [REPOSITORY[:TAG]]", "Create an empty filesystem image and import the contents of the tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it.")
961
+
962
+	if err := cmd.Parse(args); err != nil {
963
+		return nil
964
+	}
965
+	if cmd.NArg() < 1 {
966
+		cmd.Usage()
967
+		return nil
968
+	}
969
+
970
+	var src, repository, tag string
971
+
972
+	if cmd.NArg() == 3 {
973
+		fmt.Fprintf(cli.err, "[DEPRECATED] The format 'URL|- [REPOSITORY [TAG]]' as been deprecated. Please use URL|- [REPOSITORY[:TAG]]\n")
974
+		src, repository, tag = cmd.Arg(0), cmd.Arg(1), cmd.Arg(2)
975
+	} else {
976
+		src = cmd.Arg(0)
977
+		repository, tag = utils.ParseRepositoryTag(cmd.Arg(1))
978
+	}
979
+	v := url.Values{}
980
+
981
+	if repository != "" {
982
+		//Check if the given image name can be resolved
983
+		if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
984
+			return err
985
+		}
986
+	}
987
+
988
+	v.Set("repo", repository)
989
+	v.Set("tag", tag)
990
+	v.Set("fromSrc", src)
991
+
992
+	var in io.Reader
993
+
994
+	if src == "-" {
995
+		in = cli.in
996
+	}
997
+
998
+	return cli.stream("POST", "/images/create?"+v.Encode(), in, cli.out, nil)
999
+}
1000
+
1001
+func (cli *DockerCli) CmdPush(args ...string) error {
1002
+	cmd := cli.Subcmd("push", "NAME", "Push an image or a repository to the registry")
1003
+	if err := cmd.Parse(args); err != nil {
1004
+		return nil
1005
+	}
1006
+	name := cmd.Arg(0)
1007
+
1008
+	if name == "" {
1009
+		cmd.Usage()
1010
+		return nil
1011
+	}
1012
+
1013
+	cli.LoadConfigFile()
1014
+
1015
+	// Resolve the Repository name from fqn to hostname + name
1016
+	hostname, _, err := registry.ResolveRepositoryName(name)
1017
+	if err != nil {
1018
+		return err
1019
+	}
1020
+	// Resolve the Auth config relevant for this server
1021
+	authConfig := cli.configFile.ResolveAuthConfig(hostname)
1022
+	// If we're not using a custom registry, we know the restrictions
1023
+	// applied to repository names and can warn the user in advance.
1024
+	// Custom repositories can have different rules, and we must also
1025
+	// allow pushing by image ID.
1026
+	if len(strings.SplitN(name, "/", 2)) == 1 {
1027
+		username := cli.configFile.Configs[registry.IndexServerAddress()].Username
1028
+		if username == "" {
1029
+			username = "<user>"
1030
+		}
1031
+		return fmt.Errorf("You cannot push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", username, name)
1032
+	}
1033
+
1034
+	v := url.Values{}
1035
+	push := func(authConfig registry.AuthConfig) error {
1036
+		buf, err := json.Marshal(authConfig)
1037
+		if err != nil {
1038
+			return err
1039
+		}
1040
+		registryAuthHeader := []string{
1041
+			base64.URLEncoding.EncodeToString(buf),
1042
+		}
1043
+
1044
+		return cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), nil, cli.out, map[string][]string{
1045
+			"X-Registry-Auth": registryAuthHeader,
1046
+		})
1047
+	}
1048
+
1049
+	if err := push(authConfig); err != nil {
1050
+		if strings.Contains(err.Error(), "Status 401") {
1051
+			fmt.Fprintln(cli.out, "\nPlease login prior to push:")
1052
+			if err := cli.CmdLogin(hostname); err != nil {
1053
+				return err
1054
+			}
1055
+			authConfig := cli.configFile.ResolveAuthConfig(hostname)
1056
+			return push(authConfig)
1057
+		}
1058
+		return err
1059
+	}
1060
+	return nil
1061
+}
1062
+
1063
+func (cli *DockerCli) CmdPull(args ...string) error {
1064
+	cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry")
1065
+	tag := cmd.String([]string{"#t", "#-tag"}, "", "Download tagged image in repository")
1066
+	if err := cmd.Parse(args); err != nil {
1067
+		return nil
1068
+	}
1069
+
1070
+	if cmd.NArg() != 1 {
1071
+		cmd.Usage()
1072
+		return nil
1073
+	}
1074
+
1075
+	remote, parsedTag := utils.ParseRepositoryTag(cmd.Arg(0))
1076
+	if *tag == "" {
1077
+		*tag = parsedTag
1078
+	}
1079
+
1080
+	// Resolve the Repository name from fqn to hostname + name
1081
+	hostname, _, err := registry.ResolveRepositoryName(remote)
1082
+	if err != nil {
1083
+		return err
1084
+	}
1085
+
1086
+	cli.LoadConfigFile()
1087
+
1088
+	// Resolve the Auth config relevant for this server
1089
+	authConfig := cli.configFile.ResolveAuthConfig(hostname)
1090
+	v := url.Values{}
1091
+	v.Set("fromImage", remote)
1092
+	v.Set("tag", *tag)
1093
+
1094
+	pull := func(authConfig registry.AuthConfig) error {
1095
+		buf, err := json.Marshal(authConfig)
1096
+		if err != nil {
1097
+			return err
1098
+		}
1099
+		registryAuthHeader := []string{
1100
+			base64.URLEncoding.EncodeToString(buf),
1101
+		}
1102
+
1103
+		return cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.out, map[string][]string{
1104
+			"X-Registry-Auth": registryAuthHeader,
1105
+		})
1106
+	}
1107
+
1108
+	if err := pull(authConfig); err != nil {
1109
+		if strings.Contains(err.Error(), "Status 401") {
1110
+			fmt.Fprintln(cli.out, "\nPlease login prior to pull:")
1111
+			if err := cli.CmdLogin(hostname); err != nil {
1112
+				return err
1113
+			}
1114
+			authConfig := cli.configFile.ResolveAuthConfig(hostname)
1115
+			return pull(authConfig)
1116
+		}
1117
+		return err
1118
+	}
1119
+
1120
+	return nil
1121
+}
1122
+
1123
+func (cli *DockerCli) CmdImages(args ...string) error {
1124
+	cmd := cli.Subcmd("images", "[OPTIONS] [NAME]", "List images")
1125
+	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
1126
+	all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (by default filter out the intermediate images used to build)")
1127
+	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
1128
+	flViz := cmd.Bool([]string{"v", "#viz", "-viz"}, false, "Output graph in graphviz format")
1129
+	flTree := cmd.Bool([]string{"t", "#tree", "-tree"}, false, "Output graph in tree format")
1130
+
1131
+	if err := cmd.Parse(args); err != nil {
1132
+		return nil
1133
+	}
1134
+	if cmd.NArg() > 1 {
1135
+		cmd.Usage()
1136
+		return nil
1137
+	}
1138
+
1139
+	filter := cmd.Arg(0)
1140
+
1141
+	if *flViz || *flTree {
1142
+		body, _, err := readBody(cli.call("GET", "/images/json?all=1", nil, false))
1143
+		if err != nil {
1144
+			return err
1145
+		}
1146
+
1147
+		outs := engine.NewTable("Created", 0)
1148
+		if _, err := outs.ReadListFrom(body); err != nil {
1149
+			return err
1150
+		}
1151
+
1152
+		var (
1153
+			printNode  func(cli *DockerCli, noTrunc bool, image *engine.Env, prefix string)
1154
+			startImage *engine.Env
1155
+
1156
+			roots    = engine.NewTable("Created", outs.Len())
1157
+			byParent = make(map[string]*engine.Table)
1158
+		)
1159
+
1160
+		for _, image := range outs.Data {
1161
+			if image.Get("ParentId") == "" {
1162
+				roots.Add(image)
1163
+			} else {
1164
+				if children, exists := byParent[image.Get("ParentId")]; exists {
1165
+					children.Add(image)
1166
+				} else {
1167
+					byParent[image.Get("ParentId")] = engine.NewTable("Created", 1)
1168
+					byParent[image.Get("ParentId")].Add(image)
1169
+				}
1170
+			}
1171
+
1172
+			if filter != "" {
1173
+				if filter == image.Get("Id") || filter == utils.TruncateID(image.Get("Id")) {
1174
+					startImage = image
1175
+				}
1176
+
1177
+				for _, repotag := range image.GetList("RepoTags") {
1178
+					if repotag == filter {
1179
+						startImage = image
1180
+					}
1181
+				}
1182
+			}
1183
+		}
1184
+
1185
+		if *flViz {
1186
+			fmt.Fprintf(cli.out, "digraph docker {\n")
1187
+			printNode = (*DockerCli).printVizNode
1188
+		} else {
1189
+			printNode = (*DockerCli).printTreeNode
1190
+		}
1191
+
1192
+		if startImage != nil {
1193
+			root := engine.NewTable("Created", 1)
1194
+			root.Add(startImage)
1195
+			cli.WalkTree(*noTrunc, root, byParent, "", printNode)
1196
+		} else if filter == "" {
1197
+			cli.WalkTree(*noTrunc, roots, byParent, "", printNode)
1198
+		}
1199
+		if *flViz {
1200
+			fmt.Fprintf(cli.out, " base [style=invisible]\n}\n")
1201
+		}
1202
+	} else {
1203
+		v := url.Values{}
1204
+		if cmd.NArg() == 1 {
1205
+			v.Set("filter", filter)
1206
+		}
1207
+		if *all {
1208
+			v.Set("all", "1")
1209
+		}
1210
+
1211
+		body, _, err := readBody(cli.call("GET", "/images/json?"+v.Encode(), nil, false))
1212
+
1213
+		if err != nil {
1214
+			return err
1215
+		}
1216
+
1217
+		outs := engine.NewTable("Created", 0)
1218
+		if _, err := outs.ReadListFrom(body); err != nil {
1219
+			return err
1220
+		}
1221
+
1222
+		w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
1223
+		if !*quiet {
1224
+			fmt.Fprintln(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tVIRTUAL SIZE")
1225
+		}
1226
+
1227
+		for _, out := range outs.Data {
1228
+			for _, repotag := range out.GetList("RepoTags") {
1229
+
1230
+				repo, tag := utils.ParseRepositoryTag(repotag)
1231
+				outID := out.Get("Id")
1232
+				if !*noTrunc {
1233
+					outID = utils.TruncateID(outID)
1234
+				}
1235
+
1236
+				if !*quiet {
1237
+					fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, outID, utils.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), utils.HumanSize(out.GetInt64("VirtualSize")))
1238
+				} else {
1239
+					fmt.Fprintln(w, outID)
1240
+				}
1241
+			}
1242
+		}
1243
+
1244
+		if !*quiet {
1245
+			w.Flush()
1246
+		}
1247
+	}
1248
+	return nil
1249
+}
1250
+
1251
+func (cli *DockerCli) WalkTree(noTrunc bool, images *engine.Table, byParent map[string]*engine.Table, prefix string, printNode func(cli *DockerCli, noTrunc bool, image *engine.Env, prefix string)) {
1252
+	length := images.Len()
1253
+	if length > 1 {
1254
+		for index, image := range images.Data {
1255
+			if index+1 == length {
1256
+				printNode(cli, noTrunc, image, prefix+"└─")
1257
+				if subimages, exists := byParent[image.Get("Id")]; exists {
1258
+					cli.WalkTree(noTrunc, subimages, byParent, prefix+"  ", printNode)
1259
+				}
1260
+			} else {
1261
+				printNode(cli, noTrunc, image, prefix+"\u251C─")
1262
+				if subimages, exists := byParent[image.Get("Id")]; exists {
1263
+					cli.WalkTree(noTrunc, subimages, byParent, prefix+"\u2502 ", printNode)
1264
+				}
1265
+			}
1266
+		}
1267
+	} else {
1268
+		for _, image := range images.Data {
1269
+			printNode(cli, noTrunc, image, prefix+"└─")
1270
+			if subimages, exists := byParent[image.Get("Id")]; exists {
1271
+				cli.WalkTree(noTrunc, subimages, byParent, prefix+"  ", printNode)
1272
+			}
1273
+		}
1274
+	}
1275
+}
1276
+
1277
+func (cli *DockerCli) printVizNode(noTrunc bool, image *engine.Env, prefix string) {
1278
+	var (
1279
+		imageID  string
1280
+		parentID string
1281
+	)
1282
+	if noTrunc {
1283
+		imageID = image.Get("Id")
1284
+		parentID = image.Get("ParentId")
1285
+	} else {
1286
+		imageID = utils.TruncateID(image.Get("Id"))
1287
+		parentID = utils.TruncateID(image.Get("ParentId"))
1288
+	}
1289
+	if parentID == "" {
1290
+		fmt.Fprintf(cli.out, " base -> \"%s\" [style=invis]\n", imageID)
1291
+	} else {
1292
+		fmt.Fprintf(cli.out, " \"%s\" -> \"%s\"\n", parentID, imageID)
1293
+	}
1294
+	if image.GetList("RepoTags")[0] != "<none>:<none>" {
1295
+		fmt.Fprintf(cli.out, " \"%s\" [label=\"%s\\n%s\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n",
1296
+			imageID, imageID, strings.Join(image.GetList("RepoTags"), "\\n"))
1297
+	}
1298
+}
1299
+
1300
+func (cli *DockerCli) printTreeNode(noTrunc bool, image *engine.Env, prefix string) {
1301
+	var imageID string
1302
+	if noTrunc {
1303
+		imageID = image.Get("Id")
1304
+	} else {
1305
+		imageID = utils.TruncateID(image.Get("Id"))
1306
+	}
1307
+
1308
+	fmt.Fprintf(cli.out, "%s%s Virtual Size: %s", prefix, imageID, utils.HumanSize(image.GetInt64("VirtualSize")))
1309
+	if image.GetList("RepoTags")[0] != "<none>:<none>" {
1310
+		fmt.Fprintf(cli.out, " Tags: %s\n", strings.Join(image.GetList("RepoTags"), ", "))
1311
+	} else {
1312
+		fmt.Fprint(cli.out, "\n")
1313
+	}
1314
+}
1315
+
1316
+func (cli *DockerCli) CmdPs(args ...string) error {
1317
+	cmd := cli.Subcmd("ps", "[OPTIONS]", "List containers")
1318
+	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
1319
+	size := cmd.Bool([]string{"s", "-size"}, false, "Display sizes")
1320
+	all := cmd.Bool([]string{"a", "-all"}, false, "Show all containers. Only running containers are shown by default.")
1321
+	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
1322
+	nLatest := cmd.Bool([]string{"l", "-latest"}, false, "Show only the latest created container, include non-running ones.")
1323
+	since := cmd.String([]string{"#sinceId", "#-since-id", "-since"}, "", "Show only containers created since Id or Name, include non-running ones.")
1324
+	before := cmd.String([]string{"#beforeId", "#-before-id", "-before"}, "", "Show only container created before Id or Name, include non-running ones.")
1325
+	last := cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.")
1326
+
1327
+	if err := cmd.Parse(args); err != nil {
1328
+		return nil
1329
+	}
1330
+	v := url.Values{}
1331
+	if *last == -1 && *nLatest {
1332
+		*last = 1
1333
+	}
1334
+	if *all {
1335
+		v.Set("all", "1")
1336
+	}
1337
+	if *last != -1 {
1338
+		v.Set("limit", strconv.Itoa(*last))
1339
+	}
1340
+	if *since != "" {
1341
+		v.Set("since", *since)
1342
+	}
1343
+	if *before != "" {
1344
+		v.Set("before", *before)
1345
+	}
1346
+	if *size {
1347
+		v.Set("size", "1")
1348
+	}
1349
+
1350
+	body, _, err := readBody(cli.call("GET", "/containers/json?"+v.Encode(), nil, false))
1351
+	if err != nil {
1352
+		return err
1353
+	}
1354
+
1355
+	outs := engine.NewTable("Created", 0)
1356
+	if _, err := outs.ReadListFrom(body); err != nil {
1357
+		return err
1358
+	}
1359
+	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
1360
+	if !*quiet {
1361
+		fmt.Fprint(w, "CONTAINER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES")
1362
+		if *size {
1363
+			fmt.Fprintln(w, "\tSIZE")
1364
+		} else {
1365
+			fmt.Fprint(w, "\n")
1366
+		}
1367
+	}
1368
+
1369
+	for _, out := range outs.Data {
1370
+		var (
1371
+			outID    = out.Get("Id")
1372
+			outNames = out.GetList("Names")
1373
+		)
1374
+
1375
+		if !*noTrunc {
1376
+			outID = utils.TruncateID(outID)
1377
+		}
1378
+
1379
+		// Remove the leading / from the names
1380
+		for i := 0; i < len(outNames); i++ {
1381
+			outNames[i] = outNames[i][1:]
1382
+		}
1383
+
1384
+		if !*quiet {
1385
+			var (
1386
+				outCommand = out.Get("Command")
1387
+				ports      = engine.NewTable("", 0)
1388
+			)
1389
+			if !*noTrunc {
1390
+				outCommand = utils.Trunc(outCommand, 20)
1391
+			}
1392
+			ports.ReadListFrom([]byte(out.Get("Ports")))
1393
+			fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", outID, out.Get("Image"), outCommand, utils.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), out.Get("Status"), api.DisplayablePorts(ports), strings.Join(outNames, ","))
1394
+			if *size {
1395
+				if out.GetInt("SizeRootFs") > 0 {
1396
+					fmt.Fprintf(w, "%s (virtual %s)\n", utils.HumanSize(out.GetInt64("SizeRw")), utils.HumanSize(out.GetInt64("SizeRootFs")))
1397
+				} else {
1398
+					fmt.Fprintf(w, "%s\n", utils.HumanSize(out.GetInt64("SizeRw")))
1399
+				}
1400
+			} else {
1401
+				fmt.Fprint(w, "\n")
1402
+			}
1403
+		} else {
1404
+			fmt.Fprintln(w, outID)
1405
+		}
1406
+	}
1407
+
1408
+	if !*quiet {
1409
+		w.Flush()
1410
+	}
1411
+	return nil
1412
+}
1413
+
1414
+func (cli *DockerCli) CmdCommit(args ...string) error {
1415
+	cmd := cli.Subcmd("commit", "[OPTIONS] CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes")
1416
+	flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
1417
+	flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\"")
1418
+	flConfig := cmd.String([]string{"#run", "-run"}, "", "Config automatically applied when the image is run. "+`(ex: --run='{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')`)
1419
+	if err := cmd.Parse(args); err != nil {
1420
+		return nil
1421
+	}
1422
+
1423
+	var name, repository, tag string
1424
+
1425
+	if cmd.NArg() == 3 {
1426
+		fmt.Fprintf(cli.err, "[DEPRECATED] The format 'CONTAINER [REPOSITORY [TAG]]' as been deprecated. Please use CONTAINER [REPOSITORY[:TAG]]\n")
1427
+		name, repository, tag = cmd.Arg(0), cmd.Arg(1), cmd.Arg(2)
1428
+	} else {
1429
+		name = cmd.Arg(0)
1430
+		repository, tag = utils.ParseRepositoryTag(cmd.Arg(1))
1431
+	}
1432
+
1433
+	if name == "" {
1434
+		cmd.Usage()
1435
+		return nil
1436
+	}
1437
+
1438
+	//Check if the given image name can be resolved
1439
+	if repository != "" {
1440
+		if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
1441
+			return err
1442
+		}
1443
+	}
1444
+
1445
+	v := url.Values{}
1446
+	v.Set("container", name)
1447
+	v.Set("repo", repository)
1448
+	v.Set("tag", tag)
1449
+	v.Set("comment", *flComment)
1450
+	v.Set("author", *flAuthor)
1451
+	var (
1452
+		config *runconfig.Config
1453
+		env    engine.Env
1454
+	)
1455
+	if *flConfig != "" {
1456
+		config = &runconfig.Config{}
1457
+		if err := json.Unmarshal([]byte(*flConfig), config); err != nil {
1458
+			return err
1459
+		}
1460
+	}
1461
+	stream, _, err := cli.call("POST", "/commit?"+v.Encode(), config, false)
1462
+	if err != nil {
1463
+		return err
1464
+	}
1465
+	if err := env.Decode(stream); err != nil {
1466
+		return err
1467
+	}
1468
+
1469
+	fmt.Fprintf(cli.out, "%s\n", env.Get("Id"))
1470
+	return nil
1471
+}
1472
+
1473
+func (cli *DockerCli) CmdEvents(args ...string) error {
1474
+	cmd := cli.Subcmd("events", "[OPTIONS]", "Get real time events from the server")
1475
+	since := cmd.String([]string{"#since", "-since"}, "", "Show previously created events and then stream.")
1476
+	if err := cmd.Parse(args); err != nil {
1477
+		return nil
1478
+	}
1479
+
1480
+	if cmd.NArg() != 0 {
1481
+		cmd.Usage()
1482
+		return nil
1483
+	}
1484
+
1485
+	v := url.Values{}
1486
+	if *since != "" {
1487
+		loc := time.FixedZone(time.Now().Zone())
1488
+		format := "2006-01-02 15:04:05 -0700 MST"
1489
+		if len(*since) < len(format) {
1490
+			format = format[:len(*since)]
1491
+		}
1492
+
1493
+		if t, err := time.ParseInLocation(format, *since, loc); err == nil {
1494
+			v.Set("since", strconv.FormatInt(t.Unix(), 10))
1495
+		} else {
1496
+			v.Set("since", *since)
1497
+		}
1498
+	}
1499
+
1500
+	if err := cli.stream("GET", "/events?"+v.Encode(), nil, cli.out, nil); err != nil {
1501
+		return err
1502
+	}
1503
+	return nil
1504
+}
1505
+
1506
+func (cli *DockerCli) CmdExport(args ...string) error {
1507
+	cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT")
1508
+	if err := cmd.Parse(args); err != nil {
1509
+		return nil
1510
+	}
1511
+
1512
+	if cmd.NArg() != 1 {
1513
+		cmd.Usage()
1514
+		return nil
1515
+	}
1516
+
1517
+	if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, cli.out, nil); err != nil {
1518
+		return err
1519
+	}
1520
+	return nil
1521
+}
1522
+
1523
+func (cli *DockerCli) CmdDiff(args ...string) error {
1524
+	cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem")
1525
+	if err := cmd.Parse(args); err != nil {
1526
+		return nil
1527
+	}
1528
+	if cmd.NArg() != 1 {
1529
+		cmd.Usage()
1530
+		return nil
1531
+	}
1532
+
1533
+	body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, false))
1534
+
1535
+	if err != nil {
1536
+		return err
1537
+	}
1538
+
1539
+	outs := engine.NewTable("", 0)
1540
+	if _, err := outs.ReadListFrom(body); err != nil {
1541
+		return err
1542
+	}
1543
+	for _, change := range outs.Data {
1544
+		var kind string
1545
+		switch change.GetInt("Kind") {
1546
+		case archive.ChangeModify:
1547
+			kind = "C"
1548
+		case archive.ChangeAdd:
1549
+			kind = "A"
1550
+		case archive.ChangeDelete:
1551
+			kind = "D"
1552
+		}
1553
+		fmt.Fprintf(cli.out, "%s %s\n", kind, change.Get("Path"))
1554
+	}
1555
+	return nil
1556
+}
1557
+
1558
+func (cli *DockerCli) CmdLogs(args ...string) error {
1559
+	cmd := cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container")
1560
+	follow := cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
1561
+	if err := cmd.Parse(args); err != nil {
1562
+		return nil
1563
+	}
1564
+	if cmd.NArg() != 1 {
1565
+		cmd.Usage()
1566
+		return nil
1567
+	}
1568
+	name := cmd.Arg(0)
1569
+	body, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, false))
1570
+	if err != nil {
1571
+		return err
1572
+	}
1573
+
1574
+	container := &api.Container{}
1575
+	err = json.Unmarshal(body, container)
1576
+	if err != nil {
1577
+		return err
1578
+	}
1579
+
1580
+	v := url.Values{}
1581
+	v.Set("logs", "1")
1582
+	v.Set("stdout", "1")
1583
+	v.Set("stderr", "1")
1584
+	if *follow && container.State.Running {
1585
+		v.Set("stream", "1")
1586
+	}
1587
+
1588
+	if err := cli.hijack("POST", "/containers/"+name+"/attach?"+v.Encode(), container.Config.Tty, nil, cli.out, cli.err, nil); err != nil {
1589
+		return err
1590
+	}
1591
+	return nil
1592
+}
1593
+
1594
+func (cli *DockerCli) CmdAttach(args ...string) error {
1595
+	cmd := cli.Subcmd("attach", "[OPTIONS] CONTAINER", "Attach to a running container")
1596
+	noStdin := cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach stdin")
1597
+	proxy := cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxify all received signal to the process (even in non-tty mode)")
1598
+	if err := cmd.Parse(args); err != nil {
1599
+		return nil
1600
+	}
1601
+	if cmd.NArg() != 1 {
1602
+		cmd.Usage()
1603
+		return nil
1604
+	}
1605
+	name := cmd.Arg(0)
1606
+	body, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, false))
1607
+	if err != nil {
1608
+		return err
1609
+	}
1610
+
1611
+	container := &api.Container{}
1612
+	err = json.Unmarshal(body, container)
1613
+	if err != nil {
1614
+		return err
1615
+	}
1616
+
1617
+	if !container.State.Running {
1618
+		return fmt.Errorf("You cannot attach to a stopped container, start it first")
1619
+	}
1620
+
1621
+	if container.Config.Tty && cli.isTerminal {
1622
+		if err := cli.monitorTtySize(cmd.Arg(0)); err != nil {
1623
+			utils.Debugf("Error monitoring TTY size: %s", err)
1624
+		}
1625
+	}
1626
+
1627
+	var in io.ReadCloser
1628
+
1629
+	v := url.Values{}
1630
+	v.Set("stream", "1")
1631
+	if !*noStdin && container.Config.OpenStdin {
1632
+		v.Set("stdin", "1")
1633
+		in = cli.in
1634
+	}
1635
+	v.Set("stdout", "1")
1636
+	v.Set("stderr", "1")
1637
+
1638
+	if *proxy && !container.Config.Tty {
1639
+		sigc := cli.forwardAllSignals(cmd.Arg(0))
1640
+		defer signal.StopCatch(sigc)
1641
+	}
1642
+
1643
+	if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), container.Config.Tty, in, cli.out, cli.err, nil); err != nil {
1644
+		return err
1645
+	}
1646
+
1647
+	_, status, err := getExitCode(cli, cmd.Arg(0))
1648
+	if err != nil {
1649
+		return err
1650
+	}
1651
+	if status != 0 {
1652
+		return &utils.StatusError{StatusCode: status}
1653
+	}
1654
+
1655
+	return nil
1656
+}
1657
+
1658
+func (cli *DockerCli) CmdSearch(args ...string) error {
1659
+	cmd := cli.Subcmd("search", "TERM", "Search the docker index for images")
1660
+	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
1661
+	trusted := cmd.Bool([]string{"t", "#trusted", "-trusted"}, false, "Only show trusted builds")
1662
+	stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least xxx stars")
1663
+	if err := cmd.Parse(args); err != nil {
1664
+		return nil
1665
+	}
1666
+	if cmd.NArg() != 1 {
1667
+		cmd.Usage()
1668
+		return nil
1669
+	}
1670
+
1671
+	v := url.Values{}
1672
+	v.Set("term", cmd.Arg(0))
1673
+
1674
+	body, _, err := readBody(cli.call("GET", "/images/search?"+v.Encode(), nil, true))
1675
+
1676
+	if err != nil {
1677
+		return err
1678
+	}
1679
+	outs := engine.NewTable("star_count", 0)
1680
+	if _, err := outs.ReadListFrom(body); err != nil {
1681
+		return err
1682
+	}
1683
+	w := tabwriter.NewWriter(cli.out, 10, 1, 3, ' ', 0)
1684
+	fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tTRUSTED\n")
1685
+	for _, out := range outs.Data {
1686
+		if (*trusted && !out.GetBool("is_trusted")) || (*stars > out.GetInt("star_count")) {
1687
+			continue
1688
+		}
1689
+		desc := strings.Replace(out.Get("description"), "\n", " ", -1)
1690
+		desc = strings.Replace(desc, "\r", " ", -1)
1691
+		if !*noTrunc && len(desc) > 45 {
1692
+			desc = utils.Trunc(desc, 42) + "..."
1693
+		}
1694
+		fmt.Fprintf(w, "%s\t%s\t%d\t", out.Get("name"), desc, out.GetInt("star_count"))
1695
+		if out.GetBool("is_official") {
1696
+			fmt.Fprint(w, "[OK]")
1697
+
1698
+		}
1699
+		fmt.Fprint(w, "\t")
1700
+		if out.GetBool("is_trusted") {
1701
+			fmt.Fprint(w, "[OK]")
1702
+		}
1703
+		fmt.Fprint(w, "\n")
1704
+	}
1705
+	w.Flush()
1706
+	return nil
1707
+}
1708
+
1709
+// Ports type - Used to parse multiple -p flags
1710
+type ports []int
1711
+
1712
+func (cli *DockerCli) CmdTag(args ...string) error {
1713
+	cmd := cli.Subcmd("tag", "[OPTIONS] IMAGE [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository")
1714
+	force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
1715
+	if err := cmd.Parse(args); err != nil {
1716
+		return nil
1717
+	}
1718
+	if cmd.NArg() != 2 && cmd.NArg() != 3 {
1719
+		cmd.Usage()
1720
+		return nil
1721
+	}
1722
+
1723
+	var repository, tag string
1724
+
1725
+	if cmd.NArg() == 3 {
1726
+		fmt.Fprintf(cli.err, "[DEPRECATED] The format 'IMAGE [REPOSITORY [TAG]]' as been deprecated. Please use IMAGE [REGISTRYHOST/][USERNAME/]NAME[:TAG]]\n")
1727
+		repository, tag = cmd.Arg(1), cmd.Arg(2)
1728
+	} else {
1729
+		repository, tag = utils.ParseRepositoryTag(cmd.Arg(1))
1730
+	}
1731
+
1732
+	v := url.Values{}
1733
+
1734
+	//Check if the given image name can be resolved
1735
+	if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
1736
+		return err
1737
+	}
1738
+	v.Set("repo", repository)
1739
+	v.Set("tag", tag)
1740
+
1741
+	if *force {
1742
+		v.Set("force", "1")
1743
+	}
1744
+
1745
+	if _, _, err := readBody(cli.call("POST", "/images/"+cmd.Arg(0)+"/tag?"+v.Encode(), nil, false)); err != nil {
1746
+		return err
1747
+	}
1748
+	return nil
1749
+}
1750
+
1751
+func (cli *DockerCli) CmdRun(args ...string) error {
1752
+	// FIXME: just use runconfig.Parse already
1753
+	config, hostConfig, cmd, err := runconfig.ParseSubcommand(cli.Subcmd("run", "[OPTIONS] IMAGE [COMMAND] [ARG...]", "Run a command in a new container"), args, nil)
1754
+	if err != nil {
1755
+		return err
1756
+	}
1757
+	if config.Image == "" {
1758
+		cmd.Usage()
1759
+		return nil
1760
+	}
1761
+
1762
+	// Retrieve relevant client-side config
1763
+	var (
1764
+		flName        = cmd.Lookup("name")
1765
+		flRm          = cmd.Lookup("rm")
1766
+		flSigProxy    = cmd.Lookup("sig-proxy")
1767
+		autoRemove, _ = strconv.ParseBool(flRm.Value.String())
1768
+		sigProxy, _   = strconv.ParseBool(flSigProxy.Value.String())
1769
+	)
1770
+
1771
+	// Disable sigProxy in case on TTY
1772
+	if config.Tty {
1773
+		sigProxy = false
1774
+	}
1775
+
1776
+	var containerIDFile io.WriteCloser
1777
+	if len(hostConfig.ContainerIDFile) > 0 {
1778
+		if _, err := os.Stat(hostConfig.ContainerIDFile); err == nil {
1779
+			return fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", hostConfig.ContainerIDFile)
1780
+		}
1781
+		if containerIDFile, err = os.Create(hostConfig.ContainerIDFile); err != nil {
1782
+			return fmt.Errorf("Failed to create the container ID file: %s", err)
1783
+		}
1784
+		defer func() {
1785
+			containerIDFile.Close()
1786
+			var (
1787
+				cidFileInfo os.FileInfo
1788
+				err         error
1789
+			)
1790
+			if cidFileInfo, err = os.Stat(hostConfig.ContainerIDFile); err != nil {
1791
+				return
1792
+			}
1793
+			if cidFileInfo.Size() == 0 {
1794
+				if err := os.Remove(hostConfig.ContainerIDFile); err != nil {
1795
+					fmt.Printf("failed to remove CID file '%s': %s \n", hostConfig.ContainerIDFile, err)
1796
+				}
1797
+			}
1798
+		}()
1799
+	}
1800
+
1801
+	containerValues := url.Values{}
1802
+	if name := flName.Value.String(); name != "" {
1803
+		containerValues.Set("name", name)
1804
+	}
1805
+
1806
+	//create the container
1807
+	stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), config, false)
1808
+	//if image not found try to pull it
1809
+	if statusCode == 404 {
1810
+		fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", config.Image)
1811
+
1812
+		v := url.Values{}
1813
+		repos, tag := utils.ParseRepositoryTag(config.Image)
1814
+		v.Set("fromImage", repos)
1815
+		v.Set("tag", tag)
1816
+
1817
+		// Resolve the Repository name from fqn to hostname + name
1818
+		hostname, _, err := registry.ResolveRepositoryName(repos)
1819
+		if err != nil {
1820
+			return err
1821
+		}
1822
+
1823
+		// Load the auth config file, to be able to pull the image
1824
+		cli.LoadConfigFile()
1825
+
1826
+		// Resolve the Auth config relevant for this server
1827
+		authConfig := cli.configFile.ResolveAuthConfig(hostname)
1828
+		buf, err := json.Marshal(authConfig)
1829
+		if err != nil {
1830
+			return err
1831
+		}
1832
+
1833
+		registryAuthHeader := []string{
1834
+			base64.URLEncoding.EncodeToString(buf),
1835
+		}
1836
+		if err = cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.err, map[string][]string{"X-Registry-Auth": registryAuthHeader}); err != nil {
1837
+			return err
1838
+		}
1839
+		if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), config, false); err != nil {
1840
+			return err
1841
+		}
1842
+	} else if err != nil {
1843
+		return err
1844
+	}
1845
+
1846
+	var runResult engine.Env
1847
+	if err := runResult.Decode(stream); err != nil {
1848
+		return err
1849
+	}
1850
+
1851
+	for _, warning := range runResult.GetList("Warnings") {
1852
+		fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
1853
+	}
1854
+
1855
+	if len(hostConfig.ContainerIDFile) > 0 {
1856
+		if _, err = containerIDFile.Write([]byte(runResult.Get("Id"))); err != nil {
1857
+			return fmt.Errorf("Failed to write the container ID to the file: %s", err)
1858
+		}
1859
+	}
1860
+
1861
+	if sigProxy {
1862
+		sigc := cli.forwardAllSignals(runResult.Get("Id"))
1863
+		defer signal.StopCatch(sigc)
1864
+	}
1865
+
1866
+	var (
1867
+		waitDisplayId chan struct{}
1868
+		errCh         chan error
1869
+	)
1870
+
1871
+	if !config.AttachStdout && !config.AttachStderr {
1872
+		// Make this asynchrone in order to let the client write to stdin before having to read the ID
1873
+		waitDisplayId = make(chan struct{})
1874
+		go func() {
1875
+			defer close(waitDisplayId)
1876
+			fmt.Fprintf(cli.out, "%s\n", runResult.Get("Id"))
1877
+		}()
1878
+	}
1879
+
1880
+	// We need to instanciate the chan because the select needs it. It can
1881
+	// be closed but can't be uninitialized.
1882
+	hijacked := make(chan io.Closer)
1883
+
1884
+	// Block the return until the chan gets closed
1885
+	defer func() {
1886
+		utils.Debugf("End of CmdRun(), Waiting for hijack to finish.")
1887
+		if _, ok := <-hijacked; ok {
1888
+			utils.Errorf("Hijack did not finish (chan still open)")
1889
+		}
1890
+	}()
1891
+
1892
+	if config.AttachStdin || config.AttachStdout || config.AttachStderr {
1893
+		var (
1894
+			out, stderr io.Writer
1895
+			in          io.ReadCloser
1896
+			v           = url.Values{}
1897
+		)
1898
+		v.Set("stream", "1")
1899
+
1900
+		if config.AttachStdin {
1901
+			v.Set("stdin", "1")
1902
+			in = cli.in
1903
+		}
1904
+		if config.AttachStdout {
1905
+			v.Set("stdout", "1")
1906
+			out = cli.out
1907
+		}
1908
+		if config.AttachStderr {
1909
+			v.Set("stderr", "1")
1910
+			if config.Tty {
1911
+				stderr = cli.out
1912
+			} else {
1913
+				stderr = cli.err
1914
+			}
1915
+		}
1916
+
1917
+		errCh = utils.Go(func() error {
1918
+			return cli.hijack("POST", "/containers/"+runResult.Get("Id")+"/attach?"+v.Encode(), config.Tty, in, out, stderr, hijacked)
1919
+		})
1920
+	} else {
1921
+		close(hijacked)
1922
+	}
1923
+
1924
+	// Acknowledge the hijack before starting
1925
+	select {
1926
+	case closer := <-hijacked:
1927
+		// Make sure that hijack gets closed when returning. (result
1928
+		// in closing hijack chan and freeing server's goroutines.
1929
+		if closer != nil {
1930
+			defer closer.Close()
1931
+		}
1932
+	case err := <-errCh:
1933
+		if err != nil {
1934
+			utils.Debugf("Error hijack: %s", err)
1935
+			return err
1936
+		}
1937
+	}
1938
+
1939
+	//start the container
1940
+	if _, _, err = readBody(cli.call("POST", "/containers/"+runResult.Get("Id")+"/start", hostConfig, false)); err != nil {
1941
+		return err
1942
+	}
1943
+
1944
+	if (config.AttachStdin || config.AttachStdout || config.AttachStderr) && config.Tty && cli.isTerminal {
1945
+		if err := cli.monitorTtySize(runResult.Get("Id")); err != nil {
1946
+			utils.Errorf("Error monitoring TTY size: %s\n", err)
1947
+		}
1948
+	}
1949
+
1950
+	if errCh != nil {
1951
+		if err := <-errCh; err != nil {
1952
+			utils.Debugf("Error hijack: %s", err)
1953
+			return err
1954
+		}
1955
+	}
1956
+
1957
+	// Detached mode: wait for the id to be displayed and return.
1958
+	if !config.AttachStdout && !config.AttachStderr {
1959
+		// Detached mode
1960
+		<-waitDisplayId
1961
+		return nil
1962
+	}
1963
+
1964
+	var status int
1965
+
1966
+	// Attached mode
1967
+	if autoRemove {
1968
+		// Autoremove: wait for the container to finish, retrieve
1969
+		// the exit code and remove the container
1970
+		if _, _, err := readBody(cli.call("POST", "/containers/"+runResult.Get("Id")+"/wait", nil, false)); err != nil {
1971
+			return err
1972
+		}
1973
+		if _, status, err = getExitCode(cli, runResult.Get("Id")); err != nil {
1974
+			return err
1975
+		}
1976
+		if _, _, err := readBody(cli.call("DELETE", "/containers/"+runResult.Get("Id")+"?v=1", nil, false)); err != nil {
1977
+			return err
1978
+		}
1979
+	} else {
1980
+		if !config.Tty {
1981
+			// In non-tty mode, we can't dettach, so we know we need to wait.
1982
+			if status, err = waitForExit(cli, runResult.Get("Id")); err != nil {
1983
+				return err
1984
+			}
1985
+		} else {
1986
+			// In TTY mode, there is a race. If the process dies too slowly, the state can be update after the getExitCode call
1987
+			// and result in a wrong exit code.
1988
+			// No Autoremove: Simply retrieve the exit code
1989
+			if _, status, err = getExitCode(cli, runResult.Get("Id")); err != nil {
1990
+				return err
1991
+			}
1992
+		}
1993
+	}
1994
+	if status != 0 {
1995
+		return &utils.StatusError{StatusCode: status}
1996
+	}
1997
+	return nil
1998
+}
1999
+
2000
+func (cli *DockerCli) CmdCp(args ...string) error {
2001
+	cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH")
2002
+	if err := cmd.Parse(args); err != nil {
2003
+		return nil
2004
+	}
2005
+
2006
+	if cmd.NArg() != 2 {
2007
+		cmd.Usage()
2008
+		return nil
2009
+	}
2010
+
2011
+	var copyData engine.Env
2012
+	info := strings.Split(cmd.Arg(0), ":")
2013
+
2014
+	if len(info) != 2 {
2015
+		return fmt.Errorf("Error: Path not specified")
2016
+	}
2017
+
2018
+	copyData.Set("Resource", info[1])
2019
+	copyData.Set("HostPath", cmd.Arg(1))
2020
+
2021
+	stream, statusCode, err := cli.call("POST", "/containers/"+info[0]+"/copy", copyData, false)
2022
+	if stream != nil {
2023
+		defer stream.Close()
2024
+	}
2025
+	if statusCode == 404 {
2026
+		return fmt.Errorf("No such container: %v", info[0])
2027
+	}
2028
+	if err != nil {
2029
+		return err
2030
+	}
2031
+
2032
+	if statusCode == 200 {
2033
+		if err := archive.Untar(stream, copyData.Get("HostPath"), nil); err != nil {
2034
+			return err
2035
+		}
2036
+	}
2037
+	return nil
2038
+}
2039
+
2040
+func (cli *DockerCli) CmdSave(args ...string) error {
2041
+	cmd := cli.Subcmd("save", "IMAGE", "Save an image to a tar archive (streamed to stdout by default)")
2042
+	outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
2043
+
2044
+	if err := cmd.Parse(args); err != nil {
2045
+		return err
2046
+	}
2047
+
2048
+	if cmd.NArg() != 1 {
2049
+		cmd.Usage()
2050
+		return nil
2051
+	}
2052
+
2053
+	var (
2054
+		output io.Writer = cli.out
2055
+		err    error
2056
+	)
2057
+	if *outfile != "" {
2058
+		output, err = os.Create(*outfile)
2059
+		if err != nil {
2060
+			return err
2061
+		}
2062
+	}
2063
+	image := cmd.Arg(0)
2064
+	if err := cli.stream("GET", "/images/"+image+"/get", nil, output, nil); err != nil {
2065
+		return err
2066
+	}
2067
+	return nil
2068
+}
2069
+
2070
+func (cli *DockerCli) CmdLoad(args ...string) error {
2071
+	cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN")
2072
+	infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
2073
+
2074
+	if err := cmd.Parse(args); err != nil {
2075
+		return err
2076
+	}
2077
+
2078
+	if cmd.NArg() != 0 {
2079
+		cmd.Usage()
2080
+		return nil
2081
+	}
2082
+
2083
+	var (
2084
+		input io.Reader = cli.in
2085
+		err   error
2086
+	)
2087
+	if *infile != "" {
2088
+		input, err = os.Open(*infile)
2089
+		if err != nil {
2090
+			return err
2091
+		}
2092
+	}
2093
+	if err := cli.stream("POST", "/images/load", input, cli.out, nil); err != nil {
2094
+		return err
2095
+	}
2096
+	return nil
2097
+}
0 2098
new file mode 100644
... ...
@@ -0,0 +1,390 @@
0
+package client
1
+
2
+import (
3
+	"bytes"
4
+	"crypto/tls"
5
+	"encoding/base64"
6
+	"encoding/json"
7
+	"errors"
8
+	"fmt"
9
+	"io"
10
+	"io/ioutil"
11
+	"net"
12
+	"net/http"
13
+	"net/http/httputil"
14
+	"net/url"
15
+	"os"
16
+	gosignal "os/signal"
17
+	"regexp"
18
+	goruntime "runtime"
19
+	"strconv"
20
+	"strings"
21
+	"syscall"
22
+
23
+	"github.com/dotcloud/docker/api"
24
+	"github.com/dotcloud/docker/dockerversion"
25
+	"github.com/dotcloud/docker/engine"
26
+	"github.com/dotcloud/docker/pkg/term"
27
+	"github.com/dotcloud/docker/registry"
28
+	"github.com/dotcloud/docker/utils"
29
+)
30
+
31
+var (
32
+	ErrConnectionRefused = errors.New("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
33
+)
34
+
35
+func (cli *DockerCli) dial() (net.Conn, error) {
36
+	if cli.tlsConfig != nil && cli.proto != "unix" {
37
+		return tls.Dial(cli.proto, cli.addr, cli.tlsConfig)
38
+	}
39
+	return net.Dial(cli.proto, cli.addr)
40
+}
41
+
42
+func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo bool) (io.ReadCloser, int, error) {
43
+	params := bytes.NewBuffer(nil)
44
+	if data != nil {
45
+		if env, ok := data.(engine.Env); ok {
46
+			if err := env.Encode(params); err != nil {
47
+				return nil, -1, err
48
+			}
49
+		} else {
50
+			buf, err := json.Marshal(data)
51
+			if err != nil {
52
+				return nil, -1, err
53
+			}
54
+			if _, err := params.Write(buf); err != nil {
55
+				return nil, -1, err
56
+			}
57
+		}
58
+	}
59
+	// fixme: refactor client to support redirect
60
+	re := regexp.MustCompile("/+")
61
+	path = re.ReplaceAllString(path, "/")
62
+
63
+	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), params)
64
+	if err != nil {
65
+		return nil, -1, err
66
+	}
67
+	if passAuthInfo {
68
+		cli.LoadConfigFile()
69
+		// Resolve the Auth config relevant for this server
70
+		authConfig := cli.configFile.ResolveAuthConfig(registry.IndexServerAddress())
71
+		getHeaders := func(authConfig registry.AuthConfig) (map[string][]string, error) {
72
+			buf, err := json.Marshal(authConfig)
73
+			if err != nil {
74
+				return nil, err
75
+			}
76
+			registryAuthHeader := []string{
77
+				base64.URLEncoding.EncodeToString(buf),
78
+			}
79
+			return map[string][]string{"X-Registry-Auth": registryAuthHeader}, nil
80
+		}
81
+		if headers, err := getHeaders(authConfig); err == nil && headers != nil {
82
+			for k, v := range headers {
83
+				req.Header[k] = v
84
+			}
85
+		}
86
+	}
87
+	req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION)
88
+	req.Host = cli.addr
89
+	if data != nil {
90
+		req.Header.Set("Content-Type", "application/json")
91
+	} else if method == "POST" {
92
+		req.Header.Set("Content-Type", "plain/text")
93
+	}
94
+	dial, err := cli.dial()
95
+	if err != nil {
96
+		if strings.Contains(err.Error(), "connection refused") {
97
+			return nil, -1, ErrConnectionRefused
98
+		}
99
+		return nil, -1, err
100
+	}
101
+	clientconn := httputil.NewClientConn(dial, nil)
102
+	resp, err := clientconn.Do(req)
103
+	if err != nil {
104
+		clientconn.Close()
105
+		if strings.Contains(err.Error(), "connection refused") {
106
+			return nil, -1, ErrConnectionRefused
107
+		}
108
+		return nil, -1, err
109
+	}
110
+
111
+	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
112
+		body, err := ioutil.ReadAll(resp.Body)
113
+		if err != nil {
114
+			return nil, -1, err
115
+		}
116
+		if len(body) == 0 {
117
+			return nil, resp.StatusCode, fmt.Errorf("Error: request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(resp.StatusCode), req.URL)
118
+		}
119
+		return nil, resp.StatusCode, fmt.Errorf("Error: %s", bytes.TrimSpace(body))
120
+	}
121
+
122
+	wrapper := utils.NewReadCloserWrapper(resp.Body, func() error {
123
+		if resp != nil && resp.Body != nil {
124
+			resp.Body.Close()
125
+		}
126
+		return clientconn.Close()
127
+	})
128
+	return wrapper, resp.StatusCode, nil
129
+}
130
+
131
+func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, headers map[string][]string) error {
132
+	if (method == "POST" || method == "PUT") && in == nil {
133
+		in = bytes.NewReader([]byte{})
134
+	}
135
+
136
+	// fixme: refactor client to support redirect
137
+	re := regexp.MustCompile("/+")
138
+	path = re.ReplaceAllString(path, "/")
139
+
140
+	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), in)
141
+	if err != nil {
142
+		return err
143
+	}
144
+	req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION)
145
+	req.Host = cli.addr
146
+	if method == "POST" {
147
+		req.Header.Set("Content-Type", "plain/text")
148
+	}
149
+
150
+	if headers != nil {
151
+		for k, v := range headers {
152
+			req.Header[k] = v
153
+		}
154
+	}
155
+
156
+	dial, err := cli.dial()
157
+	if err != nil {
158
+		if strings.Contains(err.Error(), "connection refused") {
159
+			return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
160
+		}
161
+		return err
162
+	}
163
+	clientconn := httputil.NewClientConn(dial, nil)
164
+	resp, err := clientconn.Do(req)
165
+	defer clientconn.Close()
166
+	if err != nil {
167
+		if strings.Contains(err.Error(), "connection refused") {
168
+			return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
169
+		}
170
+		return err
171
+	}
172
+	defer resp.Body.Close()
173
+
174
+	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
175
+		body, err := ioutil.ReadAll(resp.Body)
176
+		if err != nil {
177
+			return err
178
+		}
179
+		if len(body) == 0 {
180
+			return fmt.Errorf("Error :%s", http.StatusText(resp.StatusCode))
181
+		}
182
+		return fmt.Errorf("Error: %s", bytes.TrimSpace(body))
183
+	}
184
+
185
+	if api.MatchesContentType(resp.Header.Get("Content-Type"), "application/json") {
186
+		return utils.DisplayJSONMessagesStream(resp.Body, out, cli.terminalFd, cli.isTerminal)
187
+	}
188
+	if _, err := io.Copy(out, resp.Body); err != nil {
189
+		return err
190
+	}
191
+	return nil
192
+}
193
+
194
+func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, stdout, stderr io.Writer, started chan io.Closer) error {
195
+	defer func() {
196
+		if started != nil {
197
+			close(started)
198
+		}
199
+	}()
200
+	// fixme: refactor client to support redirect
201
+	re := regexp.MustCompile("/+")
202
+	path = re.ReplaceAllString(path, "/")
203
+
204
+	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), nil)
205
+	if err != nil {
206
+		return err
207
+	}
208
+	req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION)
209
+	req.Header.Set("Content-Type", "plain/text")
210
+	req.Host = cli.addr
211
+
212
+	dial, err := cli.dial()
213
+	if err != nil {
214
+		if strings.Contains(err.Error(), "connection refused") {
215
+			return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
216
+		}
217
+		return err
218
+	}
219
+	clientconn := httputil.NewClientConn(dial, nil)
220
+	defer clientconn.Close()
221
+
222
+	// Server hijacks the connection, error 'connection closed' expected
223
+	clientconn.Do(req)
224
+
225
+	rwc, br := clientconn.Hijack()
226
+	defer rwc.Close()
227
+
228
+	if started != nil {
229
+		started <- rwc
230
+	}
231
+
232
+	var receiveStdout chan error
233
+
234
+	var oldState *term.State
235
+
236
+	if in != nil && setRawTerminal && cli.isTerminal && os.Getenv("NORAW") == "" {
237
+		oldState, err = term.SetRawTerminal(cli.terminalFd)
238
+		if err != nil {
239
+			return err
240
+		}
241
+		defer term.RestoreTerminal(cli.terminalFd, oldState)
242
+	}
243
+
244
+	if stdout != nil || stderr != nil {
245
+		receiveStdout = utils.Go(func() (err error) {
246
+			defer func() {
247
+				if in != nil {
248
+					if setRawTerminal && cli.isTerminal {
249
+						term.RestoreTerminal(cli.terminalFd, oldState)
250
+					}
251
+					// For some reason this Close call blocks on darwin..
252
+					// As the client exists right after, simply discard the close
253
+					// until we find a better solution.
254
+					if goruntime.GOOS != "darwin" {
255
+						in.Close()
256
+					}
257
+				}
258
+			}()
259
+
260
+			// When TTY is ON, use regular copy
261
+			if setRawTerminal {
262
+				_, err = io.Copy(stdout, br)
263
+			} else {
264
+				_, err = utils.StdCopy(stdout, stderr, br)
265
+			}
266
+			utils.Debugf("[hijack] End of stdout")
267
+			return err
268
+		})
269
+	}
270
+
271
+	sendStdin := utils.Go(func() error {
272
+		if in != nil {
273
+			io.Copy(rwc, in)
274
+			utils.Debugf("[hijack] End of stdin")
275
+		}
276
+		if tcpc, ok := rwc.(*net.TCPConn); ok {
277
+			if err := tcpc.CloseWrite(); err != nil {
278
+				utils.Errorf("Couldn't send EOF: %s\n", err)
279
+			}
280
+		} else if unixc, ok := rwc.(*net.UnixConn); ok {
281
+			if err := unixc.CloseWrite(); err != nil {
282
+				utils.Errorf("Couldn't send EOF: %s\n", err)
283
+			}
284
+		}
285
+		// Discard errors due to pipe interruption
286
+		return nil
287
+	})
288
+
289
+	if stdout != nil || stderr != nil {
290
+		if err := <-receiveStdout; err != nil {
291
+			utils.Errorf("Error receiveStdout: %s", err)
292
+			return err
293
+		}
294
+	}
295
+
296
+	if !cli.isTerminal {
297
+		if err := <-sendStdin; err != nil {
298
+			utils.Errorf("Error sendStdin: %s", err)
299
+			return err
300
+		}
301
+	}
302
+	return nil
303
+
304
+}
305
+
306
+func (cli *DockerCli) resizeTty(id string) {
307
+	height, width := cli.getTtySize()
308
+	if height == 0 && width == 0 {
309
+		return
310
+	}
311
+	v := url.Values{}
312
+	v.Set("h", strconv.Itoa(height))
313
+	v.Set("w", strconv.Itoa(width))
314
+	if _, _, err := readBody(cli.call("POST", "/containers/"+id+"/resize?"+v.Encode(), nil, false)); err != nil {
315
+		utils.Errorf("Error resize: %s", err)
316
+	}
317
+}
318
+
319
+func waitForExit(cli *DockerCli, containerId string) (int, error) {
320
+	stream, _, err := cli.call("POST", "/containers/"+containerId+"/wait", nil, false)
321
+	if err != nil {
322
+		return -1, err
323
+	}
324
+
325
+	var out engine.Env
326
+	if err := out.Decode(stream); err != nil {
327
+		return -1, err
328
+	}
329
+	return out.GetInt("StatusCode"), nil
330
+}
331
+
332
+// getExitCode perform an inspect on the container. It returns
333
+// the running state and the exit code.
334
+func getExitCode(cli *DockerCli, containerId string) (bool, int, error) {
335
+	body, _, err := readBody(cli.call("GET", "/containers/"+containerId+"/json", nil, false))
336
+	if err != nil {
337
+		// If we can't connect, then the daemon probably died.
338
+		if err != ErrConnectionRefused {
339
+			return false, -1, err
340
+		}
341
+		return false, -1, nil
342
+	}
343
+	c := &api.Container{}
344
+	if err := json.Unmarshal(body, c); err != nil {
345
+		return false, -1, err
346
+	}
347
+	return c.State.Running, c.State.ExitCode, nil
348
+}
349
+
350
+func (cli *DockerCli) monitorTtySize(id string) error {
351
+	cli.resizeTty(id)
352
+
353
+	sigchan := make(chan os.Signal, 1)
354
+	gosignal.Notify(sigchan, syscall.SIGWINCH)
355
+	go func() {
356
+		for _ = range sigchan {
357
+			cli.resizeTty(id)
358
+		}
359
+	}()
360
+	return nil
361
+}
362
+
363
+func (cli *DockerCli) getTtySize() (int, int) {
364
+	if !cli.isTerminal {
365
+		return 0, 0
366
+	}
367
+	ws, err := term.GetWinsize(cli.terminalFd)
368
+	if err != nil {
369
+		utils.Errorf("Error getting size: %s", err)
370
+		if ws == nil {
371
+			return 0, 0
372
+		}
373
+	}
374
+	return int(ws.Height), int(ws.Width)
375
+}
376
+
377
+func readBody(stream io.ReadCloser, statusCode int, err error) ([]byte, int, error) {
378
+	if stream != nil {
379
+		defer stream.Close()
380
+	}
381
+	if err != nil {
382
+		return nil, statusCode, err
383
+	}
384
+	body, err := ioutil.ReadAll(stream)
385
+	if err != nil {
386
+		return nil, -1, err
387
+	}
388
+	return body, statusCode, nil
389
+}