commands.go
e5e66716
 package docker
e1b25e9b
 
 import (
2f84bab8
 	"bytes"
 	"encoding/json"
1aa7f139
 	"flag"
e1b25e9b
 	"fmt"
be20f3c5
 	"github.com/dotcloud/docker/auth"
e5104a4c
 	"github.com/dotcloud/docker/term"
2e69e172
 	"github.com/dotcloud/docker/utils"
2f84bab8
 	"io"
1aa7f139
 	"io/ioutil"
0f135ad7
 	"mime/multipart"
cf19be44
 	"net"
fae8284b
 	"net/http"
cf19be44
 	"net/http/httputil"
d6c3d022
 	"net/url"
d6c24092
 	"os"
deb9963e
 	"os/signal"
75d22440
 	"path"
1df5f409
 	"path/filepath"
76173121
 	"reflect"
4489005c
 	"regexp"
f857fa0d
 	"strconv"
2f84bab8
 	"strings"
deb9963e
 	"syscall"
2f84bab8
 	"text/tabwriter"
 	"time"
97401029
 	"unicode"
e1b25e9b
 )
 
02f0c1e4
 const VERSION = "0.4.4"
e1b25e9b
 
1967c834
 var (
fd224ee5
 	GITCOMMIT string
1967c834
 )
37a78902
 
31c98bda
 func (cli *DockerCli) getMethod(name string) (reflect.Method, bool) {
 	methodName := "Cmd" + strings.ToUpper(name[:1]) + strings.ToLower(name[1:])
 	return reflect.TypeOf(cli).MethodByName(methodName)
 }
 
3adf9ce0
 func ParseCommands(proto, addr string, args ...string) error {
 	cli := NewDockerCli(proto, addr)
1aa7f139
 
 	if len(args) > 0 {
31c98bda
 		method, exists := cli.getMethod(args[0])
1aa7f139
 		if !exists {
cf19be44
 			fmt.Println("Error: Command not found:", args[0])
31c98bda
 			return cli.CmdHelp(args[1:]...)
1aa7f139
 		}
76173121
 		ret := method.Func.CallSlice([]reflect.Value{
 			reflect.ValueOf(cli),
f2741554
 			reflect.ValueOf(args[1:]),
76173121
 		})[0].Interface()
 		if ret == nil {
 			return nil
1aa7f139
 		}
76173121
 		return ret.(error)
1aa7f139
 	}
76173121
 	return cli.CmdHelp(args...)
e1b25e9b
 }
 
f2741554
 func (cli *DockerCli) CmdHelp(args ...string) error {
31c98bda
 	if len(args) > 0 {
 		method, exists := cli.getMethod(args[0])
 		if !exists {
 			fmt.Println("Error: Command not found:", args[0])
 		} else {
 			method.Func.CallSlice([]reflect.Value{
 				reflect.ValueOf(cli),
 				reflect.ValueOf([]string{"--help"}),
 			})[0].Interface()
 			return nil
 		}
 	}
dede1585
 	help := fmt.Sprintf("Usage: docker [OPTIONS] COMMAND [arg...]\n  -H=[tcp://%s:%d]: tcp://host:port to bind/connect to or unix://path/to/socker to use\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n", DEFAULTHTTPHOST, DEFAULTHTTPPORT)
2c14d394
 	for _, command := range [][2]string{
 		{"attach", "Attach to a running container"},
 		{"build", "Build a container from a Dockerfile"},
 		{"commit", "Create a new image from a container's changes"},
 		{"diff", "Inspect changes on a container's filesystem"},
 		{"export", "Stream the contents of a container as a tar archive"},
 		{"history", "Show the history of an image"},
 		{"images", "List images"},
 		{"import", "Create a new filesystem image from the contents of a tarball"},
 		{"info", "Display system-wide information"},
 		{"insert", "Insert a file in an image"},
 		{"inspect", "Return low-level information on a container"},
 		{"kill", "Kill a running container"},
 		{"login", "Register or Login to the docker registry server"},
 		{"logs", "Fetch the logs of a container"},
 		{"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"},
 		{"ps", "List containers"},
 		{"pull", "Pull an image or a repository from the docker registry server"},
 		{"push", "Push an image or a repository to the docker registry server"},
 		{"restart", "Restart a running container"},
 		{"rm", "Remove a container"},
 		{"rmi", "Remove an image"},
 		{"run", "Run a command in a new container"},
 		{"search", "Search for an image in the docker index"},
 		{"start", "Start a stopped container"},
 		{"stop", "Stop a running container"},
 		{"tag", "Tag an image into a repository"},
 		{"version", "Show the docker version information"},
ca5ae266
 		{"wait", "Block until a container stops, then print its exit code"},
e1b25e9b
 	} {
2c14d394
 		help += fmt.Sprintf("    %-10.10s%s\n", command[0], command[1])
e1b25e9b
 	}
1aa7f139
 	fmt.Println(help)
 	return nil
e1b25e9b
 }
 
f2741554
 func (cli *DockerCli) CmdInsert(args ...string) error {
10c0e990
 	cmd := Subcmd("insert", "IMAGE URL PATH", "Insert a file from URL in the IMAGE at PATH")
97514831
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
 	if cmd.NArg() != 3 {
 		cmd.Usage()
 		return nil
 	}
 
10c0e990
 	v := url.Values{}
 	v.Set("url", cmd.Arg(1))
 	v.Set("path", cmd.Arg(2))
6f212538
 
0f135ad7
 	if err := cli.stream("POST", "/images/"+cmd.Arg(0)+"/insert?"+v.Encode(), nil, os.Stdout); err != nil {
97514831
 		return err
 	}
 	return nil
 }
 
