1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

builder: add an option for specifying build target

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi 2017-04-10 15:27:42 -07:00
parent 778e32a2fa
commit 33e07f41ad
7 changed files with 55 additions and 4 deletions

View file

@ -56,6 +56,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
options.ExtraHosts = r.Form["extrahosts"] options.ExtraHosts = r.Form["extrahosts"]
options.SecurityOpt = r.Form["securityopt"] options.SecurityOpt = r.Form["securityopt"]
options.Squash = httputils.BoolValue(r, "squash") options.Squash = httputils.BoolValue(r, "squash")
options.Target = r.FormValue("target")
if r.Form.Get("shmsize") != "" { if r.Form.Get("shmsize") != "" {
shmSize, err := strconv.ParseInt(r.Form.Get("shmsize"), 10, 64) shmSize, err := strconv.ParseInt(r.Form.Get("shmsize"), 10, 64)

View file

@ -176,6 +176,7 @@ type ImageBuildOptions struct {
CacheFrom []string CacheFrom []string
SecurityOpt []string SecurityOpt []string
ExtraHosts []string // List of extra hosts ExtraHosts []string // List of extra hosts
Target string
} }
// ImageBuildResponse holds information // ImageBuildResponse holds information

View file

@ -16,6 +16,7 @@ import (
"github.com/docker/docker/api/types/backend" "github.com/docker/docker/api/types/backend"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/builder" "github.com/docker/docker/builder"
"github.com/docker/docker/builder/dockerfile/command"
"github.com/docker/docker/builder/dockerfile/parser" "github.com/docker/docker/builder/dockerfile/parser"
"github.com/docker/docker/image" "github.com/docker/docker/image"
"github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/stringid"
@ -253,6 +254,10 @@ func (b *Builder) build(stdout io.Writer, stderr io.Writer, out io.Writer) (stri
// Not cancelled yet, keep going... // Not cancelled yet, keep going...
} }
if command.From == n.Value && b.imageContexts.isCurrentTarget(b.options.Target) {
break
}
if err := b.dispatch(i, total, n); err != nil { if err := b.dispatch(i, total, n); err != nil {
if b.options.ForceRemove { if b.options.ForceRemove {
b.clearTmp() b.clearTmp()
@ -267,6 +272,10 @@ func (b *Builder) build(stdout io.Writer, stderr io.Writer, out io.Writer) (stri
} }
} }
if b.options.Target != "" && !b.imageContexts.isCurrentTarget(b.options.Target) {
return "", perrors.Errorf("failed to reach build target %s in Dockerfile", b.options.Target)
}
b.warnOnUnusedBuildArgs() b.warnOnUnusedBuildArgs()
if b.image == "" { if b.image == "" {

View file

@ -19,6 +19,7 @@ type imageContexts struct {
list []*imageMount list []*imageMount
byName map[string]*imageMount byName map[string]*imageMount
cache *pathCache cache *pathCache
currentName string
} }
func (ic *imageContexts) new(name string, increment bool) (*imageMount, error) { func (ic *imageContexts) new(name string, increment bool) (*imageMount, error) {
@ -35,6 +36,7 @@ func (ic *imageContexts) new(name string, increment bool) (*imageMount, error) {
if increment { if increment {
ic.list = append(ic.list, im) ic.list = append(ic.list, im)
} }
ic.currentName = name
return im, nil return im, nil
} }
@ -88,6 +90,13 @@ func (ic *imageContexts) unmount() (retErr error) {
return return
} }
func (ic *imageContexts) isCurrentTarget(target string) bool {
if target == "" {
return false
}
return strings.EqualFold(ic.currentName, target)
}
func (ic *imageContexts) getCache(id, path string) (interface{}, bool) { func (ic *imageContexts) getCache(id, path string) (interface{}, bool) {
if ic.cache != nil { if ic.cache != nil {
if id == "" { if id == "" {

View file

@ -64,6 +64,7 @@ type buildOptions struct {
securityOpt []string securityOpt []string
networkMode string networkMode string
squash bool squash bool
target string
} }
// NewBuildCommand creates a new `docker build` command // NewBuildCommand creates a new `docker build` command
@ -115,6 +116,7 @@ func NewBuildCommand(dockerCli *command.DockerCli) *cobra.Command {
flags.StringVar(&options.networkMode, "network", "default", "Set the networking mode for the RUN instructions during build") flags.StringVar(&options.networkMode, "network", "default", "Set the networking mode for the RUN instructions during build")
flags.SetAnnotation("network", "version", []string{"1.25"}) flags.SetAnnotation("network", "version", []string{"1.25"})
flags.Var(&options.extraHosts, "add-host", "Add a custom host-to-IP mapping (host:ip)") flags.Var(&options.extraHosts, "add-host", "Add a custom host-to-IP mapping (host:ip)")
flags.StringVar(&options.target, "target", "", "Set the target build stage to build.")
command.AddTrustVerificationFlags(flags) command.AddTrustVerificationFlags(flags)
@ -302,6 +304,7 @@ func runBuild(dockerCli *command.DockerCli, options buildOptions) error {
NetworkMode: options.networkMode, NetworkMode: options.networkMode,
Squash: options.squash, Squash: options.squash,
ExtraHosts: options.extraHosts.GetAll(), ExtraHosts: options.extraHosts.GetAll(),
Target: options.target,
} }
response, err := dockerCli.Client().ImageBuild(ctx, body, buildOptions) response, err := dockerCli.Client().ImageBuild(ctx, body, buildOptions)

View file

@ -95,6 +95,7 @@ func (cli *Client) imageBuildOptionsToQuery(options types.ImageBuildOptions) (ur
query.Set("cgroupparent", options.CgroupParent) query.Set("cgroupparent", options.CgroupParent)
query.Set("shmsize", strconv.FormatInt(options.ShmSize, 10)) query.Set("shmsize", strconv.FormatInt(options.ShmSize, 10))
query.Set("dockerfile", options.Dockerfile) query.Set("dockerfile", options.Dockerfile)
query.Set("target", options.Target)
ulimitsJSON, err := json.Marshal(options.Ulimits) ulimitsJSON, err := json.Marshal(options.Ulimits)
if err != nil { if err != nil {

View file

@ -6210,6 +6210,33 @@ func (s *DockerSuite) TestBuildCopyFromWindowsIsCaseInsensitive(c *check.C) {
result.Assert(c, exp) result.Assert(c, exp)
} }
func (s *DockerSuite) TestBuildIntermediateTarget(c *check.C) {
dockerfile := `
FROM busybox AS build-env
CMD ["/dev"]
FROM busybox
CMD ["/dist"]
`
ctx := fakeContext(c, dockerfile, map[string]string{
"Dockerfile": dockerfile,
})
defer ctx.Close()
result := buildImage("build1", withExternalBuildContext(ctx),
cli.WithFlags("--target", "build-env"))
result.Assert(c, icmd.Success)
res := inspectFieldJSON(c, "build1", "Config.Cmd")
c.Assert(res, checker.Equals, `["/dev"]`)
result = buildImage("build1", withExternalBuildContext(ctx),
cli.WithFlags("--target", "nosuchtarget"))
result.Assert(c, icmd.Expected{
ExitCode: 1,
Err: "failed to reach build target",
})
}
// TestBuildOpaqueDirectory tests that a build succeeds which // TestBuildOpaqueDirectory tests that a build succeeds which
// creates opaque directories. // creates opaque directories.
// See https://github.com/docker/docker/issues/25244 // See https://github.com/docker/docker/issues/25244