build_config job: parse dockerfile ast into config

Instead of building the actual image, `build_config` will serialize a subset of
dockerfile ast into *runconfig.Config

Docker-DCO-1.1-Signed-off-by: Daniel, Dao Quang Minh <dqminh89@gmail.com> (github: dqminh)

Docker-DCO-1.1-Signed-off-by: Dan Walsh <dwalsh@redhat.com> (github: rhatdan)
This commit is contained in:
Dan Walsh 2015-01-09 16:07:00 -05:00
parent f8e77dfb3d
commit 7f091eca70
3 changed files with 69 additions and 0 deletions

View file

@ -96,6 +96,11 @@ type Builder struct {
ForceRemove bool ForceRemove bool
Pull bool Pull bool
// set this to true if we want the builder to not commit between steps.
// This is useful when we only want to use the evaluator table to generate
// the final configs of the Dockerfile but dont want the layers
disableCommit bool
AuthConfig *registry.AuthConfig AuthConfig *registry.AuthConfig
AuthConfigFile *registry.ConfigFile AuthConfigFile *registry.ConfigFile

View file

@ -60,6 +60,9 @@ func (b *Builder) readContext(context io.Reader) error {
} }
func (b *Builder) commit(id string, autoCmd []string, comment string) error { func (b *Builder) commit(id string, autoCmd []string, comment string) error {
if b.disableCommit {
return nil
}
if b.image == "" && !b.noBaseImage { if b.image == "" && !b.noBaseImage {
return fmt.Errorf("Please provide a source image with `from` prior to commit") return fmt.Errorf("Please provide a source image with `from` prior to commit")
} }

View file

@ -1,12 +1,16 @@
package builder package builder
import ( import (
"bytes"
"encoding/json"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
"github.com/docker/docker/api" "github.com/docker/docker/api"
"github.com/docker/docker/builder/parser"
"github.com/docker/docker/daemon" "github.com/docker/docker/daemon"
"github.com/docker/docker/engine" "github.com/docker/docker/engine"
"github.com/docker/docker/graph" "github.com/docker/docker/graph"
@ -14,6 +18,7 @@ import (
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/urlutil" "github.com/docker/docker/pkg/urlutil"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/utils" "github.com/docker/docker/utils"
) )
@ -24,6 +29,7 @@ type BuilderJob struct {
func (b *BuilderJob) Install() { func (b *BuilderJob) Install() {
b.Engine.Register("build", b.CmdBuild) b.Engine.Register("build", b.CmdBuild)
b.Engine.Register("build_config", b.CmdBuildConfig)
} }
func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status { func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status {
@ -138,3 +144,58 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status {
} }
return engine.StatusOK return engine.StatusOK
} }
func (b *BuilderJob) CmdBuildConfig(job *engine.Job) engine.Status {
if len(job.Args) != 0 {
return job.Errorf("Usage: %s\n", job.Name)
}
var (
validCmd = map[string]struct{}{
"entrypoint": {},
"cmd": {},
"user": {},
"workdir": {},
"env": {},
"volume": {},
"expose": {},
"onbuild": {},
}
changes = job.Getenv("changes")
newConfig runconfig.Config
)
if err := job.GetenvJson("config", &newConfig); err != nil {
return job.Error(err)
}
ast, err := parser.Parse(bytes.NewBufferString(changes))
if err != nil {
return job.Error(err)
}
builder := &Builder{
Daemon: b.Daemon,
Engine: b.Engine,
Config: &newConfig,
OutStream: ioutil.Discard,
ErrStream: ioutil.Discard,
disableCommit: true,
}
for i, n := range ast.Children {
cmd := n.Value
if _, ok := validCmd[cmd]; ok {
if err := builder.dispatch(i, n); err != nil {
return job.Error(err)
}
} else {
fmt.Fprintf(builder.ErrStream, "# Skipping serialization of instruction %s\n", strings.ToUpper(cmd))
}
}
if err := json.NewEncoder(job.Stdout).Encode(builder.Config); err != nil {
return job.Error(err)
}
return engine.StatusOK
}