f2741554
 func (cli *DockerCli) CmdBuild(args ...string) error {
28d5b2c1
 	cmd := Subcmd("build", "[OPTIONS] PATH | -", "Build a new container image from the source code at PATH")
 	tag := cmd.String("t", "", "Tag to be applied to the resulting image in case of success")
27319da0
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
fc864d2f
 	if cmd.NArg() != 1 {
 		cmd.Usage()
 		return nil
 	}
0f135ad7
 
0f312113
 	var (
d42c10aa
 		multipartBody io.Reader
33ea1483
 		file          io.ReadCloser
 		contextPath   string
0f312113
 	)
10c0e990
 
d42c10aa
 	// Init the needed component for the Multipart
 	buff := bytes.NewBuffer([]byte{})
 	multipartBody = buff
0f135ad7
 	w := multipart.NewWriter(buff)
d42c10aa
 	boundary := strings.NewReader("\r\n--" + w.Boundary() + "--\r\n")
0f135ad7
 
fc864d2f
 	compression := Bzip2
75d22440
 
fc864d2f
 	if cmd.Arg(0) == "-" {
d42c10aa
 		file = os.Stdin
 	} else {
fc864d2f
 		// Send Dockerfile from arg/Dockerfile (deprecate later)
86ada2fa
 		f, err := os.Open(path.Join(cmd.Arg(0), "Dockerfile"))
0f312113
 		if err != nil {
 			return err
 		}
86ada2fa
 		file = f
fc864d2f
 		// Send context from arg
 		// Create a FormFile multipart for the context if needed
d42c10aa
 		// FIXME: Use NewTempArchive in order to have the size and avoid too much memory usage?
90ffcda0
 		context, err := Tar(cmd.Arg(0), compression)
d42c10aa
 		if err != nil {
 			return err
 		}
2127f8d6
 		// NOTE: Do this in case '.' or '..' is input
 		absPath, err := filepath.Abs(cmd.Arg(0))
 		if err != nil {
 			return err
 		}
86ada2fa
 		wField, err := w.CreateFormFile("Context", filepath.Base(absPath)+"."+compression.Extension())
 		if err != nil {
d42c10aa
 			return err
 		}
86ada2fa
 		// FIXME: Find a way to have a progressbar for the upload too
 		sf := utils.NewStreamFormatter(false)
 		io.Copy(wField, utils.ProgressReader(ioutil.NopCloser(context), -1, os.Stdout, sf.FormatProgress("Caching Context", "%v/%v (%v)"), sf))
2127f8d6
 		multipartBody = io.MultiReader(multipartBody, boundary)
d42c10aa
 	}
fc864d2f
 	// Create a FormFile multipart for the Dockerfile
86ada2fa
 	wField, err := w.CreateFormFile("Dockerfile", "Dockerfile")
 	if err != nil {
fc864d2f
 		return err
 	}
86ada2fa
 	io.Copy(wField, file)
fc864d2f
 	multipartBody = io.MultiReader(multipartBody, boundary)
d42c10aa
 
56431d31
 	v := &url.Values{}
 	v.Set("t", *tag)
d42c10aa
 	// Send the multipart request with correct content-type
dbfb3eb9
 	req, err := http.NewRequest("POST", fmt.Sprintf("/v%g/build?%s", APIVERSION, v.Encode()), multipartBody)
d42c10aa
 	if err != nil {
0f135ad7
 		return err
 	}
d42c10aa
 	req.Header.Set("Content-Type", w.FormDataContentType())
33ea1483
 	if contextPath != "" {
90ffcda0
 		req.Header.Set("X-Docker-Context-Compression", compression.Flag())
2127f8d6
 		fmt.Println("Uploading Context...")
90ffcda0
 	}
3adf9ce0
 	dial, err := net.Dial(cli.proto, cli.addr)
 	if err != nil {
 		return err
 	}
 	clientconn := httputil.NewClientConn(dial, nil)
 	resp, err := clientconn.Do(req)
 	defer clientconn.Close()
0f135ad7
 	if err != nil {
 		return err
 	}
 	defer resp.Body.Close()
 
d42c10aa
 	// Check for errors
0f135ad7
 	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
 		body, err := ioutil.ReadAll(resp.Body)
0f312113
 		if err != nil {
 			return err
 		}
ab0d0a28
 		if len(body) == 0 {
 			return fmt.Errorf("Error: %s", http.StatusText(resp.StatusCode))
 		}
 		return fmt.Errorf("Error: %s", body)
dade9584
 	}
0f135ad7
 
d42c10aa
 	// Output the result
0f135ad7
 	if _, err := io.Copy(os.Stdout, resp.Body); err != nil {
dade9584
 		return err
 	}
0f135ad7
 
dade9584
 	return nil
27319da0
 }
 
be20f3c5
 // 'docker login': login / register a user to registry service.
f2741554
 func (cli *DockerCli) CmdLogin(args ...string) error {
d530d581
 	var readStringOnRawTerminal = func(stdin io.Reader, stdout io.Writer, echo bool) string {
97401029
 		char := make([]byte, 1)
 		buffer := make([]byte, 64)
 		var i = 0
 		for i < len(buffer) {
 			n, err := stdin.Read(char)
 			if n > 0 {
 				if char[0] == '\r' || char[0] == '\n' {
9d1fd231
 					stdout.Write([]byte{'\r', '\n'})
97401029
 					break
 				} else if char[0] == 127 || char[0] == '\b' {
 					if i > 0 {
 						if echo {
 							stdout.Write([]byte{'\b', ' ', '\b'})
 						}
 						i--
 					}
 				} else if !unicode.IsSpace(rune(char[0])) &&
 					!unicode.IsControl(rune(char[0])) {
 					if echo {
 						stdout.Write(char)
 					}
 					buffer[i] = char[0]
 					i++
 				}
 			}
 			if err != nil {
 				if err != io.EOF {
9d1fd231
 					fmt.Fprintf(stdout, "Read error: %v\r\n", err)
97401029
 				}
 				break
 			}
 		}
 		return string(buffer[:i])
 	}
d530d581
 	var readAndEchoString = func(stdin io.Reader, stdout io.Writer) string {
97401029
 		return readStringOnRawTerminal(stdin, stdout, true)
 	}
d530d581
 	var readString = func(stdin io.Reader, stdout io.Writer) string {
97401029
 		return readStringOnRawTerminal(stdin, stdout, false)
 	}
 
2e69e172
 	oldState, err := term.SetRawTerminal()
f37399d2
 	if err != nil {
 		return err
 	}
86ada2fa
 	defer term.RestoreTerminal(oldState)
7d0ab385
 
f37399d2
 	cmd := Subcmd("login", "", "Register or Login to the docker registry server")
878ae259
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
97401029
 
be20f3c5
 	var username string
 	var password string
 	var email string
 
49e65683
 	fmt.Print("Username (", cli.authConfig.Username, "): ")
f37399d2
 	username = readAndEchoString(os.Stdin, os.Stdout)
be20f3c5
 	if username == "" {
49e65683
 		username = cli.authConfig.Username
be20f3c5
 	}
49e65683
 	if username != cli.authConfig.Username {
f37399d2
 		fmt.Print("Password: ")
 		password = readString(os.Stdin, os.Stdout)
be20f3c5
 
878ae259
 		if password == "" {
d17f78c3
 			return fmt.Errorf("Error : Password Required")
878ae259
 		}
 
49e65683
 		fmt.Print("Email (", cli.authConfig.Email, "): ")
f37399d2
 		email = readAndEchoString(os.Stdin, os.Stdout)
be20f3c5
 		if email == "" {
49e65683
 			email = cli.authConfig.Email
be20f3c5
 		}
 	} else {
49e65683
 		email = cli.authConfig.Email
be20f3c5
 	}
49e65683
 	term.RestoreTerminal(oldState)
f37399d2
 
49e65683
 	cli.authConfig.Username = username
 	cli.authConfig.Password = password
 	cli.authConfig.Email = email
f37399d2
 
49e65683
 	body, _, err := cli.call("POST", "/auth", cli.authConfig)
be20f3c5
 	if err != nil {
f37399d2
 		return err
 	}
 
fd224ee5
 	var out2 APIAuth
24c785bc
 	err = json.Unmarshal(body, &out2)
f37399d2
 	if err != nil {
49e65683
 		auth.LoadConfig(os.Getenv("HOME"))
f37399d2
 		return err
be20f3c5
 	}
49e65683
 	auth.SaveConfig(cli.authConfig)
f37399d2
 	if out2.Status != "" {
 		fmt.Print(out2.Status)
d94a5b7d
 	}
be20f3c5
 	return nil
 }
 
ebaa50c4
 // 'docker wait': block until a container stops
