Browse Source

Merge branch 'pull-missing' of ssh://github.com/chooper/docker

Solomon Hykes 12 năm trước cách đây
mục cha
commit
8f81feb1f0
2 tập tin đã thay đổi với 73 bổ sung21 xóa
  1. 32 9
      commands/commands.go
  2. 41 12
      future/future.go

+ 32 - 9
commands/commands.go

@@ -11,8 +11,9 @@ import (
 	"github.com/dotcloud/docker/future"
 	"github.com/dotcloud/docker/rcli"
 	"io"
-	"net/http"
+	"io/ioutil"
 	"net/url"
+	"net/http"
 	"os"
 	"path"
 	"strconv"
@@ -425,10 +426,12 @@ func (srv *Server) CmdKill(stdin io.ReadCloser, stdout io.Writer, args ...string
 func (srv *Server) CmdImport(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
 	cmd := rcli.Subcmd(stdout, "import", "[OPTIONS] NAME", "Create a new filesystem image from the contents of a tarball")
 	fl_stdin := cmd.Bool("stdin", false, "Read tarball from stdin")
+	var archive io.Reader
+	var resp *http.Response
+
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	var archive io.Reader
 	name := cmd.Arg(0)
 	if name == "" {
 		return errors.New("Not enough arguments")
@@ -451,14 +454,11 @@ func (srv *Server) CmdImport(stdin io.ReadCloser, stdout io.Writer, args ...stri
 		fmt.Fprintf(stdout, "Downloading from %s\n", u.String())
 		// Download with curl (pretty progress bar)
 		// If curl is not available, fallback to http.Get()
-		archive, err = future.Curl(u.String(), stdout)
+		resp, err = future.Download(u.String(), stdout)
 		if err != nil {
-			if resp, err := http.Get(u.String()); err != nil {
-				return err
-			} else {
-				archive = resp.Body
-			}
+			return err
 		}
+		archive = future.ProgressReader(resp.Body, int(resp.ContentLength), stdout)
 	}
 	fmt.Fprintf(stdout, "Unpacking to %s\n", name)
 	img, err := srv.images.Create(archive, nil, name, "")
@@ -838,12 +838,16 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
 	fl_comment := cmd.String("c", "", "Comment")
 	fl_memory := cmd.Int64("m", 0, "Memory limit (in bytes)")
 	var fl_ports ports
+
 	cmd.Var(&fl_ports, "p", "Map a network port to the container")
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
 	name := cmd.Arg(0)
+	var img_name string
+	//var img_version string  // Only here for reference
 	var cmdline []string
+
 	if len(cmd.Args()) >= 2 {
 		cmdline = cmd.Args()[1:]
 	}
@@ -851,6 +855,7 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
 	if name == "" {
 		name = "base"
 	}
+
 	// Choose a default command if needed
 	if len(cmdline) == 0 {
 		*fl_stdin = true
@@ -858,13 +863,31 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
 		*fl_attach = true
 		cmdline = []string{"/bin/bash", "-i"}
 	}
+
 	// Find the image
 	img, err := srv.images.Find(name)
 	if err != nil {
 		return err
 	} else if img == nil {
-		return errors.New("No such image: " + name)
+		// Separate the name:version tag
+	    if strings.Contains(name, ":") {
+    	    parts := strings.SplitN(name, ":", 2)
+    	    img_name = parts[0]
+			//img_version = parts[1]   // Only here for reference
+   		} else {
+			img_name = name
+		}
+
+		stdin_noclose := ioutil.NopCloser(stdin)
+		if err := srv.CmdImport(stdin_noclose, stdout, img_name); err != nil {
+			return err
+		}
+		img, err = srv.images.Find(name)
+		if err != nil || img == nil {
+			return errors.New("Could not find image after downloading: " + name)
+		}
 	}
+
 	// Create new container
 	container, err := srv.CreateContainer(img, fl_ports, *fl_user, *fl_tty,
 		*fl_stdin, *fl_memory, *fl_comment, cmdline[0], cmdline[1:]...)

+ 41 - 12
future/future.go

@@ -3,10 +3,11 @@ package future
 import (
 	"bytes"
 	"crypto/sha256"
+	"errors"
 	"fmt"
 	"io"
 	"math/rand"
-	"os/exec"
+	"net/http"
 	"time"
 )
 
@@ -85,18 +86,46 @@ func Pv(src io.Reader, info io.Writer) io.Reader {
 	return r
 }
 
-// Curl makes an http request by executing the unix command 'curl', and returns
-// the body of the response. If `stderr` is not nil, a progress bar will be
-// written to it.
-func Curl(url string, stderr io.Writer) (io.Reader, error) {
-	curl := exec.Command("curl", "-#", "-L", url)
-	output, err := curl.StdoutPipe()
-	if err != nil {
+// Request a given URL and return an io.Reader
+func Download(url string, stderr io.Writer) (*http.Response, error) {
+	var resp *http.Response
+	var err error = nil
+	if resp, err = http.Get(url); err != nil {
 		return nil, err
 	}
-	curl.Stderr = stderr
-	if err := curl.Start(); err != nil {
-		return nil, err
+	if resp.StatusCode >= 400 {
+		return nil, errors.New("Got HTTP status code >= 400: " + resp.Status)
 	}
-	return output, nil
+	return resp, nil
+}
+
+// Reader with progress bar
+type progressReader struct {
+	reader         io.ReadCloser  // Stream to read from
+	output         io.Writer      // Where to send progress bar to
+	read_total     int            // Expected stream length (bytes)
+	read_progress  int            // How much has been read so far (bytes)
+	last_update    int            // How many bytes read at least update
+}
+func (r *progressReader) Read(p []byte) (n int, err error) {
+	read, err := io.ReadCloser(r.reader).Read(p)
+	r.read_progress += read
+
+	// Only update progress for every 1% read
+	update_every := int(0.01 * float64(r.read_total))
+    if r.read_progress - r.last_update > update_every {
+		fmt.Fprintf(r.output, "%d/%d (%.0f%%)\r", 
+			r.read_progress,
+			r.read_total,
+			float64(r.read_progress) / float64(r.read_total) * 100)
+		r.last_update = r.read_progress
+	}
+
+	return read, err
+}
+func (r *progressReader) Close() error {
+	return io.ReadCloser(r.reader).Close()
+}
+func ProgressReader(r io.ReadCloser, size int, output io.Writer) *progressReader {
+	return &progressReader{r, output, size, 0, 0}
 }