Merge pull request #1227 from dotcloud/bump_0.5.0

Bump to 0.5.0
diff --git a/api.go b/api.go
index 25dea19..b6ab7ba 100644
--- a/api.go
+++ b/api.go
@@ -774,6 +774,7 @@
 	}
 	remoteURL := r.FormValue("remote")
 	repoName := r.FormValue("t")
+	rawSuppressOutput := r.FormValue("q")
 	tag := ""
 	if strings.Contains(repoName, ":") {
 		remoteParts := strings.Split(repoName, ":")
@@ -820,7 +821,13 @@
 		}
 		context = c
 	}
-	b := NewBuildFile(srv, utils.NewWriteFlusher(w))
+
+	suppressOutput, err := getBoolParam(rawSuppressOutput)
+	if err != nil {
+		return err
+	}
+
+	b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput)
 	id, err := b.Build(context)
 	if err != nil {
 		fmt.Fprintf(w, "Error build: %s\n", err)
diff --git a/buildfile.go b/buildfile.go
index 38e6c33..7ade058 100644
--- a/buildfile.go
+++ b/buildfile.go
@@ -28,8 +28,8 @@
 	maintainer string
 	config     *Config
 	context    string
+	verbose    bool
 
-	lastContainer *Container
 	tmpContainers map[string]struct{}
 	tmpImages     map[string]struct{}
 
@@ -254,7 +254,6 @@
 		return err
 	}
 	b.tmpContainers[container.ID] = struct{}{}
-	b.lastContainer = container
 
 	if err := container.EnsureMounted(); err != nil {
 		return err
@@ -290,7 +289,6 @@
 		return "", err
 	}
 	b.tmpContainers[c.ID] = struct{}{}
-	b.lastContainer = c
 	fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID))
 
 	// override the entry point that may have been picked up from the base image
@@ -303,6 +301,13 @@
 		return "", err
 	}
 
+	if b.verbose {
+		err = <-c.Attach(nil, nil, b.out, b.out)
+		if err != nil {
+			return "", err
+		}
+	}
+
 	// Wait for it to finish
 	if ret := c.Wait(); ret != 0 {
 		return "", fmt.Errorf("The command %v returned a non-zero code: %d", b.config.Cmd, ret)
@@ -337,7 +342,6 @@
 			return err
 		}
 		b.tmpContainers[container.ID] = struct{}{}
-		b.lastContainer = container
 		fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(container.ID))
 		id = container.ID
 		if err := container.EnsureMounted(); err != nil {
@@ -365,29 +369,6 @@
 }
 
 func (b *buildFile) Build(context io.Reader) (string, error) {
-	defer func() {
-		// If we have an error and a container, the display the logs
-		if b.lastContainer != nil {
-			fmt.Fprintf(b.out, "******** Logs from last container (%s) *******\n", b.lastContainer.ShortID())
-
-			cLog, err := b.lastContainer.ReadLog("stdout")
-			if err != nil {
-				utils.Debugf("Error reading logs (stdout): %s", err)
-			}
-			if _, err := io.Copy(b.out, cLog); err != nil {
-				utils.Debugf("Error streaming logs (stdout): %s", err)
-			}
-			cLog, err = b.lastContainer.ReadLog("stderr")
-			if err != nil {
-				utils.Debugf("Error reading logs (stderr): %s", err)
-			}
-			if _, err := io.Copy(b.out, cLog); err != nil {
-				utils.Debugf("Error streaming logs (stderr): %s", err)
-			}
-			fmt.Fprintf(b.out, "************* End of logs for %s *************\n", b.lastContainer.ShortID())
-		}
-	}()
-
 	// FIXME: @creack any reason for using /tmp instead of ""?
 	// FIXME: @creack "name" is a terrible variable name
 	name, err := ioutil.TempDir("/tmp", "docker-build")
@@ -440,7 +421,6 @@
 			return "", ret.(error)
 		}
 
-		b.lastContainer = nil
 		fmt.Fprintf(b.out, " ---> %v\n", utils.TruncateID(b.image))
 	}
 	if b.image != "" {
@@ -450,7 +430,7 @@
 	return "", fmt.Errorf("An error occured during the build\n")
 }
 