f2741554
 func (cli *DockerCli) CmdWait(args ...string) error {
1e357c69
 	cmd := Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.")
ebaa50c4
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
 	if cmd.NArg() < 1 {
 		cmd.Usage()
 		return nil
 	}
 	for _, name := range cmd.Args() {
76173121
 		body, _, err := cli.call("POST", "/containers/"+name+"/wait", nil)
1e357c69
 		if err != nil {
 			fmt.Printf("%s", err)
ebaa50c4
 		} else {
fd224ee5
 			var out APIWait
1e357c69
 			err = json.Unmarshal(body, &out)
 			if err != nil {
 				return err
 			}
 			fmt.Println(out.StatusCode)
ebaa50c4
 		}
 	}
 	return nil
 }
 
e20a74d2
 // 'docker version': show version information
f2741554
 func (cli *DockerCli) CmdVersion(args ...string) error {
1aa7f139
 	cmd := Subcmd("version", "", "Show the docker version information.")
 	if err := cmd.Parse(args); err != nil {
 		return nil
2d32ac8c
 	}
f2741554
 
1aa7f139
 	if cmd.NArg() > 0 {
 		cmd.Usage()
 		return nil
 	}
 
76173121
 	body, _, err := cli.call("GET", "/version", nil)
1aa7f139
 	if err != nil {
 		return err
1967c834
 	}
1aa7f139
 
fd224ee5
 	var out APIVersion
1aa7f139
 	err = json.Unmarshal(body, &out)
 	if err != nil {
2e69e172
 		utils.Debugf("Error unmarshal: body: %s, err: %s\n", body, err)
1aa7f139
 		return err
 	}
1dae7a25
 	fmt.Println("Client version:", VERSION)
 	fmt.Println("Server version:", out.Version)
 	if out.GitCommit != "" {
 		fmt.Println("Git commit:", out.GitCommit)
4f0bda2d
 	}
1dae7a25
 	if out.GoVersion != "" {
 		fmt.Println("Go version:", out.GoVersion)
1967c834
 	}
e20a74d2
 	return nil
 }
 
e1b25e9b
 // 'docker info': display system-wide information.
f2741554
 func (cli *DockerCli) CmdInfo(args ...string) error {
1aa7f139
 	cmd := Subcmd("info", "", "Display system-wide information")
52b811f5
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
d91d0da4
 	if cmd.NArg() > 0 {
52b811f5
 		cmd.Usage()
 		return nil
63dd8f10
 	}
99f9b697
 
76173121
 	body, _, err := cli.call("GET", "/info", nil)
1aa7f139
 	if err != nil {
 		return err
99f9b697
 	}
5098c4fc
 
fd224ee5
 	var out APIInfo
1dae7a25
 	if err := json.Unmarshal(body, &out); err != nil {
1aa7f139
 		return err
 	}
1dae7a25
 
 	fmt.Printf("Containers: %d\n", out.Containers)
 	fmt.Printf("Images: %d\n", out.Images)
 	if out.Debug || os.Getenv("DEBUG") != "" {
 		fmt.Printf("Debug mode (server): %v\n", out.Debug)
 		fmt.Printf("Debug mode (client): %v\n", os.Getenv("DEBUG") != "")
 		fmt.Printf("Fds: %d\n", out.NFd)
 		fmt.Printf("Goroutines: %d\n", out.NGoroutines)
 	}
 	if !out.MemoryLimit {
 		fmt.Println("WARNING: No memory limit support")
 	}
 	if !out.SwapLimit {
 		fmt.Println("WARNING: No swap limit support")
99f9b697
 	}
e1b25e9b
 	return nil
 }
 
f2741554
 func (cli *DockerCli) CmdStop(args ...string) error {
4f0bda2d
 	cmd := Subcmd("stop", "[OPTIONS] CONTAINER [CONTAINER...]", "Stop a running container")
1615bb08
 	nSeconds := cmd.Int("t", 10, "wait t seconds before killing the container")
e1b25e9b
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
 	if cmd.NArg() < 1 {
 		cmd.Usage()
 		return nil
 	}
1aa7f139
 
4f0bda2d
 	v := url.Values{}
 	v.Set("t", strconv.Itoa(*nSeconds))
 
e1b25e9b
 	for _, name := range cmd.Args() {
76173121
 		_, _, err := cli.call("POST", "/containers/"+name+"/stop?"+v.Encode(), nil)
1aa7f139
 		if err != nil {
41077010
 			fmt.Fprintf(os.Stderr, "%s", err)
e1b25e9b
 		} else {
1aa7f139
 			fmt.Println(name)
d2885910
 		}
 	}
 	return nil
 }
 
f2741554
 func (cli *DockerCli) CmdRestart(args ...string) error {
4f0bda2d
 	cmd := Subcmd("restart", "[OPTIONS] CONTAINER [CONTAINER...]", "Restart a running container")
1615bb08
 	nSeconds := cmd.Int("t", 10, "wait t seconds before killing the container")
d2885910
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
 	if cmd.NArg() < 1 {
 		cmd.Usage()
 		return nil
 	}
1aa7f139
 
4f0bda2d
 	v := url.Values{}
 	v.Set("t", strconv.Itoa(*nSeconds))
 
d2885910
 	for _, name := range cmd.Args() {
76173121
 		_, _, err := cli.call("POST", "/containers/"+name+"/restart?"+v.Encode(), nil)
1aa7f139
 		if err != nil {
41077010
 			fmt.Fprintf(os.Stderr, "%s", err)
d2885910
 		} else {
1aa7f139
 			fmt.Println(name)
d2885910
 		}
 	}
 	return nil
 }
 
f2741554
 func (cli *DockerCli) CmdStart(args ...string) error {
1aa7f139
 	cmd := Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container")
d2885910
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
 	if cmd.NArg() < 1 {
 		cmd.Usage()
 		return nil
 	}
1aa7f139
 
 	for _, name := range args {
76173121
 		_, _, err := cli.call("POST", "/containers/"+name+"/start", nil)
1aa7f139
 		if err != nil {
41077010
 			fmt.Fprintf(os.Stderr, "%s", err)
d2885910
 		} else {
1aa7f139
 			fmt.Println(name)
e1b25e9b
 		}
 	}
 	return nil
 }
 
f2741554
 func (cli *DockerCli) CmdInspect(args ...string) error {
a799cdad
 	cmd := Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container/image")
e1b25e9b
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
a799cdad
 	if cmd.NArg() < 1 {
e1b25e9b
 		cmd.Usage()
 		return nil
 	}
41077010
 	fmt.Printf("[")
 	for i, name := range args {
 		if i > 0 {
 			fmt.Printf(",")
 		}
a799cdad
 		obj, _, err := cli.call("GET", "/containers/"+name+"/json", nil)
1e357c69
 		if err != nil {
a799cdad
 			obj, _, err = cli.call("GET", "/images/"+name+"/json", nil)
 			if err != nil {
41077010
 				fmt.Fprintf(os.Stderr, "%s", err)
a799cdad
 				continue
 			}
1e357c69
 		}
842cb890
 
a799cdad
 		indented := new(bytes.Buffer)
 		if err = json.Indent(indented, obj, "", "    "); err != nil {
41077010
 			fmt.Fprintf(os.Stderr, "%s", err)
a799cdad
 			continue
 		}
 		if _, err := io.Copy(os.Stdout, indented); err != nil {
41077010
 			fmt.Fprintf(os.Stderr, "%s", err)
a799cdad
 		}
e1b25e9b
 	}
41077010
 	fmt.Printf("]")
e1b25e9b
 	return nil
 }
 
