From 415379e45dadb32385771ceae701d8b9f204f2b8 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Thu, 23 Jan 2014 12:19:52 -0800 Subject: [PATCH] move build to a job Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- api.go | 98 +++++++++---------------------------------------------- server.go | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 82 deletions(-) diff --git a/api.go b/api.go index b45f1a35d1..06d9fde77b 100644 --- a/api.go +++ b/api.go @@ -8,7 +8,6 @@ import ( "encoding/json" "expvar" "fmt" - "github.com/dotcloud/docker/archive" "github.com/dotcloud/docker/auth" "github.com/dotcloud/docker/engine" "github.com/dotcloud/docker/pkg/systemd" @@ -22,7 +21,6 @@ import ( "net/http" "net/http/pprof" "os" - "os/exec" "regexp" "strconv" "strings" @@ -892,18 +890,12 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ return fmt.Errorf("Multipart upload for build is no longer supported. Please upgrade your docker client.") } var ( - remoteURL = r.FormValue("remote") - repoName = r.FormValue("t") - rawSuppressOutput = r.FormValue("q") - rawNoCache = r.FormValue("nocache") - rawRm = r.FormValue("rm") authEncoded = r.Header.Get("X-Registry-Auth") authConfig = &auth.AuthConfig{} configFileEncoded = r.Header.Get("X-Registry-Config") configFile = &auth.ConfigFile{} - tag string + job = srv.Eng.Job("build") ) - repoName, tag = utils.ParseRepositoryTag(repoName) // This block can be removed when API versions prior to 1.9 are deprecated. // Both headers will be parsed and sent along to the daemon, but if a non-empty @@ -927,83 +919,25 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ } } - var context io.Reader - - if remoteURL == "" { - context = r.Body - } else if utils.IsGIT(remoteURL) { - if !strings.HasPrefix(remoteURL, "git://") { - remoteURL = "https://" + remoteURL - } - root, err := ioutil.TempDir("", "docker-build-git") - if err != nil { - return err - } - defer os.RemoveAll(root) - - if output, err := exec.Command("git", "clone", remoteURL, root).CombinedOutput(); err != nil { - return fmt.Errorf("Error trying to use git: %s (%s)", err, output) - } - - c, err := archive.Tar(root, archive.Uncompressed) - if err != nil { - return err - } - context = c - } else if utils.IsURL(remoteURL) { - f, err := utils.Download(remoteURL) - if err != nil { - return err - } - defer f.Body.Close() - dockerFile, err := ioutil.ReadAll(f.Body) - if err != nil { - return err - } - c, err := MkBuildContext(string(dockerFile), nil) - if err != nil { - return err - } - context = c - } - - suppressOutput, err := getBoolParam(rawSuppressOutput) - if err != nil { - return err - } - noCache, err := getBoolParam(rawNoCache) - if err != nil { - return err - } - rm, err := getBoolParam(rawRm) - if err != nil { - return err - } - if version >= 1.8 { w.Header().Set("Content-Type", "application/json") + job.SetenvBool("json", true) } - sf := utils.NewStreamFormatter(version >= 1.8) - b := NewBuildFile(srv, - &StdoutFormater{ - Writer: utils.NewWriteFlusher(w), - StreamFormatter: sf, - }, - &StderrFormater{ - Writer: utils.NewWriteFlusher(w), - StreamFormatter: sf, - }, - !suppressOutput, !noCache, rm, utils.NewWriteFlusher(w), sf, authConfig, configFile) - id, err := b.Build(context) - if err != nil { - if sf.Used() { - w.Write(sf.FormatError(err)) - return nil + + job.Stdout.Add(utils.NewWriteFlusher(w)) + job.Stdin.Add(r.Body) + job.Setenv("remote", r.FormValue("remote")) + job.Setenv("t", r.FormValue("t")) + job.Setenv("q", r.FormValue("q")) + job.Setenv("nocache", r.FormValue("nocache")) + job.Setenv("rm", r.FormValue("rm")) + + if err := job.Run(); err != nil { + if !job.Stdout.Used() { + return err } - return fmt.Errorf("Error build: %s", err) - } - if repoName != "" { - srv.runtime.repositories.Set(repoName, tag, id, false) + sf := utils.NewStreamFormatter(version >= 1.8) + w.Write(sf.FormatError(err)) } return nil } diff --git a/server.go b/server.go index 60fefc524f..c0b45feeb2 100644 --- a/server.go +++ b/server.go @@ -96,6 +96,7 @@ func jobInitApi(job *engine.Job) engine.Status { "changes": srv.ContainerChanges, "top": srv.ContainerTop, "load": srv.ImageLoad, + "build": srv.Build, } { if err := job.Eng.Register(name, handler); err != nil { job.Error(err) @@ -391,6 +392,92 @@ func (srv *Server) exportImage(image *Image, tempdir string) error { return nil } +func (srv *Server) Build(job *engine.Job) engine.Status { + if len(job.Args) != 0 { + job.Errorf("Usage: %s\n", job.Name) + return engine.StatusErr + } + var ( + remoteURL = job.Getenv("remote") + repoName = job.Getenv("t") + suppressOutput = job.GetenvBool("q") + noCache = job.GetenvBool("nocache") + rm = job.GetenvBool("rm") + authConfig = &auth.AuthConfig{} + configFile = &auth.ConfigFile{} + tag string + context io.Reader + ) + job.GetenvJson("authConfig", authConfig) + job.GetenvJson("configFile", configFile) + repoName, tag = utils.ParseRepositoryTag(repoName) + + if remoteURL == "" { + context = job.Stdin + } else if utils.IsGIT(remoteURL) { + if !strings.HasPrefix(remoteURL, "git://") { + remoteURL = "https://" + remoteURL + } + root, err := ioutil.TempDir("", "docker-build-git") + if err != nil { + job.Error(err) + return engine.StatusErr + } + defer os.RemoveAll(root) + + if output, err := exec.Command("git", "clone", remoteURL, root).CombinedOutput(); err != nil { + job.Errorf("Error trying to use git: %s (%s)", err, output) + return engine.StatusErr + } + + c, err := archive.Tar(root, archive.Uncompressed) + if err != nil { + job.Error(err) + return engine.StatusErr + } + context = c + } else if utils.IsURL(remoteURL) { + f, err := utils.Download(remoteURL) + if err != nil { + job.Error(err) + return engine.StatusErr + } + defer f.Body.Close() + dockerFile, err := ioutil.ReadAll(f.Body) + if err != nil { + job.Error(err) + return engine.StatusErr + } + c, err := MkBuildContext(string(dockerFile), nil) + if err != nil { + job.Error(err) + return engine.StatusErr + } + context = c + } + + sf := utils.NewStreamFormatter(job.GetenvBool("json")) + b := NewBuildFile(srv, + &StdoutFormater{ + Writer: job.Stdout, + StreamFormatter: sf, + }, + &StderrFormater{ + Writer: job.Stdout, + StreamFormatter: sf, + }, + !suppressOutput, !noCache, rm, job.Stdout, sf, authConfig, configFile) + id, err := b.Build(context) + if err != nil { + job.Error(err) + return engine.StatusErr + } + if repoName != "" { + srv.runtime.repositories.Set(repoName, tag, id, false) + } + return engine.StatusOK +} + // Loads a set of images into the repository. This is the complementary of ImageExport. // The input stream is an uncompressed tar ball containing images and metadata. func (srv *Server) ImageLoad(job *engine.Job) engine.Status {