-func NewBuildFile(srv *Server, out io.Writer) BuildFile {
+func NewBuildFile(srv *Server, out io.Writer, verbose bool) BuildFile {
 	return &buildFile{
 		builder:       NewBuilder(srv.runtime),
 		runtime:       srv.runtime,
@@ -459,5 +439,6 @@
 		out:           out,
 		tmpContainers: make(map[string]struct{}),
 		tmpImages:     make(map[string]struct{}),
+		verbose:       verbose,
 	}
 }
diff --git a/buildfile_test.go b/buildfile_test.go
index b85a62c..14edbc0 100644
--- a/buildfile_test.go
+++ b/buildfile_test.go
@@ -105,23 +105,11 @@
 
 func TestBuild(t *testing.T) {
 	for _, ctx := range testContexts {
-		runtime := mkRuntime(t)
-		defer nuke(runtime)
-
-		srv := &Server{
-			runtime:     runtime,
-			pullingPool: make(map[string]struct{}),
-			pushingPool: make(map[string]struct{}),
-		}
-
-		buildfile := NewBuildFile(srv, ioutil.Discard)
-		if _, err := buildfile.Build(mkTestContext(ctx.dockerfile, ctx.files, t)); err != nil {
-			t.Fatal(err)
-		}
+		buildImage(ctx, t)
 	}
 }
 
-func TestVolume(t *testing.T) {
+func buildImage(context testContextTemplate, t *testing.T) *Image {
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
@@ -133,26 +121,96 @@
 		pullingPool: make(map[string]struct{}),
 		pushingPool: make(map[string]struct{}),
 	}
+	buildfile := NewBuildFile(srv, ioutil.Discard, false)
 
-	buildfile := NewBuildFile(srv, ioutil.Discard)
-	imgId, err := buildfile.Build(mkTestContext(`
-from %s
-VOLUME /test
-CMD Hello world
-`, nil, t))
+	id, err := buildfile.Build(mkTestContext(context.dockerfile, context.files, t))
 	if err != nil {
 		t.Fatal(err)
 	}
-	img, err := srv.ImageInspect(imgId)
+
+	img, err := srv.ImageInspect(id)
 	if err != nil {
 		t.Fatal(err)
 	}
+	return img
+}
+
+func TestVolume(t *testing.T) {
+	img := buildImage(testContextTemplate{`
+        from %s
+        volume /test
+        cmd Hello world
+    `, nil}, t)
+
 	if len(img.Config.Volumes) == 0 {
 		t.Fail()
 	}
-	for key, _ := range img.Config.Volumes {
+	for key := range img.Config.Volumes {
 		if key != "/test" {
 			t.Fail()
 		}
 	}
 }
+
+func TestBuildMaintainer(t *testing.T) {
+	img := buildImage(testContextTemplate{`
+        from %s
+        maintainer dockerio
+    `, nil}, t)
+
+	if img.Author != "dockerio" {
+		t.Fail()
+	}
+}
+
+func TestBuildEnv(t *testing.T) {
+	img := buildImage(testContextTemplate{`
+        from %s
+        env port 4243
+        `,
+		nil}, t)
+
+	if img.Config.Env[0] != "port=4243" {
+		t.Fail()
+	}
+}
+
+func TestBuildCmd(t *testing.T) {
+	img := buildImage(testContextTemplate{`
+        from %s
+        cmd ["/bin/echo", "Hello World"]
+        `,
+		nil}, t)
+
+	if img.Config.Cmd[0] != "/bin/echo" {
+		t.Log(img.Config.Cmd[0])
+		t.Fail()
+	}
+	if img.Config.Cmd[1] != "Hello World" {
+		t.Log(img.Config.Cmd[1])
+		t.Fail()
+	}
+}
+
+func TestBuildExpose(t *testing.T) {
+	img := buildImage(testContextTemplate{`
+        from %s
+        expose 4243
+        `,
+		nil}, t)
+
+	if img.Config.PortSpecs[0] != "4243" {
+		t.Fail()
+	}
+}
+
+func TestBuildEntrypoint(t *testing.T) {
+	img := buildImage(testContextTemplate{`
+        from %s
+        entrypoint ["/bin/echo"]
+        `,
+		nil}, t)
+
+	if img.Config.Entrypoint[0] != "/bin/echo" {
+	}
+}
diff --git a/commands.go b/commands.go
index d814197..f78effe 100644
--- a/commands.go
+++ b/commands.go
@@ -94,8 +94,8 @@
 		{"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"},
+		{"rm", "Remove one or more containers"},
+		{"rmi", "Remove one or more images"},
 		{"run", "Run a command in a new container"},
 		{"search", "Search for an image in the docker index"},
 		{"start", "Start a stopped container"},
@@ -158,6 +158,8 @@
 func (cli *DockerCli) CmdBuild(args ...string) error {
 	cmd := Subcmd("build", "[OPTIONS] PATH | URL | -", "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")
+	suppressOutput := cmd.Bool("q", false, "Suppress verbose build output")
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
@@ -195,6 +197,10 @@
 	// Upload the build context
 	v := &url.Values{}
 	v.Set("t", *tag)
+
+	if *suppressOutput {
+		v.Set("q", "1")
+	}
 	if isRemote {
 		v.Set("remote", cmd.Arg(0))
 	}
@@ -469,7 +475,7 @@
 
 func (cli *DockerCli) CmdStop(args ...string) error {
 	cmd := Subcmd("stop", "[OPTIONS] CONTAINER [CONTAINER...]", "Stop a running container")
-	nSeconds := cmd.Int("t", 10, "wait t seconds before killing the container")
+	nSeconds := cmd.Int("t", 10, "Number of seconds to try to stop for before killing the container. Default=10")
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
@@ -494,7 +500,7 @@
 
 func (cli *DockerCli) CmdRestart(args ...string) error {
 	cmd := Subcmd("restart", "[OPTIONS] CONTAINER [CONTAINER...]", "Restart a running container")
-	nSeconds := cmd.Int("t", 10, "wait t seconds before killing the container")
+	nSeconds := cmd.Int("t", 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default=10")
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
@@ -638,7 +644,7 @@
 
 // 'docker rmi IMAGE' removes all images with the name IMAGE
 func (cli *DockerCli) CmdRmi(args ...string) error {
-	cmd := Subcmd("rmi", "IMAGE [IMAGE...]", "Remove an image")
+	cmd := Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images")
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
@@ -703,7 +709,7 @@
 }
 
 func (cli *DockerCli) CmdRm(args ...string) error {
-	cmd := Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove a container")
+	cmd := Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove one or more containers")
 	v := cmd.Bool("v", false, "Remove the volumes associated to the container")
 	if err := cmd.Parse(args); err != nil {
 		return nil
@@ -773,7 +779,7 @@
 }
 
 func (cli *DockerCli) CmdPush(args ...string) error {
-	cmd := Subcmd("push", "[OPTION] NAME", "Push an image or a repository to the registry")
+	cmd := Subcmd("push", "NAME", "Push an image or a repository to the registry")
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
@@ -1249,10 +1255,22 @@
 }
 
 func (opts PathOpts) Set(val string) error {
-	if !filepath.IsAbs(val) {
-		return fmt.Errorf("%s is not an absolute path", val)
+	var containerPath string
+
+	splited := strings.SplitN(val, ":", 2)
+	if len(splited) == 1 {
+		containerPath = splited[0]
+		val = filepath.Clean(splited[0])
+	} else {
+		containerPath = splited[1]
+		val = fmt.Sprintf("%s:%s", splited[0], filepath.Clean(splited[1]))
 	}
-	opts[filepath.Clean(val)] = struct{}{}
+
+	if !filepath.IsAbs(containerPath) {
+		utils.Debugf("%s is not an absolute path", containerPath)
+		return fmt.Errorf("%s is not an absolute path", containerPath)
+	}
+	opts[val] = struct{}{}
 	return nil
 }
 
diff --git a/container.go b/container.go
index c714e9f..3772cf2 100644
--- a/container.go
+++ b/container.go
@@ -121,14 +121,11 @@
 	cmd.Var(&flDns, "dns", "Set custom dns servers")
 
 	flVolumes := NewPathOpts()
-	cmd.Var(flVolumes, "v", "Attach a data volume")
+	cmd.Var(flVolumes, "v", "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
 
 	flVolumesFrom := cmd.String("volumes-from", "", "Mount volumes from the specified container")
 	flEntrypoint := cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image")
 
-	var flBinds ListOpts
-	cmd.Var(&flBinds, "b", "Bind mount a volume from the host (e.g. -b /host:/container)")
-
 	if err := cmd.Parse(args); err != nil {
 		return nil, nil, cmd, err
 	}
@@ -146,11 +143,17 @@
 		}
 	}
 
+	var binds []string
+
 	// add any bind targets to the list of container volumes
-	for _, bind := range flBinds {
+	for bind := range flVolumes {
 		arr := strings.Split(bind, ":")
-		dstDir := arr[1]
-		flVolumes[dstDir] = struct{}{}
+		if len(arr) > 1 {
+			dstDir := arr[1]
+			flVolumes[dstDir] = struct{}{}
+			binds = append(binds, bind)
+			delete(flVolumes, bind)
+		}
 	}
 
 	parsedArgs := cmd.Args()
@@ -187,7 +190,7 @@
 		Entrypoint:   entrypoint,
 	}
 	hostConfig := &HostConfig{
-		Binds: flBinds,
+		Binds: binds,
 	}
 
 	if capabilities != nil && *flMemory > 0 && !capabilities.SwapLimit {
@@ -493,6 +496,7 @@
 func (container *Container) Start(hostConfig *HostConfig) error {
 	container.State.Lock()
 	defer container.State.Unlock()
+
 	if len(hostConfig.Binds) == 0 {
 		hostConfig, _ = container.ReadHostConfig()
 	}
diff --git a/container_test.go b/container_test.go
index f431c7d..6e82dd5 100644
--- a/container_test.go
+++ b/container_test.go
@@ -1231,19 +1231,18 @@
 	writeFile(path.Join(tmpDir, "touch-me"), "", t)
 
 	// Test reading from a read-only bind mount
-	stdout, _ := runContainer(r, []string{"-b", fmt.Sprintf("%s:/tmp:ro", tmpDir), "_", "ls", "/tmp"}, t)
+	stdout, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/tmp:ro", tmpDir), "_", "ls", "/tmp"}, t)
 	if !strings.Contains(stdout, "touch-me") {
 		t.Fatal("Container failed to read from bind mount")
 	}
 
 	// test writing to bind mount
-	runContainer(r, []string{"-b", fmt.Sprintf("%s:/tmp:rw", tmpDir), "_", "touch", "/tmp/holla"}, t)
+	runContainer(r, []string{"-v", fmt.Sprintf("%s:/tmp:rw", tmpDir), "_", "touch", "/tmp/holla"}, t)
 	readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist
 
 	// test mounting to an illegal destination directory
-	if _, err := runContainer(r, []string{"-b", fmt.Sprintf("%s:.", tmpDir), "ls", "."}, nil); err == nil {
+	if _, err := runContainer(r, []string{"-v", fmt.Sprintf("%s:.", tmpDir), "ls", "."}, nil); err == nil {
 		t.Fatal("Container bind mounted illegal directory")
-
 	}
 }
 
diff --git a/docs/sources/api/docker_remote_api_v1.3.rst b/docs/sources/api/docker_remote_api_v1.3.rst
index 6542c83..9f33365 100644
--- a/docs/sources/api/docker_remote_api_v1.3.rst
+++ b/docs/sources/api/docker_remote_api_v1.3.rst
@@ -921,6 +921,7 @@
         The Content-type header should be set to "application/tar".
 
 	:query t: tag to be applied to the resulting image in case of success
+	:query q: suppress verbose build output
 	:statuscode 200: no error
         :statuscode 500: server error
 
diff --git a/docs/sources/commandline/command/build.rst b/docs/sources/commandline/command/build.rst
index 1645002..45b6d2e 100644
--- a/docs/sources/commandline/command/build.rst
+++ b/docs/sources/commandline/command/build.rst
@@ -11,6 +11,7 @@
     Usage: docker build [OPTIONS] PATH | URL | -
     Build a new container image from the source code at PATH
       -t="": Tag to be applied to the resulting image in case of success.
+      -q=false: Suppress verbose build output.
     When a single Dockerfile is given as URL, then no context is set. When a git repository is set as URL, the repository is used as context
 
 
diff --git a/docs/sources/commandline/command/rm.rst b/docs/sources/commandline/command/rm.rst
index dc6d916..8a2309c 100644
--- a/docs/sources/commandline/command/rm.rst
+++ b/docs/sources/commandline/command/rm.rst
@@ -10,4 +10,4 @@
 
     Usage: docker rm [OPTIONS] CONTAINER
 
-    Remove a container
+    Remove one or more containers
diff --git a/docs/sources/commandline/command/rmi.rst b/docs/sources/commandline/command/rmi.rst
index a013188..954e522 100644
--- a/docs/sources/commandline/command/rmi.rst
+++ b/docs/sources/commandline/command/rmi.rst
@@ -8,6 +8,6 @@
 
 ::
 
-    Usage: docker rmimage [OPTIONS] IMAGE
+    Usage: docker rmi IMAGE [IMAGE...]
 
-    Remove an image
+    Remove one or more images
diff --git a/docs/sources/commandline/command/run.rst b/docs/sources/commandline/command/run.rst
index 4529013..1a14a9b 100644
--- a/docs/sources/commandline/command/run.rst
+++ b/docs/sources/commandline/command/run.rst
@@ -23,7 +23,6 @@
       -t=false: Allocate a pseudo-tty
       -u="": Username or UID
       -d=[]: Set custom dns servers for the container
-      -v=[]: Creates a new volume and mounts it at the specified path.
+      -v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. If "host-dir" is missing, then docker creates a new volume.
       -volumes-from="": Mount all volumes from the given container.
-      -b=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]
       -entrypoint="": Overwrite the default entrypoint set by the image.
diff --git a/docs/sources/use/builder.rst b/docs/sources/use/builder.rst
index ceda9c9..9ea8033 100644
--- a/docs/sources/use/builder.rst
+++ b/docs/sources/use/builder.rst
@@ -1,25 +1,27 @@
-:title: Docker Builder
+:title: Dockerfile Builder
 :description: Docker Builder specifes a simple DSL which allows you to automate the steps you would normally manually take to create an image.
 :keywords: builder, docker, Docker Builder, automation, image creation
 
-==============
-Docker Builder
-==============
+==================
+Dockerfile Builder
+==================
+
+**Docker can act as a builder** and read instructions from a text
+Dockerfile to automate the steps you would otherwise make manually to
+create an image. Executing ``docker build`` will run your steps and
+commit them along the way, giving you a final image.
 
 .. contents:: Table of Contents
 
-Docker Builder specifes a simple DSL which allows you to automate the steps you
-would normally manually take to create an image. Docker Build will run your 
-steps and commit them along the way, giving you a final image.
-
 1. Usage
 ========
 
-To build an image from a source repository, create a description file called `Dockerfile`
-at the root of your repository. This file will describe the steps to assemble
-the image.
+To build an image from a source repository, create a description file
+called ``Dockerfile`` at the root of your repository. This file will
+describe the steps to assemble the image.
 
-Then call `docker build` with the path of your source repository as argument:
+Then call ``docker build`` with the path of your source repository as
+argument:
 
     ``docker build .``
 
@@ -36,136 +38,162 @@
 
 The Dockerfile format is quite simple:
 
-    ``instruction arguments``
+::
+
+    # Comment
+    INSTRUCTION arguments
 
 The Instruction is not case-sensitive, however convention is for them to be 
 UPPERCASE in order to distinguish them from arguments more easily.
 
-Dockerfiles are evaluated in order, therefore the first instruction must be 
-`FROM` in order to specify the base image from which you are building.
+Docker evaluates the instructions in a Dockerfile in order. **The first
+instruction must be `FROM`** in order to specify the base image from
+which you are building.
 
-Docker will ignore lines in Dockerfiles prefixed with "`#`", so you may add 
-comment lines. A comment marker in the rest of the line will be treated as an
-argument.
+Docker will ignore **comment lines** *beginning* with ``#``. A comment
+marker anywhere in the rest of the line will be treated as an argument.
 
 3. Instructions
 ===============
 
-Docker builder comes with a set of instructions, described below.
+Here is the set of instructions you can use in a ``Dockerfile`` for
+building images.
 
 3.1 FROM
 --------
 
     ``FROM <image>``
 
-The `FROM` instruction sets the base image for subsequent instructions. As such,
-a valid Dockerfile must have it as its first instruction.
+The ``FROM`` instruction sets the :ref:`base_image_def` for subsequent
+instructions. As such, a valid Dockerfile must have ``FROM`` as its
+first instruction.
 
-`FROM` can be included multiple times within a single Dockerfile in order to 
-create multiple images. Simply make a note of the last image id output by the 
-commit before each new `FROM` command.
+``FROM`` must be the first non-comment instruction in the
+``Dockerfile``.
+
+``FROM`` can appear multiple times within a single Dockerfile in order
+to create multiple images. Simply make a note of the last image id
+output by the commit before each new ``FROM`` command.
 
 3.2 MAINTAINER
 --------------
 
     ``MAINTAINER <name>``
 
-The `MAINTAINER` instruction allows you to set the Author field of the generated 
-images.
+The ``MAINTAINER`` instruction allows you to set the *Author* field of
+the generated images.
 
 3.3 RUN
 -------
 
     ``RUN <command>``
 
-The `RUN` instruction will execute any commands on the current image and commit
-the results. The resulting committed image will be used for the next step in the
-Dockerfile.
+The ``RUN`` instruction will execute any commands on the current image
+and commit the results. The resulting committed image will be used for
+the next step in the Dockerfile.
 
-Layering `RUN` instructions and generating commits conforms to the
-core concepts of Docker where commits are cheap and containers can be created
-from any point in an image's history, much like source control.
+Layering ``RUN`` instructions and generating commits conforms to the
+core concepts of Docker where commits are cheap and containers can be
+created from any point in an image's history, much like source
+control.
 
 3.4 CMD
 -------
 
     ``CMD <command>``
 
-The `CMD` instruction sets the command to be executed when running the image.
-This is functionally equivalent to running 
-`docker commit -run '{"Cmd": <command>}'` outside the builder.
+The ``CMD`` instruction sets the command to be executed when running
+the image.  This is functionally equivalent to running ``docker commit
+-run '{"Cmd": <command>}'`` outside the builder.
 
-.. note::
-    Don't confuse `RUN` with `CMD`. `RUN` actually runs a command and commits 
-    the result; `CMD` does not execute anything at build time, but specifies the
-    intended command for the image.
+.. note:: 
+    Don't confuse `RUN` with `CMD`. `RUN` actually runs a
+    command and commits the result; `CMD` does not execute anything at
+    build time, but specifies the intended command for the image.
 
 3.5 EXPOSE
 ----------
 
     ``EXPOSE <port> [<port>...]``
 
-The `EXPOSE` instruction sets ports to be publicly exposed when running the 
-image. This is functionally equivalent to running 
-`docker commit -run '{"PortSpecs": ["<port>", "<port2>"]}'` outside the builder.
+The ``EXPOSE`` instruction sets ports to be publicly exposed when
+running the image. This is functionally equivalent to running ``docker
+commit -run '{"PortSpecs": ["<port>", "<port2>"]}'`` outside the
+builder.
 
 3.6 ENV
 -------
 
     ``ENV <key> <value>``
 
-The `ENV` instruction sets the environment variable `<key>` to the value 
-`<value>`. This value will be passed to all future ``RUN`` instructions. This is
-functionally equivalent to prefixing the command with `<key>=<value>`
+The ``ENV`` instruction sets the environment variable ``<key>`` to the
+value ``<value>``. This value will be passed to all future ``RUN``
+instructions. This is functionally equivalent to prefixing the command
+with ``<key>=<value>``
 
-.. note::
-    The environment variables will persist when a container is run from the resulting image.
+.. note:: 
+    The environment variables will persist when a container is run
+    from the resulting image.
 
 3.7 ADD
 -------
 
     ``ADD <src> <dest>``
 
-The `ADD` instruction will copy new files from <src> and add them to the container's filesystem at path `<dest>`.
+The ``ADD`` instruction will copy new files from <src> and add them to
+the container's filesystem at path ``<dest>``.
 
-`<src>` must be the path to a file or directory relative to the source directory being built (also called the
-context of the build) or a remote file URL.
+``<src>`` must be the path to a file or directory relative to the
+source directory being built (also called the *context* of the build) or
+a remote file URL.
 
-`<dest>` is the path at which the source will be copied in the destination container.
+``<dest>`` is the path at which the source will be copied in the
+destination container.
 
 The copy obeys the following rules:
 
-If `<src>` is a directory, the entire directory is copied, including filesystem metadata.
+* If ``<src>`` is a directory, the entire directory is copied,
+  including filesystem metadata.
+* If ``<src>``` is a tar archive in a recognized compression format
+  (identity, gzip, bzip2 or xz), it is unpacked as a directory.
 
-If `<src>` is a tar archive in a recognized compression format (identity, gzip, bzip2 or xz), it
-is unpacked as a directory.
+  When a directory is copied or unpacked, it has the same behavior as
+  ``tar -x``: the result is the union of 
 
-When a directory is copied or unpacked, it has the same behavior as 'tar -x': the result is the union of
-a) whatever existed at the destination path and b) the contents of the source tree, with conflicts resolved
-in favor of b on a file-by-file basis.
+  1. whatever existed at the destination path and
+  2. the contents of the source tree, 
 
-If `<src>` is any other kind of file, it is copied individually along with its metadata. In this case,
-if `<dst>` ends with a trailing slash '/', it will be considered a directory and the contents of `<src>`
-will be written at `<dst>/base(<src>)`.
-If `<dst>` does not end with a trailing slash, it will be considered a regular file and the contents
-of `<src>` will be written at `<dst>`.
+  with conflicts resolved in favor of 2) on a file-by-file basis.
 
-If `<dest>` doesn't exist, it is created along with all missing directories in its path. All new
-files and directories are created with mode 0700, uid and gid 0.
+* If ``<src>`` is any other kind of file, it is copied individually
+  along with its metadata. In this case, if ``<dst>`` ends with a
+  trailing slash ``/``, it will be considered a directory and the
+  contents of ``<src>`` will be written at ``<dst>/base(<src>)``.
+* If ``<dst>`` does not end with a trailing slash, it will be
+  considered a regular file and the contents of ``<src>`` will be
+  written at ``<dst>``.
+* If ``<dest>`` doesn't exist, it is created along with all missing
+  directories in its path. All new files and directories are created
+  with mode 0700, uid and gid 0.
 
 3.8 ENTRYPOINT
 -------------
 
     ``ENTRYPOINT /bin/echo``
 
-The `ENTRYPOINT` instruction adds an entry command that will not be overwritten when arguments are passed to docker run, unlike the behavior of `CMD`.  This allows arguments to be passed to the entrypoint.  i.e. `docker run <image> -d` will pass the "-d" argument to the entrypoint.
+The ``ENTRYPOINT`` instruction adds an entry command that will not be
+overwritten when arguments are passed to docker run, unlike the
+behavior of ``CMD``.  This allows arguments to be passed to the
+entrypoint.  i.e. ``docker run <image> -d`` will pass the "-d" argument
+to the entrypoint.
 
 3.9 VOLUME
 ----------
 
     ``VOLUME ["/data"]``
 
-The `VOLUME` instruction will add one or more new volumes to any container created from the image.
+The ``VOLUME`` instruction will add one or more new volumes to any
+container created from the image.
 
 4. Dockerfile Examples
 ======================
diff --git a/docs/sources/use/workingwithrepository.rst b/docs/sources/use/workingwithrepository.rst
index 243c99a..3cdbfe4 100644
--- a/docs/sources/use/workingwithrepository.rst
+++ b/docs/sources/use/workingwithrepository.rst
@@ -7,21 +7,69 @@
 Working with Repositories
 =========================
 
+A *repository* is a hosted collection of tagged :ref:`images
+<image_def>` that together create the file system for a container. The
+repository's name is a tag that indicates the provenance of the
+repository, i.e. who created it and where the original copy is
+located.
 
-Top-level repositories and user repositories
---------------------------------------------
+You can find one or more repositories hosted on a *registry*. There
+can be an implicit or explicit host name as part of the repository
+tag. The implicit registry is located at ``index.docker.io``, the home
+of "top-level" repositories and the Central Index. This registry may
+also include public "user" repositories.
 
-Generally, there are two types of repositories: Top-level repositories
-which are controlled by the people behind Docker, and user
-repositories.
+So Docker is not only a tool for creating and managing your own
+:ref:`containers <container_def>` -- **Docker is also a tool for
+sharing**. The Docker project provides a Central Registry to host
+public repositories, namespaced by user, and a Central Index which
+provides user authentication and search over all the public
+repositories. You can host your own Registry too! Docker acts as a
+client for these services via ``docker search, pull, login`` and
+``push``.
 
-* Top-level repositories can easily be recognized by not having a ``/`` (slash) in their name. These repositories can  generally be trusted.
-* User repositories always come in the form of ``<username>/<repo_name>``. This is what your published images will look like.
-* User images are not checked, it is therefore up to you whether or not you trust the creator of this image.
+Top-level, User, and Your Own Repositories
+------------------------------------------
 
+There are two types of public repositories: *top-level* repositories
+which are controlled by the Docker team, and *user* repositories
+created by individual contributors.
 
-Find public images available on the index
------------------------------------------
+* Top-level repositories can easily be recognized by **not** having a
+  ``/`` (slash) in their name. These repositories can generally be
+  trusted.
+* User repositories always come in the form of
+  ``<username>/<repo_name>``. This is what your published images will
+  look like if you push to the public Central Registry.
+* Only the authenticated user can push to their *username* namespace
+  on the Central Registry.
+* User images are not checked, it is therefore up to you whether or
+  not you trust the creator of this image.
+
+Right now (version 0.5), private repositories are only possible by
+hosting `your own registry
+<https://github.com/dotcloud/docker-registry>`_.  To push or pull to a
+repository on your own registry, you must prefix the tag with the
+address of the registry's host, like this:
+
+.. code-block:: bash
+
+    # Tag to create a repository with the full registry location.
+    # The location (e.g. localhost.localdomain:5000) becomes
+    # a permanent part of the repository name
+    docker tag 0u812deadbeef localhost.localdomain:5000/repo_name
+
+    # Push the new repository to its home location on localhost
+    docker push localhost.localdomain:5000/repo_name
+
+Once a repository has your registry's host name as part of the tag,
+you can push and pull it like any other repository, but it will
+**not** be searchable (or indexed at all) in the Central Index, and
+there will be no user name checking performed. Your registry will
+function completely independently from the Central Index.
+
+Find public images available on the Central Index
+-------------------------------------------------
 
 Seach by name, namespace or description
 
@@ -37,68 +85,48 @@
     docker pull <value>
 
 
-Very similarly you can search for and browse the index online on https://index.docker.io
+Very similarly you can search for and browse the index online on
+https://index.docker.io
 
 
-Connecting to the repository
-----------------------------
+Connecting to the Central Registry
+----------------------------------
 
-You can create a user on the central docker repository online, or by running
+You can create a user on the central Docker Index online, or by running
 
 .. code-block:: bash
 
     docker login
 
+This will prompt you for a username, which will become a public
+namespace for your public repositories.
 
-If your username does not exist it will prompt you to also enter a password and your e-mail address. It will then
-automatically log you in.
+If your username does not exist it will prompt you to also enter a
+password and your e-mail address. It will then automatically log you
+in.
 
 
 Committing a container to a named image
 ---------------------------------------
 
-In order to commit to the repository it is required to have committed your container to an image with your namespace.
+In order to commit to the repository it is required to have committed
+your container to an image within your username namespace.
 
 .. code-block:: bash
 
     # for example docker commit $CONTAINER_ID dhrp/kickassapp
-    docker commit <container_id> <your username>/<some_name>
+    docker commit <container_id> <username>/<repo_name>
 
 
-Pushing a container to the repository
------------------------------------------
+Pushing a container to its repository
+------------------------------------
 
-In order to push an image to the repository you need to have committed your container to a named image (see above)
+In order to push an image to its repository you need to have committed
+your container to a named image (see above)
 
 Now you can commit this image to the repository
 
 .. code-block:: bash
 
     # for example docker push dhrp/kickassapp
-    docker push <image-name>
-
-
-Changing the server to connect to
-----------------------------------
-
-When you are running your own index and/or registry, You can change the server the docker client will connect to.
-
-Variable
-^^^^^^^^
-
-.. code-block:: sh
-
-    DOCKER_INDEX_URL
-
-Setting this environment variable on the docker server will change the URL docker index.
-This address is used in commands such as ``docker login``, ``docker push`` and ``docker pull``.
-The docker daemon doesn't need to be restarted for this parameter to take effect.
-
-Example
-^^^^^^^
-
-.. code-block:: sh
-
-    docker -d &
-    export DOCKER_INDEX_URL="https://index.docker.io"
-
+    docker push <username>/<repo_name>
diff --git a/network_proxy.go b/network_proxy.go
index 905773e..fb91cc1 100644
--- a/network_proxy.go
+++ b/network_proxy.go
@@ -68,6 +68,7 @@
 				from.CloseWrite()
 			}
 		}
+		to.CloseRead()
 		event <- written
 	}
 	utils.Debugf("Forwarding traffic between tcp/%v and tcp/%v", client.RemoteAddr(), backend.RemoteAddr())
diff --git a/server.go b/server.go
index c43cae0..954bbb2 100644
--- a/server.go
+++ b/server.go
@@ -870,7 +870,6 @@
 	if len(srv.runtime.repositories.ByID()[id]) != 0 {
 		return ErrImageReferenced
 	}
-
 	// If the image is not referenced but has children, go recursive
 	referenced := false
 	byParents, err := srv.runtime.graph.ByParent()
@@ -924,8 +923,22 @@
 }
 
 func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, error) {
-	//Untag the current image
 	imgs := []APIRmi{}
+
+	//If delete by id, see if the id belong only to one repository
+	if strings.Contains(img.ID, repoName) && tag == "" {
+		for _, repoAndTag := range srv.runtime.repositories.ByID()[img.ID] {
+			parsedRepo := strings.Split(repoAndTag, ":")[0]
+			if strings.Contains(img.ID, repoName) {
+				repoName = parsedRepo
+			} else if repoName != parsedRepo {
+				// the id belongs to multiple repos, like base:latest and user:test,
+				// in that case return conflict
+				return imgs, nil
+			}
+		}
+	}
+	//Untag the current image
 	tagDeleted, err := srv.runtime.repositories.Delete(repoName, tag)
 	if err != nil {
 		return nil, err
diff --git a/utils.go b/utils.go
index d55b1ff..33cfbe5 100644
--- a/utils.go
+++ b/utils.go
@@ -1,5 +1,9 @@
 package docker
 
+import (
+	"strings"
+)
+
 // Compare two Config struct. Do not compare the "Image" nor "Hostname" fields
 // If OpenStdin is set, then it differs
 func CompareConfig(a, b *Config) bool {
@@ -68,6 +72,20 @@
 	}
 	if userConf.PortSpecs == nil || len(userConf.PortSpecs) == 0 {
 		userConf.PortSpecs = imageConf.PortSpecs
+	} else {
+		for _, imagePortSpec := range imageConf.PortSpecs {
+			found := false
+			imageNat, _ := parseNat(imagePortSpec)
+			for _, userPortSpec := range userConf.PortSpecs {
+				userNat, _ := parseNat(userPortSpec)
+				if imageNat.Proto == userNat.Proto && imageNat.Frontend == userNat.Frontend {
+					found = true
+				}
+			}
+			if !found {
+				userConf.PortSpecs = append(userConf.PortSpecs, imagePortSpec)
+			}
+		}
 	}
 	if !userConf.Tty {
 		userConf.Tty = imageConf.Tty
@@ -80,17 +98,38 @@
 	}
 	if userConf.Env == nil || len(userConf.Env) == 0 {
 		userConf.Env = imageConf.Env
+	} else {
+		for _, imageEnv := range imageConf.Env {
+			found := false
+			imageEnvKey := strings.Split(imageEnv, "=")[0]
+			for _, userEnv := range userConf.Env {
+				userEnvKey := strings.Split(userEnv, "=")[0]
+				if imageEnvKey == userEnvKey {
+					found = true
+				}
+			}
+			if !found {
+				userConf.Env = append(userConf.Env, imageEnv)
+			}
+		}
 	}
 	if userConf.Cmd == nil || len(userConf.Cmd) == 0 {
 		userConf.Cmd = imageConf.Cmd
 	}
 	if userConf.Dns == nil || len(userConf.Dns) == 0 {
 		userConf.Dns = imageConf.Dns
+	} else {
+		//duplicates aren't an issue here
+		userConf.Dns = append(userConf.Dns, imageConf.Dns...)
 	}
 	if userConf.Entrypoint == nil || len(userConf.Entrypoint) == 0 {
 		userConf.Entrypoint = imageConf.Entrypoint
 	}
 	if userConf.Volumes == nil || len(userConf.Volumes) == 0 {
 		userConf.Volumes = imageConf.Volumes
+	} else {
+		for k, v := range imageConf.Volumes {
+			userConf.Volumes[k] = v
+		}
 	}
 }
diff --git a/utils/utils_test.go b/utils/utils_test.go
index 1a7639d..2c68be5 100644
--- a/utils/utils_test.go
+++ b/utils/utils_test.go
@@ -5,6 +5,7 @@
 	"errors"
 	"io"
 	"io/ioutil"
+	"strings"
 	"testing"
 )
 
@@ -264,14 +265,16 @@
 
 func TestHumanSize(t *testing.T) {
 
-	size1000 := HumanSize(1000)
-	if size1000 != "    1 kB" {
-		t.Errorf("1000 -> expected     1 kB, got %s", size1000)
+	size := strings.Trim(HumanSize(1000), " \t")
+	expect := "1 kB"
+	if size != expect {
+		t.Errorf("1000 -> expected '%s', got '%s'", expect, size)
 	}
 
-	size1024 := HumanSize(1024)
-	if size1024 != "1.024 kB" {
-		t.Errorf("1024 -> expected 1.024 kB, got %s", size1024)
+	size = strings.Trim(HumanSize(1024), " \t")
+	expect = "1.024 kB"
+	if size != expect {
+		t.Errorf("1024 -> expected '%s', got '%s'", expect, size)
 	}
 }
 
diff --git a/utils_test.go b/utils_test.go
index 4951d3a..1bd18f4 100644
--- a/utils_test.go
+++ b/utils_test.go
@@ -1,13 +1,13 @@
 package docker
 
 import (
+	"github.com/dotcloud/docker/utils"
 	"io"
 	"io/ioutil"
 	"os"
 	"path"
 	"strings"
 	"testing"
-	"github.com/dotcloud/docker/utils"
 )
 
 // This file contains utility functions for docker's unit test suite.
@@ -87,17 +87,18 @@
 // The image name (eg. the XXX in []string{"-i", "-t", "XXX", "bash"}, is dynamically replaced by the current test image.
 // The caller is responsible for destroying the container.
 // Call t.Fatal() at the first error.
-func mkContainer(r *Runtime, args []string, t *testing.T) (*Container, *HostConfig) {
+func mkContainer(r *Runtime, args []string, t *testing.T) (*Container, *HostConfig, error) {
 	config, hostConfig, _, err := ParseRun(args, nil)
 	if err != nil {
-		t.Fatal(err)
+		return nil, nil, err
 	}
 	config.Image = GetTestImage(r).ID
 	c, err := NewBuilder(r).Create(config)
 	if err != nil {
 		t.Fatal(err)
+		return nil, nil, err
 	}
-	return c, hostConfig
+	return c, hostConfig, nil
 }
 
 // Create a test container, start it, wait for it to complete, destroy it,
@@ -110,7 +111,10 @@
 			t.Fatal(err)
 		}
 	}()
-	container, hostConfig := mkContainer(r, args, t)
+	container, hostConfig, err := mkContainer(r, args, t)
+	if err != nil {
+		return "", err
+	}
 	defer r.Destroy(container)
 	stdout, err := container.StdoutPipe()
 	if err != nil {
@@ -128,3 +132,61 @@
 	output = string(data)
 	return
 }
+
+func TestMergeConfig(t *testing.T) {
+	volumesImage := make(map[string]struct{})
+	volumesImage["/test1"] = struct{}{}
+	volumesImage["/test2"] = struct{}{}
+	configImage := &Config{
+		Dns:       []string{"1.1.1.1", "2.2.2.2"},
+		PortSpecs: []string{"1111:1111", "2222:2222"},
+		Env:       []string{"VAR1=1", "VAR2=2"},
+		Volumes:   volumesImage,
+	}
+
+	volumesUser := make(map[string]struct{})
+	volumesUser["/test3"] = struct{}{}
+	configUser := &Config{
+		Dns:       []string{"3.3.3.3"},
+		PortSpecs: []string{"2222:3333", "3333:3333"},
+		Env:       []string{"VAR2=3", "VAR3=3"},
+		Volumes:   volumesUser,
+	}
+
+	MergeConfig(configUser, configImage)
+
+	if len(configUser.Dns) != 3 {
+		t.Fatalf("Expected 3 dns, 1.1.1.1, 2.2.2.2 and 3.3.3.3, found %d", len(configUser.Dns))
+	}
+	for _, dns := range configUser.Dns {
+		if dns != "1.1.1.1" && dns != "2.2.2.2" && dns != "3.3.3.3" {
+			t.Fatalf("Expected 1.1.1.1 or 2.2.2.2 or 3.3.3.3, found %s", dns)
+		}
+	}
+
+	if len(configUser.PortSpecs) != 3 {
+		t.Fatalf("Expected 3 portSpecs, 1111:1111, 2222:3333 and 3333:3333, found %d", len(configUser.PortSpecs))
+	}
+	for _, portSpecs := range configUser.PortSpecs {
+		if portSpecs != "1111:1111" && portSpecs != "2222:3333" && portSpecs != "3333:3333" {
+			t.Fatalf("Expected 1111:1111 or 2222:3333 or 3333:3333, found %s", portSpecs)
+		}
+	}
+	if len(configUser.Env) != 3 {
+		t.Fatalf("Expected 3 env var, VAR1=1, VAR2=3 and VAR3=3, found %d", len(configUser.Env))
+	}
+	for _, env := range configUser.Env {
+		if env != "VAR1=1" && env != "VAR2=3" && env != "VAR3=3" {
+			t.Fatalf("Expected VAR1=1 or VAR2=3 or VAR3=3, found %s", env)
+		}
+	}
+
+	if len(configUser.Volumes) != 3 {
+		t.Fatalf("Expected 3 volumes, /test1, /test2 and /test3, found %d", len(configUser.Volumes))
+	}
+	for v, _ := range configUser.Volumes {
+		if v != "/test1" && v != "/test2" && v != "/test3" {
+			t.Fatalf("Expected /test1 or /test2 or /test3, found %s", v)
+		}
+	}
+}