f2741554
 func (cli *DockerCli) CmdPort(args ...string) error {
cf19be44
 	cmd := Subcmd("port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT")
410ebe37
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
 	if cmd.NArg() != 2 {
 		cmd.Usage()
 		return nil
 	}
075e1ebb
 
76173121
 	body, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil)
cf19be44
 	if err != nil {
 		return err
 	}
075e1ebb
 	var out Container
cf19be44
 	err = json.Unmarshal(body, &out)
 	if err != nil {
 		return err
410ebe37
 	}
075e1ebb
 
 	if frontend, exists := out.NetworkSettings.PortMapping[cmd.Arg(1)]; exists {
 		fmt.Println(frontend)
410ebe37
 	} else {
ab0d0a28
 		return fmt.Errorf("Error: No private port '%s' allocated on %s", cmd.Arg(1), cmd.Arg(0))
410ebe37
 	}
 	return nil
 }
 
3ba44d2d
 // 'docker rmi IMAGE' removes all images with the name IMAGE
f2741554
 func (cli *DockerCli) CmdRmi(args ...string) error {
1aa7f139
 	cmd := Subcmd("rmi", "IMAGE [IMAGE...]", "Remove an image")
c9d93cd3
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
 	if cmd.NArg() < 1 {
c3622a96
 		cmd.Usage()
 		return nil
 	}
1aa7f139
 
c3622a96
 	for _, name := range cmd.Args() {
9060b5c2
 		body, _, err := cli.call("DELETE", "/images/"+name, nil)
97f48e59
 		if err != nil {
9060b5c2
 			fmt.Fprintf(os.Stderr, "%s", err)
1aa7f139
 		} else {
66d9a733
 			var outs []APIRmi
9060b5c2
 			err = json.Unmarshal(body, &outs)
 			if err != nil {
 				return err
 			}
 			for _, out := range outs {
 				if out.Deleted != "" {
 					fmt.Println("Deleted:", out.Deleted)
 				} else {
 					fmt.Println("Untagged:", out.Untagged)
 				}
 			}
c3622a96
 		}
 	}
 	return nil
 }
e1b25e9b
 
f2741554
 func (cli *DockerCli) CmdHistory(args ...string) error {
1aa7f139
 	cmd := Subcmd("history", "IMAGE", "Show the history of an image")
a9a43918
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
 	if cmd.NArg() != 1 {
1ad69ad4
 		cmd.Usage()
 		return nil
 	}
1aa7f139
 
76173121
 	body, _, err := cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil)
1ad69ad4
 	if err != nil {
 		return err
 	}
1aa7f139
 
fd224ee5
 	var outs []APIHistory
1aa7f139
 	err = json.Unmarshal(body, &outs)
1ad69ad4
 	if err != nil {
 		return err
 	}
1aa7f139
 	w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
c298a91f
 	fmt.Fprintln(w, "ID\tCREATED\tCREATED BY")
1aa7f139
 
 	for _, out := range outs {
808faa63
 		if out.Tags != nil {
 			out.ID = out.Tags[0]
 		}
 		fmt.Fprintf(w, "%s \t%s ago\t%s\n", out.ID, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.CreatedBy)
1aa7f139
 	}
 	w.Flush()
 	return nil
1ad69ad4
 }
 
f2741554
 func (cli *DockerCli) CmdRm(args ...string) error {
6f9b574f
 	cmd := Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove a container")
3edd14b8
 	v := cmd.Bool("v", false, "Remove the volumes associated to the container")
e1b25e9b
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
c105049f
 	if cmd.NArg() < 1 {
 		cmd.Usage()
 		return nil
 	}
6f9b574f
 	val := url.Values{}
3edd14b8
 	if *v {
6f9b574f
 		val.Set("v", "1")
 	}
 	for _, name := range cmd.Args() {
76173121
 		_, _, err := cli.call("DELETE", "/containers/"+name+"?"+val.Encode(), nil)
1aa7f139
 		if err != nil {
 			fmt.Printf("%s", err)
 		} else {
 			fmt.Println(name)
3edd14b8
 		}
 	}
e1b25e9b
 	return nil
 }
 
 // 'docker kill NAME' kills a running container
f2741554
 func (cli *DockerCli) CmdKill(args ...string) error {
1aa7f139
 	cmd := Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container")
e1b25e9b
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
8987bd58
 	if cmd.NArg() < 1 {
 		cmd.Usage()
 		return nil
 	}
1aa7f139
 
 	for _, name := range args {
76173121
 		_, _, err := cli.call("POST", "/containers/"+name+"/kill", nil)
1aa7f139
 		if err != nil {
 			fmt.Printf("%s", err)
 		} else {
 			fmt.Println(name)
e1b25e9b
 		}
 	}
 	return nil
 }
 
f2741554
 func (cli *DockerCli) CmdImport(args ...string) error {
36b968bb
 	cmd := Subcmd("import", "URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball")
e1b25e9b
 
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
8987bd58
 	if cmd.NArg() < 1 {
 		cmd.Usage()
 		return nil
 	}
36b968bb
 	src, repository, tag := cmd.Arg(0), cmd.Arg(1), cmd.Arg(2)
 	v := url.Values{}
 	v.Set("repo", repository)
 	v.Set("tag", tag)
04cd20fa
 	v.Set("fromSrc", src)
36b968bb
 
f29e5dc8
 	err := cli.stream("POST", "/images/create?"+v.Encode(), os.Stdin, os.Stdout)
e1b25e9b
 	if err != nil {
 		return err
 	}
 	return nil
 }
 
f2741554
 func (cli *DockerCli) CmdPush(args ...string) error {
10c0e990
 	cmd := Subcmd("push", "[OPTION] NAME", "Push an image or a repository to the registry")
6644a3c7
 	registry := cmd.String("registry", "", "Registry host to push the image to")
edcfd687
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
f37399d2
 	name := cmd.Arg(0)
1ed78ee1
 
f37399d2
 	if name == "" {
edcfd687
 		cmd.Usage()
 		return nil
 	}
 
49e65683
 	if err := cli.checkIfLogged(*registry == "", "push"); err != nil {
f37399d2
 		return err
 	}
 
 	if len(strings.SplitN(name, "/", 2)) == 1 {
49e65683
 		return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", cli.authConfig.Username, name)
1ed78ee1
 	}
 
7e59b830
 	buf, err := json.Marshal(cli.authConfig)
 	if err != nil {
 		return err
1ed78ee1
 	}
a55a0d37
 	nameParts := strings.SplitN(name, "/", 2)
 	validNamespace := regexp.MustCompile(`^([a-z0-9_]{4,30})$`)
 	if !validNamespace.MatchString(nameParts[0]) {
 		return fmt.Errorf("Invalid namespace name (%s), only [a-z0-9_] are allowed, size between 4 and 30", nameParts[0])
 	}
 	validRepo := regexp.MustCompile(`^([a-zA-Z0-9-_.]+)$`)
 	if !validRepo.MatchString(nameParts[1]) {
 		return fmt.Errorf("Invalid repository name (%s), only [a-zA-Z0-9-_.] are allowed", nameParts[1])
4489005c
 	}
1ed78ee1
 
10c0e990
 	v := url.Values{}
 	v.Set("registry", *registry)
7e59b830
 	if err := cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), bytes.NewBuffer(buf), os.Stdout); err != nil {
0eed4b43
 		return err
 	}
 	return nil
