Signed-off-by: David Calavera <david.calavera@gmail.com>
| ... | ... |
@@ -23,6 +23,7 @@ import ( |
| 23 | 23 |
"github.com/docker/docker/api" |
| 24 | 24 |
"github.com/docker/docker/api/types" |
| 25 | 25 |
"github.com/docker/docker/autogen/dockerversion" |
| 26 |
+ "github.com/docker/docker/builder" |
|
| 26 | 27 |
"github.com/docker/docker/daemon" |
| 27 | 28 |
"github.com/docker/docker/daemon/networkdriver/bridge" |
| 28 | 29 |
"github.com/docker/docker/engine" |
| ... | ... |
@@ -236,12 +237,12 @@ func writeJSON(w http.ResponseWriter, code int, v interface{}) error {
|
| 236 | 236 |
return json.NewEncoder(w).Encode(v) |
| 237 | 237 |
} |
| 238 | 238 |
|
| 239 |
-func streamJSON(job *engine.Job, w http.ResponseWriter, flush bool) {
|
|
| 239 |
+func streamJSON(out *engine.Output, w http.ResponseWriter, flush bool) {
|
|
| 240 | 240 |
w.Header().Set("Content-Type", "application/json")
|
| 241 | 241 |
if flush {
|
| 242 |
- job.Stdout.Add(utils.NewWriteFlusher(w)) |
|
| 242 |
+ out.Add(utils.NewWriteFlusher(w)) |
|
| 243 | 243 |
} else {
|
| 244 |
- job.Stdout.Add(w) |
|
| 244 |
+ out.Add(w) |
|
| 245 | 245 |
} |
| 246 | 246 |
} |
| 247 | 247 |
|
| ... | ... |
@@ -857,7 +858,7 @@ func (s *Server) postImagesPush(eng *engine.Engine, version version.Version, w h |
| 857 | 857 |
job.Setenv("tag", r.Form.Get("tag"))
|
| 858 | 858 |
if version.GreaterThan("1.0") {
|
| 859 | 859 |
job.SetenvBool("json", true)
|
| 860 |
- streamJSON(job, w, true) |
|
| 860 |
+ streamJSON(job.Stdout, w, true) |
|
| 861 | 861 |
} else {
|
| 862 | 862 |
job.Stdout.Add(utils.NewWriteFlusher(w)) |
| 863 | 863 |
} |
| ... | ... |
@@ -1207,7 +1208,7 @@ func (s *Server) getContainersByName(eng *engine.Engine, version version.Version |
| 1207 | 1207 |
if version.LessThan("1.12") {
|
| 1208 | 1208 |
job.SetenvBool("raw", true)
|
| 1209 | 1209 |
} |
| 1210 |
- streamJSON(job, w, false) |
|
| 1210 |
+ streamJSON(job.Stdout, w, false) |
|
| 1211 | 1211 |
return job.Run() |
| 1212 | 1212 |
} |
| 1213 | 1213 |
|
| ... | ... |
@@ -1232,7 +1233,7 @@ func (s *Server) getImagesByName(eng *engine.Engine, version version.Version, w |
| 1232 | 1232 |
if version.LessThan("1.12") {
|
| 1233 | 1233 |
job.SetenvBool("raw", true)
|
| 1234 | 1234 |
} |
| 1235 |
- streamJSON(job, w, false) |
|
| 1235 |
+ streamJSON(job.Stdout, w, false) |
|
| 1236 | 1236 |
return job.Run() |
| 1237 | 1237 |
} |
| 1238 | 1238 |
|
| ... | ... |
@@ -1245,9 +1246,11 @@ func (s *Server) postBuild(eng *engine.Engine, version version.Version, w http.R |
| 1245 | 1245 |
authConfig = ®istry.AuthConfig{}
|
| 1246 | 1246 |
configFileEncoded = r.Header.Get("X-Registry-Config")
|
| 1247 | 1247 |
configFile = ®istry.ConfigFile{}
|
| 1248 |
- job = eng.Job("build")
|
|
| 1248 |
+ job = builder.NewBuildConfig(eng.Logging, eng.Stderr) |
|
| 1249 | 1249 |
) |
| 1250 | 1250 |
|
| 1251 |
+ b := &builder.BuilderJob{eng, getDaemon(eng)}
|
|
| 1252 |
+ |
|
| 1251 | 1253 |
// This block can be removed when API versions prior to 1.9 are deprecated. |
| 1252 | 1254 |
// Both headers will be parsed and sent along to the daemon, but if a non-empty |
| 1253 | 1255 |
// ConfigFile is present, any value provided as an AuthConfig directly will |
| ... | ... |
@@ -1271,36 +1274,38 @@ func (s *Server) postBuild(eng *engine.Engine, version version.Version, w http.R |
| 1271 | 1271 |
} |
| 1272 | 1272 |
|
| 1273 | 1273 |
if version.GreaterThanOrEqualTo("1.8") {
|
| 1274 |
- job.SetenvBool("json", true)
|
|
| 1275 |
- streamJSON(job, w, true) |
|
| 1274 |
+ job.JSONFormat = true |
|
| 1275 |
+ streamJSON(job.Stdout, w, true) |
|
| 1276 | 1276 |
} else {
|
| 1277 | 1277 |
job.Stdout.Add(utils.NewWriteFlusher(w)) |
| 1278 | 1278 |
} |
| 1279 | 1279 |
|
| 1280 | 1280 |
if toBool(r.FormValue("forcerm")) && version.GreaterThanOrEqualTo("1.12") {
|
| 1281 |
- job.Setenv("rm", "1")
|
|
| 1281 |
+ job.Remove = true |
|
| 1282 | 1282 |
} else if r.FormValue("rm") == "" && version.GreaterThanOrEqualTo("1.12") {
|
| 1283 |
- job.Setenv("rm", "1")
|
|
| 1283 |
+ job.Remove = true |
|
| 1284 | 1284 |
} else {
|
| 1285 |
- job.Setenv("rm", r.FormValue("rm"))
|
|
| 1285 |
+ job.Remove = toBool(r.FormValue("rm"))
|
|
| 1286 | 1286 |
} |
| 1287 | 1287 |
if toBool(r.FormValue("pull")) && version.GreaterThanOrEqualTo("1.16") {
|
| 1288 |
- job.Setenv("pull", "1")
|
|
| 1288 |
+ job.Pull = true |
|
| 1289 | 1289 |
} |
| 1290 | 1290 |
job.Stdin.Add(r.Body) |
| 1291 |
- job.Setenv("remote", r.FormValue("remote"))
|
|
| 1292 |
- job.Setenv("dockerfile", r.FormValue("dockerfile"))
|
|
| 1293 |
- job.Setenv("t", r.FormValue("t"))
|
|
| 1294 |
- job.Setenv("q", r.FormValue("q"))
|
|
| 1295 |
- job.Setenv("nocache", r.FormValue("nocache"))
|
|
| 1296 |
- job.Setenv("forcerm", r.FormValue("forcerm"))
|
|
| 1297 |
- job.SetenvJson("authConfig", authConfig)
|
|
| 1298 |
- job.SetenvJson("configFile", configFile)
|
|
| 1299 |
- job.Setenv("memswap", r.FormValue("memswap"))
|
|
| 1300 |
- job.Setenv("memory", r.FormValue("memory"))
|
|
| 1301 |
- job.Setenv("cpusetcpus", r.FormValue("cpusetcpus"))
|
|
| 1302 |
- job.Setenv("cpusetmems", r.FormValue("cpusetmems"))
|
|
| 1303 |
- job.Setenv("cpushares", r.FormValue("cpushares"))
|
|
| 1291 |
+ |
|
| 1292 |
+ // FIXME(calavera): !!!!! Remote might not be used. Solve the mistery before merging |
|
| 1293 |
+ //job.Setenv("remote", r.FormValue("remote"))
|
|
| 1294 |
+ job.DockerfileName = r.FormValue("dockerfile")
|
|
| 1295 |
+ job.RepoName = r.FormValue("t")
|
|
| 1296 |
+ job.SuppressOutput = toBool(r.FormValue("q"))
|
|
| 1297 |
+ job.NoCache = toBool(r.FormValue("nocache"))
|
|
| 1298 |
+ job.ForceRemove = toBool(r.FormValue("forcerm"))
|
|
| 1299 |
+ job.AuthConfig = authConfig |
|
| 1300 |
+ job.ConfigFile = configFile |
|
| 1301 |
+ job.MemorySwap = toInt64(r.FormValue("memswap"))
|
|
| 1302 |
+ job.Memory = toInt64(r.FormValue("memory"))
|
|
| 1303 |
+ job.CpuShares = toInt64(r.FormValue("cpushares"))
|
|
| 1304 |
+ job.CpuSetCpus = r.FormValue("cpusetcpus")
|
|
| 1305 |
+ job.CpuSetMems = r.FormValue("cpusetmems")
|
|
| 1304 | 1306 |
|
| 1305 | 1307 |
// Job cancellation. Note: not all job types support this. |
| 1306 | 1308 |
if closeNotifier, ok := w.(http.CloseNotifier); ok {
|
| ... | ... |
@@ -1310,13 +1315,13 @@ func (s *Server) postBuild(eng *engine.Engine, version version.Version, w http.R |
| 1310 | 1310 |
select {
|
| 1311 | 1311 |
case <-finished: |
| 1312 | 1312 |
case <-closeNotifier.CloseNotify(): |
| 1313 |
- logrus.Infof("Client disconnected, cancelling job: %s", job.Name)
|
|
| 1313 |
+ logrus.Infof("Client disconnected, cancelling job: build")
|
|
| 1314 | 1314 |
job.Cancel() |
| 1315 | 1315 |
} |
| 1316 | 1316 |
}() |
| 1317 | 1317 |
} |
| 1318 | 1318 |
|
| 1319 |
- if err := job.Run(); err != nil {
|
|
| 1319 |
+ if err := b.CmdBuild(job); err != nil {
|
|
| 1320 | 1320 |
if !job.Stdout.Used() {
|
| 1321 | 1321 |
return err |
| 1322 | 1322 |
} |
| ... | ... |
@@ -1676,3 +1681,12 @@ func toBool(s string) bool {
|
| 1676 | 1676 |
s = strings.ToLower(strings.TrimSpace(s)) |
| 1677 | 1677 |
return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none") |
| 1678 | 1678 |
} |
| 1679 |
+ |
|
| 1680 |
+// FIXME(calavera): This is a copy of the Env.GetInt64 |
|
| 1681 |
+func toInt64(s string) int64 {
|
|
| 1682 |
+ val, err := strconv.ParseInt(s, 10, 64) |
|
| 1683 |
+ if err != nil {
|
|
| 1684 |
+ return 0 |
|
| 1685 |
+ } |
|
| 1686 |
+ return val |
|
| 1687 |
+} |
| ... | ... |
@@ -9,6 +9,7 @@ import ( |
| 9 | 9 |
"os" |
| 10 | 10 |
"os/exec" |
| 11 | 11 |
"strings" |
| 12 |
+ "sync" |
|
| 12 | 13 |
|
| 13 | 14 |
"github.com/docker/docker/api" |
| 14 | 15 |
"github.com/docker/docker/builder/parser" |
| ... | ... |
@@ -17,6 +18,7 @@ import ( |
| 17 | 17 |
"github.com/docker/docker/graph" |
| 18 | 18 |
"github.com/docker/docker/pkg/archive" |
| 19 | 19 |
"github.com/docker/docker/pkg/httputils" |
| 20 |
+ "github.com/docker/docker/pkg/ioutils" |
|
| 20 | 21 |
"github.com/docker/docker/pkg/parsers" |
| 21 | 22 |
"github.com/docker/docker/pkg/streamformatter" |
| 22 | 23 |
"github.com/docker/docker/pkg/urlutil" |
| ... | ... |
@@ -41,41 +43,73 @@ type BuilderJob struct {
|
| 41 | 41 |
Daemon *daemon.Daemon |
| 42 | 42 |
} |
| 43 | 43 |
|
| 44 |
+type Config struct {
|
|
| 45 |
+ DockerfileName string |
|
| 46 |
+ RemoteURL string |
|
| 47 |
+ RepoName string |
|
| 48 |
+ SuppressOutput bool |
|
| 49 |
+ NoCache bool |
|
| 50 |
+ Remove bool |
|
| 51 |
+ ForceRemove bool |
|
| 52 |
+ Pull bool |
|
| 53 |
+ JSONFormat bool |
|
| 54 |
+ Memory int64 |
|
| 55 |
+ MemorySwap int64 |
|
| 56 |
+ CpuShares int64 |
|
| 57 |
+ CpuSetCpus string |
|
| 58 |
+ CpuSetMems string |
|
| 59 |
+ AuthConfig *registry.AuthConfig |
|
| 60 |
+ ConfigFile *registry.ConfigFile |
|
| 61 |
+ |
|
| 62 |
+ Stdout *engine.Output |
|
| 63 |
+ Stderr *engine.Output |
|
| 64 |
+ Stdin *engine.Input |
|
| 65 |
+ // When closed, the job has been cancelled. |
|
| 66 |
+ // Note: not all jobs implement cancellation. |
|
| 67 |
+ // See Job.Cancel() and Job.WaitCancelled() |
|
| 68 |
+ cancelled chan struct{}
|
|
| 69 |
+ cancelOnce sync.Once |
|
| 70 |
+} |
|
| 71 |
+ |
|
| 72 |
+// When called, causes the Job.WaitCancelled channel to unblock. |
|
| 73 |
+func (b *Config) Cancel() {
|
|
| 74 |
+ b.cancelOnce.Do(func() {
|
|
| 75 |
+ close(b.cancelled) |
|
| 76 |
+ }) |
|
| 77 |
+} |
|
| 78 |
+ |
|
| 79 |
+// Returns a channel which is closed ("never blocks") when the job is cancelled.
|
|
| 80 |
+func (b *Config) WaitCancelled() <-chan struct{} {
|
|
| 81 |
+ return b.cancelled |
|
| 82 |
+} |
|
| 83 |
+ |
|
| 84 |
+func NewBuildConfig(logging bool, err io.Writer) *Config {
|
|
| 85 |
+ c := &Config{
|
|
| 86 |
+ Stdout: engine.NewOutput(), |
|
| 87 |
+ Stderr: engine.NewOutput(), |
|
| 88 |
+ Stdin: engine.NewInput(), |
|
| 89 |
+ cancelled: make(chan struct{}),
|
|
| 90 |
+ } |
|
| 91 |
+ if logging {
|
|
| 92 |
+ c.Stderr.Add(ioutils.NopWriteCloser(err)) |
|
| 93 |
+ } |
|
| 94 |
+ return c |
|
| 95 |
+} |
|
| 96 |
+ |
|
| 44 | 97 |
func (b *BuilderJob) Install() {
|
| 45 |
- b.Engine.Register("build", b.CmdBuild)
|
|
| 46 | 98 |
b.Engine.Register("build_config", b.CmdBuildConfig)
|
| 47 | 99 |
} |
| 48 | 100 |
|
| 49 |
-func (b *BuilderJob) CmdBuild(job *engine.Job) error {
|
|
| 50 |
- if len(job.Args) != 0 {
|
|
| 51 |
- return fmt.Errorf("Usage: %s\n", job.Name)
|
|
| 52 |
- } |
|
| 101 |
+func (b *BuilderJob) CmdBuild(buildConfig *Config) error {
|
|
| 53 | 102 |
var ( |
| 54 |
- dockerfileName = job.Getenv("dockerfile")
|
|
| 55 |
- remoteURL = job.Getenv("remote")
|
|
| 56 |
- repoName = job.Getenv("t")
|
|
| 57 |
- suppressOutput = job.GetenvBool("q")
|
|
| 58 |
- noCache = job.GetenvBool("nocache")
|
|
| 59 |
- rm = job.GetenvBool("rm")
|
|
| 60 |
- forceRm = job.GetenvBool("forcerm")
|
|
| 61 |
- pull = job.GetenvBool("pull")
|
|
| 62 |
- memory = job.GetenvInt64("memory")
|
|
| 63 |
- memorySwap = job.GetenvInt64("memswap")
|
|
| 64 |
- cpuShares = job.GetenvInt64("cpushares")
|
|
| 65 |
- cpuSetCpus = job.Getenv("cpusetcpus")
|
|
| 66 |
- cpuSetMems = job.Getenv("cpusetmems")
|
|
| 67 |
- authConfig = ®istry.AuthConfig{}
|
|
| 68 |
- configFile = ®istry.ConfigFile{}
|
|
| 69 |
- tag string |
|
| 70 |
- context io.ReadCloser |
|
| 103 |
+ repoName string |
|
| 104 |
+ tag string |
|
| 105 |
+ context io.ReadCloser |
|
| 71 | 106 |
) |
| 72 | 107 |
|
| 73 |
- job.GetenvJson("authConfig", authConfig)
|
|
| 74 |
- job.GetenvJson("configFile", configFile)
|
|
| 75 |
- |
|
| 76 |
- repoName, tag = parsers.ParseRepositoryTag(repoName) |
|
| 108 |
+ repoName, tag = parsers.ParseRepositoryTag(buildConfig.RepoName) |
|
| 77 | 109 |
if repoName != "" {
|
| 78 |
- if err := registry.ValidateRepositoryName(repoName); err != nil {
|
|
| 110 |
+ if err := registry.ValidateRepositoryName(buildConfig.RepoName); err != nil {
|
|
| 79 | 111 |
return err |
| 80 | 112 |
} |
| 81 | 113 |
if len(tag) > 0 {
|
| ... | ... |
@@ -85,11 +119,11 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) error {
|
| 85 | 85 |
} |
| 86 | 86 |
} |
| 87 | 87 |
|
| 88 |
- if remoteURL == "" {
|
|
| 89 |
- context = ioutil.NopCloser(job.Stdin) |
|
| 90 |
- } else if urlutil.IsGitURL(remoteURL) {
|
|
| 91 |
- if !urlutil.IsGitTransport(remoteURL) {
|
|
| 92 |
- remoteURL = "https://" + remoteURL |
|
| 88 |
+ if buildConfig.RemoteURL == "" {
|
|
| 89 |
+ context = ioutil.NopCloser(buildConfig.Stdin) |
|
| 90 |
+ } else if urlutil.IsGitURL(buildConfig.RemoteURL) {
|
|
| 91 |
+ if !urlutil.IsGitTransport(buildConfig.RemoteURL) {
|
|
| 92 |
+ buildConfig.RemoteURL = "https://" + buildConfig.RemoteURL |
|
| 93 | 93 |
} |
| 94 | 94 |
root, err := ioutil.TempDir("", "docker-build-git")
|
| 95 | 95 |
if err != nil {
|
| ... | ... |
@@ -97,7 +131,7 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) error {
|
| 97 | 97 |
} |
| 98 | 98 |
defer os.RemoveAll(root) |
| 99 | 99 |
|
| 100 |
- if output, err := exec.Command("git", "clone", "--recursive", remoteURL, root).CombinedOutput(); err != nil {
|
|
| 100 |
+ if output, err := exec.Command("git", "clone", "--recursive", buildConfig.RemoteURL, root).CombinedOutput(); err != nil {
|
|
| 101 | 101 |
return fmt.Errorf("Error trying to use git: %s (%s)", err, output)
|
| 102 | 102 |
} |
| 103 | 103 |
|
| ... | ... |
@@ -106,8 +140,8 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) error {
|
| 106 | 106 |
return err |
| 107 | 107 |
} |
| 108 | 108 |
context = c |
| 109 |
- } else if urlutil.IsURL(remoteURL) {
|
|
| 110 |
- f, err := httputils.Download(remoteURL) |
|
| 109 |
+ } else if urlutil.IsURL(buildConfig.RemoteURL) {
|
|
| 110 |
+ f, err := httputils.Download(buildConfig.RemoteURL) |
|
| 111 | 111 |
if err != nil {
|
| 112 | 112 |
return err |
| 113 | 113 |
} |
| ... | ... |
@@ -119,9 +153,9 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) error {
|
| 119 | 119 |
|
| 120 | 120 |
// When we're downloading just a Dockerfile put it in |
| 121 | 121 |
// the default name - don't allow the client to move/specify it |
| 122 |
- dockerfileName = api.DefaultDockerfileName |
|
| 122 |
+ buildConfig.DockerfileName = api.DefaultDockerfileName |
|
| 123 | 123 |
|
| 124 |
- c, err := archive.Generate(dockerfileName, string(dockerFile)) |
|
| 124 |
+ c, err := archive.Generate(buildConfig.DockerfileName, string(dockerFile)) |
|
| 125 | 125 |
if err != nil {
|
| 126 | 126 |
return err |
| 127 | 127 |
} |
| ... | ... |
@@ -129,35 +163,35 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) error {
|
| 129 | 129 |
} |
| 130 | 130 |
defer context.Close() |
| 131 | 131 |
|
| 132 |
- sf := streamformatter.NewStreamFormatter(job.GetenvBool("json"))
|
|
| 132 |
+ sf := streamformatter.NewStreamFormatter(buildConfig.JSONFormat) |
|
| 133 | 133 |
|
| 134 | 134 |
builder := &Builder{
|
| 135 | 135 |
Daemon: b.Daemon, |
| 136 | 136 |
Engine: b.Engine, |
| 137 | 137 |
OutStream: &streamformatter.StdoutFormater{
|
| 138 |
- Writer: job.Stdout, |
|
| 138 |
+ Writer: buildConfig.Stdout, |
|
| 139 | 139 |
StreamFormatter: sf, |
| 140 | 140 |
}, |
| 141 | 141 |
ErrStream: &streamformatter.StderrFormater{
|
| 142 |
- Writer: job.Stdout, |
|
| 142 |
+ Writer: buildConfig.Stdout, |
|
| 143 | 143 |
StreamFormatter: sf, |
| 144 | 144 |
}, |
| 145 |
- Verbose: !suppressOutput, |
|
| 146 |
- UtilizeCache: !noCache, |
|
| 147 |
- Remove: rm, |
|
| 148 |
- ForceRemove: forceRm, |
|
| 149 |
- Pull: pull, |
|
| 150 |
- OutOld: job.Stdout, |
|
| 145 |
+ Verbose: !buildConfig.SuppressOutput, |
|
| 146 |
+ UtilizeCache: !buildConfig.NoCache, |
|
| 147 |
+ Remove: buildConfig.Remove, |
|
| 148 |
+ ForceRemove: buildConfig.ForceRemove, |
|
| 149 |
+ Pull: buildConfig.Pull, |
|
| 150 |
+ OutOld: buildConfig.Stdout, |
|
| 151 | 151 |
StreamFormatter: sf, |
| 152 |
- AuthConfig: authConfig, |
|
| 153 |
- ConfigFile: configFile, |
|
| 154 |
- dockerfileName: dockerfileName, |
|
| 155 |
- cpuShares: cpuShares, |
|
| 156 |
- cpuSetCpus: cpuSetCpus, |
|
| 157 |
- cpuSetMems: cpuSetMems, |
|
| 158 |
- memory: memory, |
|
| 159 |
- memorySwap: memorySwap, |
|
| 160 |
- cancelled: job.WaitCancelled(), |
|
| 152 |
+ AuthConfig: buildConfig.AuthConfig, |
|
| 153 |
+ ConfigFile: buildConfig.ConfigFile, |
|
| 154 |
+ dockerfileName: buildConfig.DockerfileName, |
|
| 155 |
+ cpuShares: buildConfig.CpuShares, |
|
| 156 |
+ cpuSetCpus: buildConfig.CpuSetCpus, |
|
| 157 |
+ cpuSetMems: buildConfig.CpuSetMems, |
|
| 158 |
+ memory: buildConfig.Memory, |
|
| 159 |
+ memorySwap: buildConfig.MemorySwap, |
|
| 160 |
+ cancelled: buildConfig.WaitCancelled(), |
|
| 161 | 161 |
} |
| 162 | 162 |
|
| 163 | 163 |
id, err := builder.Run(context) |