diff options
author | Dan Duvall <dduvall@wikimedia.org> | 2017-08-30 09:47:41 -0700 |
---|---|---|
committer | Dan Duvall <dduvall@wikimedia.org> | 2017-09-07 10:01:34 -0700 |
commit | 410085e1f5be759b6a2bfbe08a51dca84aa18e3c (patch) | |
tree | 9c0b1e24953082cfe96e84b0924ba0ac90c67100 /docker | |
parent | 2a19f04679b042567dd7ed9c0208eacbb63b8d26 (diff) | |
download | blubber-410085e1f5be759b6a2bfbe08a51dca84aa18e3c.tar.gz |
Support `copies` config entry for multi-stage builds
Summary:
Support a `copies` variant config entry that will result in a
multi-stage build, copying both shared library files and application
directory from a previously defined variant. This is essentially a
shorthand for two `artifacts` entries that are likely to be idiomatic to
multi-stage build/prod configurations.
Defined a new abstract `build.CopyFrom` instruction and corresponding
`docker.DockerCopyFrom` instruction and refactored the writing of these
Dockerfile lines to be accomplished using an `InstructionsForPhase`
method on `config.ArtifactsConfig`.
Implemented new support for `copies` configuration in
`config.VariantConfig` and an `InstructionsForPhase` method that returns
`build.CopyFrom` instructions for both the shared library and
application directories.
Fixes T174622
Depends on D759
Test Plan:
Run `go test ./...`. Run `blubber blubber.example.yaml production` and ensure
the right `COPY --from` lines are included for the final stage.
Reviewers: thcipriani, mobrovac, hashar, mmodell, #release-engineering-team
Reviewed By: thcipriani, #release-engineering-team
Tags: #release-engineering-team
Maniphest Tasks: T174622
Differential Revision: https://phabricator.wikimedia.org/D768
Diffstat (limited to 'docker')
-rw-r--r-- | docker/compiler.go | 29 | ||||
-rw-r--r-- | docker/instructions.go | 24 | ||||
-rw-r--r-- | docker/instructions_test.go | 12 |
3 files changed, 36 insertions, 29 deletions
diff --git a/docker/compiler.go b/docker/compiler.go index e77691f..2891140 100644 --- a/docker/compiler.go +++ b/docker/compiler.go @@ -17,25 +17,13 @@ func Compile(cfg *config.Config, variant string) *bytes.Buffer { // omit the main stage name unless multi-stage is required below mainStage := "" - // get unique set of artifact/variant dependencies - existing := map[string]bool{} - stages := []string{} - - for _, artifact := range vcfg.Artifacts { - if stage := artifact.From; stage != "" && !existing[stage] { - existing[stage] = true - stages = append(stages, stage) - - mainStage = variant - } - } - - // write multi-stage sections for each artifact/variant dependency - for _, stage := range stages { + // write multi-stage sections for each variant dependency + for _, stage := range vcfg.VariantDependencies() { dependency, err := config.ExpandVariant(cfg, stage) if err == nil { CompileStage(buffer, stage, dependency) + mainStage = variant } } @@ -76,17 +64,6 @@ func CompileStage(buffer *bytes.Buffer, stage string, vcfg *config.VariantConfig Writeln(buffer, "COPY . .") } - // Artifact copying - for _, artifact := range vcfg.Artifacts { - Write(buffer, "COPY ") - - if artifact.From != "" { - Write(buffer, "--from=", artifact.From, " ") - } - - Writeln(buffer, "[\"", artifact.Source, "\", \"", artifact.Destination, "\"]") - } - CompilePhase(buffer, vcfg, build.PhasePostInstall) if len(vcfg.EntryPoint) > 0 { diff --git a/docker/instructions.go b/docker/instructions.go index a93ad11..2b00c1b 100644 --- a/docker/instructions.go +++ b/docker/instructions.go @@ -18,11 +18,16 @@ func NewDockerInstruction(instruction build.Instruction) (DockerInstruction, err var dockerInstruction DockerCopy dockerInstruction.arguments = instruction.Compile() return dockerInstruction, nil + case build.CopyFrom: + var dockerInstruction DockerCopyFrom + dockerInstruction.arguments = instruction.Compile() + return dockerInstruction, nil case build.Env: var dockerInstruction DockerEnv dockerInstruction.arguments = instruction.Compile() return dockerInstruction, nil } + return nil, errors.New("Unable to create DockerInstruction") } @@ -44,7 +49,7 @@ type DockerRun struct{ abstractDockerInstruction } func (dr DockerRun) Compile() string { return fmt.Sprintf( "RUN %s\n", - removeNewlines(strings.Join(dr.arguments, ""))) + join(dr.arguments, "")) } type DockerCopy struct{ abstractDockerInstruction } @@ -52,7 +57,16 @@ type DockerCopy struct{ abstractDockerInstruction } func (dc DockerCopy) Compile() string { return fmt.Sprintf( "COPY [%s]\n", - removeNewlines(strings.Join(dc.arguments, ", "))) + join(dc.arguments, ", ")) +} + +type DockerCopyFrom struct{ abstractDockerInstruction } + +func (dcf DockerCopyFrom) Compile() string { + return fmt.Sprintf( + "COPY --from=%s [%s]\n", + dcf.arguments[0], + join(dcf.arguments[1:], ", ")) } type DockerEnv struct{ abstractDockerInstruction } @@ -60,7 +74,11 @@ type DockerEnv struct{ abstractDockerInstruction } func (de DockerEnv) Compile() string { return fmt.Sprintf( "ENV %s\n", - removeNewlines(strings.Join(de.arguments, " "))) + join(de.arguments, " ")) +} + +func join(arguments []string, delimiter string) string { + return removeNewlines(strings.Join(arguments, delimiter)) } func removeNewlines(instructions string) string { diff --git a/docker/instructions_test.go b/docker/instructions_test.go index c03d48b..fb9116b 100644 --- a/docker/instructions_test.go +++ b/docker/instructions_test.go @@ -46,6 +46,18 @@ func TestCopy(t *testing.T) { assert.Equal(t, "COPY [\"foo1\", \"foo2\", \"bar\"]\n", di.Compile()) } +func TestCopyFrom(t *testing.T) { + i := build.CopyFrom{"foo", build.Copy{[]string{"foo1", "foo2"}, "bar"}} + + di, err := docker.NewDockerInstruction(i) + + var dockerCopyFrom docker.DockerCopyFrom + + assert.Nil(t, err) + assert.IsType(t, dockerCopyFrom, di) + assert.Equal(t, "COPY --from=foo [\"foo1\", \"foo2\", \"bar\"]\n", di.Compile()) +} + func TestEnv(t *testing.T) { i := build.Env{map[string]string{"foo": "bar", "bar": "foo"}} |