edcfd687
 }
 
f2741554
 func (cli *DockerCli) CmdPull(args ...string) error {
cf19be44
 	cmd := Subcmd("pull", "NAME", "Pull an image or a repository from the registry")
2f082510
 	tag := cmd.String("t", "", "Download tagged image in repository")
 	registry := cmd.String("registry", "", "Registry to download from. Necessary if image is pulled by ID")
edcfd687
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
cf19be44
 
 	if cmd.NArg() != 1 {
edcfd687
 		cmd.Usage()
 		return nil
 	}
11c42948
 
10c0e990
 	remote := cmd.Arg(0)
e81a53ee
 	if strings.Contains(remote, ":") {
 		remoteParts := strings.Split(remote, ":")
 		tag = &remoteParts[1]
 		remote = remoteParts[0]
 	}
 
04cd20fa
 	v := url.Values{}
10c0e990
 	v.Set("fromImage", remote)
 	v.Set("tag", *tag)
 	v.Set("registry", *registry)
11c42948
 
f29e5dc8
 	if err := cli.stream("POST", "/images/create?"+v.Encode(), nil, os.Stdout); err != nil {
0eed4b43
 		return err
 	}
cf19be44
 
0eed4b43
 	return nil
edcfd687
 }
 
f2741554
 func (cli *DockerCli) CmdImages(args ...string) error {
1aa7f139
 	cmd := Subcmd("images", "[OPTIONS] [NAME]", "List images")
e1b25e9b
 	quiet := cmd.Bool("q", false, "only show numeric IDs")
1aa7f139
 	all := cmd.Bool("a", false, "show all images")
e82ff22f
 	noTrunc := cmd.Bool("notrunc", false, "Don't truncate output")
f4de9d91
 	flViz := cmd.Bool("viz", false, "output graph in graphviz format")
cf19be44
 
06d420d2
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
e1b25e9b
 	if cmd.NArg() > 1 {
 		cmd.Usage()
 		return nil
 	}
f4de9d91
 
 	if *flViz {
76173121
 		body, _, err := cli.call("GET", "/images/viz", false)
0ecf5e24
 		if err != nil {
10c0e990
 			return err
f4de9d91
 		}
0ecf5e24
 		fmt.Printf("%s", body)
f4de9d91
 	} else {
10c0e990
 		v := url.Values{}
f4de9d91
 		if cmd.NArg() == 1 {
10c0e990
 			v.Set("filter", cmd.Arg(0))
f4de9d91
 		}
10c0e990
 		if *all {
 			v.Set("all", "1")
f4de9d91
 		}
1aa7f139
 
76173121
 		body, _, err := cli.call("GET", "/images/json?"+v.Encode(), nil)
f4de9d91
 		if err != nil {
 			return err
 		}
1aa7f139
 
fd224ee5
 		var outs []APIImages
10c0e990
 		err = json.Unmarshal(body, &outs)
 		if err != nil {
 			return err
e1b25e9b
 		}
10c0e990
 
 		w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
1aa7f139
 		if !*quiet {
a91b7109
 			fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED\tSIZE")
44faa07b
 		}
1aa7f139
 
10c0e990
 		for _, out := range outs {
1990c49a
 			if out.Repository == "" {
 				out.Repository = "<none>"
 			}
 			if out.Tag == "" {
 				out.Tag = "<none>"
 			}
 
10c0e990
 			if !*quiet {
e82ff22f
 				fmt.Fprintf(w, "%s\t%s\t", out.Repository, out.Tag)
 				if *noTrunc {
fd224ee5
 					fmt.Fprintf(w, "%s\t", out.ID)
e82ff22f
 				} else {
fd224ee5
 					fmt.Fprintf(w, "%s\t", utils.TruncateID(out.ID))
e82ff22f
 				}
6fce89e6
 				fmt.Fprintf(w, "%s ago\t", utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))))
00cf2a1f
 				if out.VirtualSize > 0 {
 					fmt.Fprintf(w, "%s (virtual %s)\n", utils.HumanSize(out.Size), utils.HumanSize(out.VirtualSize))
6fce89e6
 				} else {
 					fmt.Fprintf(w, "%s\n", utils.HumanSize(out.Size))
 				}
10c0e990
 			} else {
e82ff22f
 				if *noTrunc {
fd224ee5
 					fmt.Fprintln(w, out.ID)
e82ff22f
 				} else {
fd224ee5
 					fmt.Fprintln(w, utils.TruncateID(out.ID))
e82ff22f
 				}
44faa07b
 			}
 		}
10c0e990
 
f4de9d91
 		if !*quiet {
 			w.Flush()
 		}
e1b25e9b
 	}
 	return nil
 }
 
