From d42c10aa094e39d8c1184b61c98777d8c59ae900 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Thu, 23 May 2013 18:32:56 -0700 Subject: [PATCH] Implement Context within docker build (not yet in use) --- api.go | 23 +++++----------- builder_client.go | 2 +- commands.go | 70 ++++++++++++++++++++++++++++++++++------------- 3 files changed, 59 insertions(+), 36 deletions(-) diff --git a/api.go b/api.go index 5812743dfe..0a65543b79 100644 --- a/api.go +++ b/api.go @@ -1,7 +1,6 @@ package docker import ( - "bytes" "encoding/json" "fmt" "github.com/dotcloud/docker/auth" @@ -631,32 +630,24 @@ func Upload(w http.ResponseWriter, req *http.Request) { } func postBuild(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { - - Upload(w, r) - - // io.Copy(os.Stderr, r.Body) - - if err := r.ParseMultipartForm(409699); err != nil { - utils.Debugf("----- %s\n", err) + if err := r.ParseMultipartForm(4096); err != nil { return err } - mpr, err := r.MultipartReader() + file, _, err := r.FormFile("Dockerfile") if err != nil { return err } - p, err := mpr.NextPart() + context, _, err := r.FormFile("Context") if err != nil { - return err + if err != http.ErrMissingFile { + return err + } } - dockerfile := make([]byte, 4096) - p.Read(dockerfile) - - utils.Debugf("Dockerfile >>>%s<<<\n", dockerfile) b := NewBuildFile(srv, w) - if _, err := b.Build(bytes.NewReader(dockerfile)); err != nil { + if _, err := b.Build(file, context); err != nil { return err } return nil diff --git a/builder_client.go b/builder_client.go index e0a55ae6c9..0b511ee218 100644 --- a/builder_client.go +++ b/builder_client.go @@ -255,7 +255,7 @@ func (b *builderClient) commit(id string) error { return nil } -func (b *builderClient) Build(dockerfile io.Reader) (string, error) { +func (b *builderClient) Build(dockerfile, context io.Reader) (string, error) { defer b.clearTmp(b.tmpContainers, b.tmpImages) file := bufio.NewReader(dockerfile) for { diff --git a/commands.go b/commands.go index 4291b1d8de..f5c658e6b1 100644 --- a/commands.go +++ b/commands.go @@ -57,7 +57,7 @@ func (cli *DockerCli) CmdHelp(args ...string) error { help := "Usage: docker COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n" for cmd, description := range map[string]string{ "attach": "Attach to a running container", - "build": "Build a container from Dockerfile or via stdin", + "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", @@ -112,36 +112,67 @@ func (cli *DockerCli) CmdInsert(args ...string) error { } func (cli *DockerCli) CmdBuild(args ...string) error { + cmd := Subcmd("build", "[OPTIONS]", "Build an image from a Dockerfile") + fileName := cmd.String("f", "Dockerfile", "Use file as Dockerfile. Can be '-' for stdin") + contextPath := cmd.String("c", "", "Use the specified directory as context for the build") + if err := cmd.Parse(args); err != nil { + return nil + } + var ( + file io.ReadCloser + multipartBody io.Reader + err error + ) + + // Init the needed component for the Multipart buff := bytes.NewBuffer([]byte{}) - + multipartBody = buff w := multipart.NewWriter(buff) + boundary := strings.NewReader("\r\n--" + w.Boundary() + "--\r\n") - dockerfile, err := w.CreateFormFile("Dockerfile", "Dockerfile") + // Create a FormFile multipart for the Dockerfile + if *fileName == "-" { + file = os.Stdin + } else { + file, err = os.Open(*fileName) + if err != nil { + return err + } + defer file.Close() + } + if _, err := w.CreateFormFile("Dockerfile", *fileName); err != nil { + return err + } + multipartBody = io.MultiReader(multipartBody, file) + + // Create a FormFile multipart for the context if needed + if *contextPath != "" { + // FIXME: Use NewTempArchive in order to have the size and avoid too much memory usage? + context, err := Tar(*contextPath, Bzip2) + if err != nil { + return err + } + if _, err := w.CreateFormFile("Context", *contextPath+".tar.bz2"); err != nil { + return err + } + multipartBody = io.MultiReader(multipartBody, utils.ProgressReader(ioutil.NopCloser(context), -1, os.Stdout, "Uploading Context %v/%v (%v)")) + } + + // Send the multipart request with correct content-type + req, err := http.NewRequest("POST", fmt.Sprintf("http://%s:%d%s", cli.host, cli.port, "/build"), io.MultiReader(multipartBody, boundary)) if err != nil { return err } - file, err := os.Open("Dockerfile") - if err != nil { - return err - } - dockerfile.Write([]byte(w.Boundary() + "\r\n")) - if _, err := io.Copy(dockerfile, file); err != nil { - return err - } - dockerfile.Write([]byte("\r\n" + w.Boundary())) + req.Header.Set("Content-Type", w.FormDataContentType()) - // req, err := http.NewRequest("POST", fmt.Sprintf("http://%s:%d%s", cli.host, cli.port, "/build"), buff) - // if err != nil { - // return err - // } - // req.Header.Set("Content-Type", w.FormDataContentType()) - resp, err := http.Post(fmt.Sprintf("http://%s:%d%s", cli.host, cli.port, "/build"), w.FormDataContentType(), buff) + resp, err := http.DefaultClient.Do(req) if err != nil { return err } defer resp.Body.Close() + // Check for errors if resp.StatusCode < 200 || resp.StatusCode >= 400 { body, err := ioutil.ReadAll(resp.Body) if err != nil { @@ -150,6 +181,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error { return fmt.Errorf("error: %s", body) } + // Output the result if _, err := io.Copy(os.Stdout, resp.Body); err != nil { return err } @@ -180,7 +212,7 @@ func (cli *DockerCli) CmdBuildClient(args ...string) error { return err } } - if _, err := NewBuilderClient("0.0.0.0", 4243).Build(file); err != nil { + if _, err := NewBuilderClient("0.0.0.0", 4243).Build(file, nil); err != nil { return err } return nil