f2741554
 func (cli *DockerCli) CmdPs(args ...string) error {
1aa7f139
 	cmd := Subcmd("ps", "[OPTIONS]", "List containers")
e1b25e9b
 	quiet := cmd.Bool("q", false, "Only display numeric IDs")
1aa7f139
 	all := cmd.Bool("a", false, "Show all containers. Only running containers are shown by default.")
 	noTrunc := cmd.Bool("notrunc", false, "Don't truncate output")
 	nLatest := cmd.Bool("l", false, "Show only the latest created container, include non-running ones.")
bc3fa506
 	since := cmd.String("sinceId", "", "Show only containers created since Id, include non-running ones.")
 	before := cmd.String("beforeId", "", "Show only container created before Id, include non-running ones.")
1aa7f139
 	last := cmd.Int("n", -1, "Show n last created containers, include non-running ones.")
 
e1b25e9b
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
1aa7f139
 	v := url.Values{}
 	if *last == -1 && *nLatest {
 		*last = 1
 	}
 	if *all {
30cb4b35
 		v.Set("all", "1")
1aa7f139
 	}
 	if *last != -1 {
60ddcaa1
 		v.Set("limit", strconv.Itoa(*last))
1aa7f139
 	}
bc3fa506
 	if *since != "" {
 		v.Set("since", *since)
 	}
 	if *before != "" {
 		v.Set("before", *before)
 	}
cf19be44
 
4f944392
 	body, _, err := cli.call("GET", "/containers/json?"+v.Encode(), nil)
1aa7f139
 	if err != nil {
 		return err
 	}
 
fd224ee5
 	var outs []APIContainers
1aa7f139
 	err = json.Unmarshal(body, &outs)
 	if err != nil {
 		return err
8c3331dc
 	}
1aa7f139
 	w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
2f84bab8
 	if !*quiet {
a91b7109
 		fmt.Fprintln(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tSIZE")
e1b25e9b
 	}
1aa7f139
 
 	for _, out := range outs {
e1b25e9b
 		if !*quiet {
1990c49a
 			if *noTrunc {
bf63cb90
 				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t", out.ID, out.Image, out.Command, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, out.Ports)
6fce89e6
 			} else {
bf63cb90
 				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t", utils.TruncateID(out.ID), out.Image, utils.Trunc(out.Command, 20), utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, out.Ports)
6fce89e6
 			}
a91b7109
 			if out.SizeRootFs > 0 {
6fce89e6
 				fmt.Fprintf(w, "%s (virtual %s)\n", utils.HumanSize(out.SizeRw), utils.HumanSize(out.SizeRootFs))
a91b7109
 			} else {
6fce89e6
 				fmt.Fprintf(w, "%s\n", utils.HumanSize(out.SizeRw))
a91b7109
 			}
e1b25e9b
 		} else {
1990c49a
 			if *noTrunc {
fd224ee5
 				fmt.Fprintln(w, out.ID)
1990c49a
 			} else {
fd224ee5
 				fmt.Fprintln(w, utils.TruncateID(out.ID))
1990c49a
 			}
e1b25e9b
 		}
 	}
1aa7f139
 
2f84bab8
 	if !*quiet {
e1b25e9b
 		w.Flush()
 	}
 	return nil
 }
 
f2741554
 func (cli *DockerCli) CmdCommit(args ...string) error {
79512b2a
 	cmd := Subcmd("commit", "[OPTIONS] CONTAINER [REPOSITORY [TAG]]", "Create a new image from a container's changes")
a6da7f13
 	flComment := cmd.String("m", "", "Commit message")
227a8142
 	flAuthor := cmd.String("author", "", "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\"")
5c30faf6
 	flConfig := cmd.String("run", "", "Config automatically applied when the image is run. "+`(ex: {"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')`)
e1b25e9b
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
79512b2a
 	name, repository, tag := cmd.Arg(0), cmd.Arg(1), cmd.Arg(2)
 	if name == "" {
e1b25e9b
 		cmd.Usage()
 		return nil
 	}
51d62282
 
79512b2a
 	v := url.Values{}
0b6c79b3
 	v.Set("container", name)
79512b2a
 	v.Set("repo", repository)
 	v.Set("tag", tag)
 	v.Set("comment", *flComment)
4f0bda2d
 	v.Set("author", *flAuthor)
a75a1b38
 	var config *Config
51d62282
 	if *flConfig != "" {
a75a1b38
 		config = &Config{}
ae974772
 		if err := json.Unmarshal([]byte(*flConfig), config); err != nil {
 			return err
 		}
51d62282
 	}
76173121
 	body, _, err := cli.call("POST", "/commit?"+v.Encode(), config)
8396798e
 	if err != nil {
 		return err
f7c5e92a
 	}
 
fd224ee5
 	apiID := &APIID{}
 	err = json.Unmarshal(body, apiID)
8396798e
 	if err != nil {
 		return err
e1b25e9b
 	}
79512b2a
 
fd224ee5
 	fmt.Println(apiID.ID)
8396798e
 	return nil
e1b25e9b
 }
 
f2741554
 func (cli *DockerCli) CmdExport(args ...string) error {
c7bbe7ca
 	cmd := Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive")
e1b25e9b
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
c7bbe7ca
 
 	if cmd.NArg() != 1 {
 		cmd.Usage()
e1b25e9b
 		return nil
 	}
c7bbe7ca
 
f29e5dc8
 	if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, os.Stdout); err != nil {
c7bbe7ca
 		return err
 	}
 	return nil
e1b25e9b
 }
 
f2741554
 func (cli *DockerCli) CmdDiff(args ...string) error {
1e357c69
 	cmd := Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem")
e1b25e9b
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
1e357c69
 	if cmd.NArg() != 1 {
8987bd58
 		cmd.Usage()
 		return nil
e1b25e9b
 	}
1e357c69
 
76173121
 	body, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil)
1e357c69
 	if err != nil {
 		return err
 	}
 
483c9425
 	changes := []Change{}
1e357c69
 	err = json.Unmarshal(body, &changes)
 	if err != nil {
 		return err
 	}
 	for _, change := range changes {
60ddcaa1
 		fmt.Println(change.String())
e1b25e9b
 	}
 	return nil
 }
 
f2741554
 func (cli *DockerCli) CmdLogs(args ...string) error {
1aa7f139
 	cmd := Subcmd("logs", "CONTAINER", "Fetch the logs of a container")
e1b25e9b
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
 	if cmd.NArg() != 1 {
 		cmd.Usage()
 		return nil
 	}
1aa7f139
 
fbcd8503
 	if err := cli.stream("POST", "/containers/"+cmd.Arg(0)+"/attach?logs=1&stdout=1", nil, os.Stdout); err != nil {
 		return err
 	}
 	if err := cli.stream("POST", "/containers/"+cmd.Arg(0)+"/attach?logs=1&stderr=1", nil, os.Stderr); err != nil {
1aa7f139
 		return err
e1b25e9b
 	}
1aa7f139
 	return nil
e1b25e9b
 }
 
f2741554
 func (cli *DockerCli) CmdAttach(args ...string) error {
30cb4b35
 	cmd := Subcmd("attach", "CONTAINER", "Attach to a running container")
e1b25e9b
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
 	if cmd.NArg() != 1 {
 		cmd.Usage()
 		return nil
 	}
6882c78c
 
76173121
 	body, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil)
131c6ab3
 	if err != nil {
 		return err
e1b25e9b
 	}
6882c78c
 
483c9425
 	container := &Container{}
 	err = json.Unmarshal(body, container)
131c6ab3
 	if err != nil {
 		return err
b76d63cb
 	}
 
c106ed32
 	if !container.State.Running {
 		return fmt.Errorf("Impossible to attach to a stopped container, start it first")
 	}
 
2eaa0a1d
 	if container.Config.Tty {
 		cli.monitorTtySize(cmd.Arg(0))
 	}
3a0ffbc7
 
a4bcf7e1
 	v := url.Values{}
 	v.Set("stream", "1")
 	v.Set("stdin", "1")
c00d1a6e
 	v.Set("stdout", "1")
3a0ffbc7
 	v.Set("stderr", "1")
 
3dc93e39
 	if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), container.Config.Tty, os.Stdin, os.Stdout); err != nil {
3a0ffbc7
 		return err
dcf4572a
 	}
30cb4b35
 	return nil
e1b25e9b
 }
 
f2741554
 func (cli *DockerCli) CmdSearch(args ...string) error {
59a6316f
 	cmd := Subcmd("search", "NAME", "Search the docker index for images")
d56c5406
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
 	if cmd.NArg() != 1 {
 		cmd.Usage()
 		return nil
 	}
40794113
 
59a6316f
 	v := url.Values{}
40794113
 	v.Set("term", cmd.Arg(0))
76173121
 	body, _, err := cli.call("GET", "/images/search?"+v.Encode(), nil)
40794113
 	if err != nil {
 		return err
 	}
 
fd224ee5
 	outs := []APISearch{}
40794113
 	err = json.Unmarshal(body, &outs)
d56c5406
 	if err != nil {
 		return err
 	}
59a6316f
 	fmt.Printf("Found %d results matching your query (\"%s\")\n", len(outs), cmd.Arg(0))
 	w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
d56c5406
 	fmt.Fprintf(w, "NAME\tDESCRIPTION\n")
59a6316f
 	for _, out := range outs {
8d4282cd
 		desc := strings.Replace(out.Description, "\n", " ", -1)
 		desc = strings.Replace(desc, "\r", " ", -1)
 		if len(desc) > 45 {
 			desc = utils.Trunc(desc, 42) + "..."
 		}
 		fmt.Fprintf(w, "%s\t%s\n", out.Name, desc)
d56c5406
 	}
 	w.Flush()
 	return nil
 }
 
f857fa0d
 // Ports type - Used to parse multiple -p flags
 type ports []int
 
34fbaa5f
 // ListOpts type
 type ListOpts []string
 
 func (opts *ListOpts) String() string {
 	return fmt.Sprint(*opts)
 }
 
 func (opts *ListOpts) Set(value string) error {
 	*opts = append(*opts, value)
 	return nil
 }
 
c04af2a3
 // AttachOpts stores arguments to 'docker run -a', eg. which streams to attach to
 type AttachOpts map[string]bool
 
4f36039e
 func NewAttachOpts() AttachOpts {
 	return make(AttachOpts)
c04af2a3
 }
 
4f36039e
 func (opts AttachOpts) String() string {
 	// Cast to underlying map type to avoid infinite recursion
 	return fmt.Sprintf("%v", map[string]bool(opts))
c04af2a3
 }
 
4f36039e
 func (opts AttachOpts) Set(val string) error {
c04af2a3
 	if val != "stdin" && val != "stdout" && val != "stderr" {
 		return fmt.Errorf("Unsupported stream name: %s", val)
 	}
4f36039e
 	opts[val] = true
c04af2a3
 	return nil
 }
 
4f36039e
 func (opts AttachOpts) Get(val string) bool {
 	if res, exists := opts[val]; exists {
c04af2a3
 		return res
 	}
 	return false
 }
 
1df5f409
 // PathOpts stores a unique set of absolute paths
faf8daa7
 type PathOpts map[string]struct{}
1df5f409
 
 func NewPathOpts() PathOpts {
 	return make(PathOpts)
 }
 
 func (opts PathOpts) String() string {
faf8daa7
 	return fmt.Sprintf("%v", map[string]struct{}(opts))
1df5f409
 }
 
 func (opts PathOpts) Set(val string) error {
 	if !filepath.IsAbs(val) {
 		return fmt.Errorf("%s is not an absolute path", val)
 	}
faf8daa7
 	opts[filepath.Clean(val)] = struct{}{}
1df5f409
 	return nil
 }
 
f2741554
 func (cli *DockerCli) CmdTag(args ...string) error {
cf19be44
 	cmd := Subcmd("tag", "[OPTIONS] IMAGE REPOSITORY [TAG]", "Tag an image into a repository")
bf7602bc
 	force := cmd.Bool("f", false, "Force")
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
cf19be44
 	if cmd.NArg() != 2 && cmd.NArg() != 3 {
bf7602bc
 		cmd.Usage()
 		return nil
 	}
cf19be44
 
 	v := url.Values{}
 	v.Set("repo", cmd.Arg(1))
 	if cmd.NArg() == 3 {
 		v.Set("tag", cmd.Arg(2))
 	}
 
 	if *force {
30cb4b35
 		v.Set("force", "1")
cf19be44
 	}
 
76173121
 	if _, _, err := cli.call("POST", "/images/"+cmd.Arg(0)+"/tag?"+v.Encode(), nil); err != nil {
cf19be44
 		return err
 	}
 	return nil
bf7602bc
 }
 
f2741554
 func (cli *DockerCli) CmdRun(args ...string) error {
10c0e990
 	config, cmd, err := ParseRun(args, nil)
031f91df
 	if err != nil {
 		return err
e1b25e9b
 	}
6ce64e84
 	if config.Image == "" {
cf19be44
 		cmd.Usage()
 		return nil
031f91df
 	}
7e1e7d14
 
a4bcf7e1
 	//create the container
76173121
 	body, statusCode, err := cli.call("POST", "/containers/create", config)
a4bcf7e1
 	//if image not found try to pull it
 	if statusCode == 404 {
04cd20fa
 		v := url.Values{}
 		v.Set("fromImage", config.Image)
f29e5dc8
 		err = cli.stream("POST", "/images/create?"+v.Encode(), nil, os.Stderr)
a4bcf7e1
 		if err != nil {
 			return err
 		}
76173121
 		body, _, err = cli.call("POST", "/containers/create", config)
04cd20fa
 		if err != nil {
 			return err
 		}
a4bcf7e1
 	}
 	if err != nil {
c808940c
 		return err
dcf4572a
 	}
6f212538
 
fd224ee5
 	out := &APIRun{}
483c9425
 	err = json.Unmarshal(body, out)
e1b25e9b
 	if err != nil {
a4bcf7e1
 		return err
e1b25e9b
 	}
a4bcf7e1
 
4f0bda2d
 	for _, warning := range out.Warnings {
 		fmt.Fprintln(os.Stderr, "WARNING: ", warning)
 	}
 
a4bcf7e1
 	//start the container
fd224ee5
 	_, _, err = cli.call("POST", "/containers/"+out.ID+"/start", nil)
1aa7f139
 	if err != nil {
c808940c
 		return err
e1b25e9b
 	}
a5b765a7
 
7e6ede63
 	if !config.AttachStdout && !config.AttachStderr {
 		fmt.Println(out.ID)
2b6ca387
 	} else {
2eaa0a1d
 		if config.Tty {
 			cli.monitorTtySize(out.ID)
 		}
c00d1a6e
 
 		v := url.Values{}
 		v.Set("logs", "1")
 		v.Set("stream", "1")
 
 		if config.AttachStdin {
 			v.Set("stdin", "1")
 		}
 		if config.AttachStdout {
 			v.Set("stdout", "1")
 		}
2b6ca387
 		if config.AttachStderr {
c00d1a6e
 			v.Set("stderr", "1")
 		}
e2d034e4
 		if err := cli.hijack("POST", "/containers/"+out.ID+"/attach?"+v.Encode(), config.Tty, os.Stdin, os.Stdout); err != nil {
2b6ca387
 			utils.Debugf("Error hijack: %s", err)
 			return err
a4bcf7e1
 		}
ac0e2769
 	}
a4bcf7e1
 	return nil
e1b25e9b
 }
cf19be44
 
49e65683
 func (cli *DockerCli) checkIfLogged(condition bool, action string) error {
4dab2fcc
 	// If condition AND the login failed
49e65683
 	if condition && cli.authConfig.Username == "" {
4dab2fcc
 		if err := cli.CmdLogin(""); err != nil {
49e65683
 			return err
1b0b962b
 		}
49e65683
 		if cli.authConfig.Username == "" {
 			return fmt.Errorf("Please login prior to %s. ('docker login')", action)
1b0b962b
 		}
 	}
49e65683
 	return nil
1b0b962b
 }
 
f2741554
 func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int, error) {
a4bcf7e1
 	var params io.Reader
cf19be44
 	if data != nil {
 		buf, err := json.Marshal(data)
 		if err != nil {
a4bcf7e1
 			return nil, -1, err
cf19be44
 		}
a4bcf7e1
 		params = bytes.NewBuffer(buf)
1aa7f139
 	}
0b6c79b3
 
3adf9ce0
 	req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), params)
1aa7f139
 	if err != nil {
a4bcf7e1
 		return nil, -1, err
1aa7f139
 	}
7c7619ec
 	req.Header.Set("User-Agent", "Docker-Client/"+VERSION)
cf19be44
 	if data != nil {
 		req.Header.Set("Content-Type", "application/json")
a4bcf7e1
 	} else if method == "POST" {
 		req.Header.Set("Content-Type", "plain/text")
1aa7f139
 	}
3adf9ce0
 	dial, err := net.Dial(cli.proto, cli.addr)
 	if err != nil {
 		return nil, -1, err
 	}
 	clientconn := httputil.NewClientConn(dial, nil)
 	resp, err := clientconn.Do(req)
 	defer clientconn.Close()
a4bcf7e1
 	if err != nil {
7c7619ec
 		if strings.Contains(err.Error(), "connection refused") {
 			return nil, -1, fmt.Errorf("Can't connect to docker daemon. Is 'docker -d' running on this host?")
 		}
a4bcf7e1
 		return nil, -1, err
 	}
 	defer resp.Body.Close()
 	body, err := ioutil.ReadAll(resp.Body)
 	if err != nil {
 		return nil, -1, err
 	}
0862183c
 	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
ab0d0a28
 		if len(body) == 0 {
 			return nil, resp.StatusCode, fmt.Errorf("Error: %s", http.StatusText(resp.StatusCode))
 		}
 		return nil, resp.StatusCode, fmt.Errorf("Error: %s", body)
e1b25e9b
 	}
a4bcf7e1
 	return body, resp.StatusCode, nil
 }
acb546cd
 
f29e5dc8
 func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) error {
 	if (method == "POST" || method == "PUT") && in == nil {
 		in = bytes.NewReader([]byte{})
 	}
3adf9ce0
 	req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), in)
93dc2c33
 	if err != nil {
 		return err
 	}
 	req.Header.Set("User-Agent", "Docker-Client/"+VERSION)
 	if method == "POST" {
 		req.Header.Set("Content-Type", "plain/text")
 	}
3adf9ce0
 	dial, err := net.Dial(cli.proto, cli.addr)
 	if err != nil {
 		return err
 	}
 	clientconn := httputil.NewClientConn(dial, nil)
 	resp, err := clientconn.Do(req)
 	defer clientconn.Close()
93dc2c33
 	if err != nil {
 		if strings.Contains(err.Error(), "connection refused") {
 			return fmt.Errorf("Can't connect to docker daemon. Is 'docker -d' running on this host?")
 		}
 		return err
 	}
 	defer resp.Body.Close()
8b31d306
 	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
 		body, err := ioutil.ReadAll(resp.Body)
 		if err != nil {
 			return err
 		}
ab0d0a28
 		if len(body) == 0 {
 			return fmt.Errorf("Error :%s", http.StatusText(resp.StatusCode))
 		}
 		return fmt.Errorf("Error: %s", body)
8b31d306
 	}
 
cf35e8ed
 	if resp.Header.Get("Content-Type") == "application/json" {
 		dec := json.NewDecoder(resp.Body)
 		for {
fd224ee5
 			var m utils.JSONMessage
cf35e8ed
 			if err := dec.Decode(&m); err == io.EOF {
 				break
 			} else if err != nil {
 				return err
 			}
3c7bca7a
 			if m.Progress != "" {
3922691f
 				fmt.Fprintf(out, "%s %s\r", m.Status, m.Progress)
cb0bc4ad
 			} else if m.Error != "" {
 				return fmt.Errorf(m.Error)
3c7bca7a
 			} else {
cf35e8ed
 				fmt.Fprintf(out, "%s\n", m.Status)
 			}
 		}
 	} else {
 		if _, err := io.Copy(out, resp.Body); err != nil {
 			return err
 		}
acb546cd
 	}
a19a9e3c
 	return nil
e1b25e9b
 }
 
c00d1a6e
 func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in *os.File, out io.Writer) error {
fd224ee5
 	req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), nil)
a4bcf7e1
 	if err != nil {
 		return err
f7837599
 	}
10c0e990
 	req.Header.Set("Content-Type", "plain/text")
3adf9ce0
 	dial, err := net.Dial(cli.proto, cli.addr)
e1b25e9b
 	if err != nil {
cf19be44
 		return err
1aa7f139
 	}
cf19be44
 	clientconn := httputil.NewClientConn(dial, nil)
75c0dc95
 	clientconn.Do(req)
cf19be44
 	defer clientconn.Close()
 
04cd20fa
 	rwc, br := clientconn.Hijack()
cf19be44
 	defer rwc.Close()
 
2e69e172
 	receiveStdout := utils.Go(func() error {
c00d1a6e
 		_, err := io.Copy(out, br)
04cd20fa
 		return err
 	})
 
31eb01ae
 	if in != nil && setRawTerminal && term.IsTerminal(in.Fd()) && os.Getenv("NORAW") == "" {
86ada2fa
 		oldState, err := term.SetRawTerminal()
 		if err != nil {
e5104a4c
 			return err
 		}
86ada2fa
 		defer term.RestoreTerminal(oldState)
e1b25e9b
 	}
2e69e172
 	sendStdin := utils.Go(func() error {
2eaa0a1d
 		io.Copy(rwc, in)
a5b765a7
 		if err := rwc.(*net.TCPConn).CloseWrite(); err != nil {
2eaa0a1d
 			utils.Debugf("Couldn't send EOF: %s\n", err)
a5b765a7
 		}
2eaa0a1d
 		// Discard errors due to pipe interruption
 		return nil
cf19be44
 	})
 
 	if err := <-receiveStdout; err != nil {
2eaa0a1d
 		utils.Debugf("Error receiveStdout: %s", err)
cf19be44
 		return err
e1b25e9b
 	}
1941c791
 
da54abaf
 	if !term.IsTerminal(in.Fd()) {
cf19be44
 		if err := <-sendStdin; err != nil {
2eaa0a1d
 			utils.Debugf("Error sendStdin: %s", err)
cf19be44
 			return err
 		}
 	}
 	return nil
e1b25e9b
 
 }
 
88ef309a
 func (cli *DockerCli) resizeTty(id string) {
 	ws, err := term.GetWinsize(os.Stdin.Fd())
 	if err != nil {
 		utils.Debugf("Error getting size: %s", err)
 	}
 	v := url.Values{}
 	v.Set("h", strconv.Itoa(int(ws.Height)))
 	v.Set("w", strconv.Itoa(int(ws.Width)))
 	if _, _, err := cli.call("POST", "/containers/"+id+"/resize?"+v.Encode(), nil); err != nil {
 		utils.Debugf("Error resize: %s", err)
 	}
 }
 
 func (cli *DockerCli) monitorTtySize(id string) {
 	cli.resizeTty(id)
 
 	c := make(chan os.Signal, 1)
 	signal.Notify(c, syscall.SIGWINCH)
 	go func() {
 		for sig := range c {
 			if sig == syscall.SIGWINCH {
 				cli.resizeTty(id)
 			}
 		}
 	}()
 }
 
1aa7f139
 func Subcmd(name, signature, description string) *flag.FlagSet {
 	flags := flag.NewFlagSet(name, flag.ContinueOnError)
 	flags.Usage = func() {
 		fmt.Printf("\nUsage: docker %s %s\n\n%s\n\n", name, signature, description)
 		flags.PrintDefaults()
 	}
 	return flags
e1b25e9b
 }
76173121
 
3adf9ce0
 func NewDockerCli(proto, addr string) *DockerCli {
49e65683
 	authConfig, _ := auth.LoadConfig(os.Getenv("HOME"))
3adf9ce0
 	return &DockerCli{proto, addr, authConfig}
76173121
 }
 
f2741554
 type DockerCli struct {
3adf9ce0
 	proto      string
 	addr       string
49e65683
 	authConfig *auth.AuthConfig
76173121
 }