2018-02-05 21:05:59 +00:00
|
|
|
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
|
2015-09-06 17:26:40 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2018-04-19 22:30:59 +00:00
|
|
|
"context"
|
2015-09-06 17:26:40 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2018-05-07 05:28:55 +00:00
|
|
|
"sort"
|
2015-09-06 17:26:40 +00:00
|
|
|
"strings"
|
|
|
|
|
2018-07-03 02:31:05 +00:00
|
|
|
"github.com/containerd/containerd/platforms"
|
2023-09-13 15:41:45 +00:00
|
|
|
"github.com/containerd/log"
|
2016-09-06 18:18:12 +00:00
|
|
|
"github.com/docker/docker/api/types"
|
2016-04-13 17:21:00 +00:00
|
|
|
"github.com/docker/docker/api/types/backend"
|
2016-09-06 18:18:12 +00:00
|
|
|
"github.com/docker/docker/api/types/container"
|
2015-09-06 17:26:40 +00:00
|
|
|
"github.com/docker/docker/builder"
|
2017-03-20 22:22:29 +00:00
|
|
|
"github.com/docker/docker/builder/remotecontext"
|
2018-01-11 19:53:06 +00:00
|
|
|
"github.com/docker/docker/errdefs"
|
2017-05-25 21:03:29 +00:00
|
|
|
"github.com/docker/docker/pkg/idtools"
|
2017-04-06 12:33:56 +00:00
|
|
|
"github.com/docker/docker/pkg/streamformatter"
|
2015-09-06 17:26:40 +00:00
|
|
|
"github.com/docker/docker/pkg/stringid"
|
2018-06-02 16:46:53 +00:00
|
|
|
"github.com/moby/buildkit/frontend/dockerfile/instructions"
|
|
|
|
"github.com/moby/buildkit/frontend/dockerfile/parser"
|
|
|
|
"github.com/moby/buildkit/frontend/dockerfile/shell"
|
2023-05-08 09:57:52 +00:00
|
|
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
2017-04-04 16:28:59 +00:00
|
|
|
"github.com/pkg/errors"
|
2017-04-13 18:37:32 +00:00
|
|
|
"golang.org/x/sync/syncmap"
|
2015-09-06 17:26:40 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var validCommitCommands = map[string]bool{
|
2016-04-18 09:48:13 +00:00
|
|
|
"cmd": true,
|
|
|
|
"entrypoint": true,
|
|
|
|
"healthcheck": true,
|
|
|
|
"env": true,
|
|
|
|
"expose": true,
|
|
|
|
"label": true,
|
|
|
|
"onbuild": true,
|
2022-03-12 16:10:35 +00:00
|
|
|
"stopsignal": true,
|
2016-04-18 09:48:13 +00:00
|
|
|
"user": true,
|
|
|
|
"volume": true,
|
|
|
|
"workdir": true,
|
2015-09-06 17:26:40 +00:00
|
|
|
}
|
|
|
|
|
2017-05-22 15:21:17 +00:00
|
|
|
const (
|
|
|
|
stepFormat = "Step %d/%d : %v"
|
|
|
|
)
|
|
|
|
|
2017-04-13 18:37:32 +00:00
|
|
|
// BuildManager is shared across all Builder objects
|
|
|
|
type BuildManager struct {
|
2022-03-14 19:24:29 +00:00
|
|
|
idMapping idtools.IdentityMapping
|
2017-11-16 06:20:33 +00:00
|
|
|
backend builder.Backend
|
|
|
|
pathCache pathCache // TODO: make this persistent
|
2017-04-13 18:37:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewBuildManager creates a BuildManager
|
2022-03-14 19:24:29 +00:00
|
|
|
func NewBuildManager(b builder.Backend, identityMapping idtools.IdentityMapping) (*BuildManager, error) {
|
2017-05-15 21:54:27 +00:00
|
|
|
bm := &BuildManager{
|
2017-11-16 06:20:33 +00:00
|
|
|
backend: b,
|
|
|
|
pathCache: &syncmap.Map{},
|
|
|
|
idMapping: identityMapping,
|
2017-05-15 21:54:27 +00:00
|
|
|
}
|
|
|
|
return bm, nil
|
2017-04-13 18:37:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Build starts a new build from a BuildConfig
|
|
|
|
func (bm *BuildManager) Build(ctx context.Context, config backend.BuildConfig) (*builder.Result, error) {
|
2017-04-24 11:32:01 +00:00
|
|
|
buildsTriggered.Inc()
|
2017-04-13 18:37:32 +00:00
|
|
|
if config.Options.Dockerfile == "" {
|
|
|
|
config.Options.Dockerfile = builder.DefaultDockerfileName
|
|
|
|
}
|
|
|
|
|
|
|
|
source, dockerfile, err := remotecontext.Detect(config)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-05-15 21:54:27 +00:00
|
|
|
defer func() {
|
|
|
|
if source != nil {
|
2017-04-13 18:37:32 +00:00
|
|
|
if err := source.Close(); err != nil {
|
2023-06-23 00:33:17 +00:00
|
|
|
log.G(ctx).Debugf("[BUILDER] failed to remove temporary context: %v", err)
|
2017-04-13 18:37:32 +00:00
|
|
|
}
|
2017-05-15 21:54:27 +00:00
|
|
|
}
|
|
|
|
}()
|
2017-04-13 18:37:32 +00:00
|
|
|
|
2017-05-15 19:59:15 +00:00
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
|
|
defer cancel()
|
|
|
|
|
2017-04-13 18:37:32 +00:00
|
|
|
builderOptions := builderOptions{
|
|
|
|
Options: config.Options,
|
|
|
|
ProgressWriter: config.ProgressWriter,
|
|
|
|
Backend: bm.backend,
|
|
|
|
PathCache: bm.pathCache,
|
2017-11-16 06:20:33 +00:00
|
|
|
IDMapping: bm.idMapping,
|
2017-04-13 18:37:32 +00:00
|
|
|
}
|
2018-07-03 02:31:05 +00:00
|
|
|
b, err := newBuilder(ctx, builderOptions)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-10-26 16:13:17 +00:00
|
|
|
return b.build(ctx, source, dockerfile)
|
2017-04-13 18:37:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// builderOptions are the dependencies required by the builder
|
|
|
|
type builderOptions struct {
|
|
|
|
Options *types.ImageBuildOptions
|
|
|
|
Backend builder.Backend
|
|
|
|
ProgressWriter backend.ProgressWriter
|
|
|
|
PathCache pathCache
|
2022-03-14 19:24:29 +00:00
|
|
|
IDMapping idtools.IdentityMapping
|
2017-04-13 18:37:32 +00:00
|
|
|
}
|
|
|
|
|
2015-09-06 17:26:40 +00:00
|
|
|
// Builder is a Dockerfile builder
|
2015-12-18 00:17:50 +00:00
|
|
|
// It implements the builder.Backend interface.
|
2015-09-06 17:26:40 +00:00
|
|
|
type Builder struct {
|
2015-12-29 20:49:17 +00:00
|
|
|
options *types.ImageBuildOptions
|
2015-09-06 17:26:40 +00:00
|
|
|
|
|
|
|
Stdout io.Writer
|
|
|
|
Stderr io.Writer
|
2017-04-06 12:33:56 +00:00
|
|
|
Aux *streamformatter.AuxFormatter
|
2016-01-20 23:32:02 +00:00
|
|
|
Output io.Writer
|
2015-09-06 17:26:40 +00:00
|
|
|
|
2022-10-28 11:40:06 +00:00
|
|
|
docker builder.Backend
|
2015-09-06 17:26:40 +00:00
|
|
|
|
2022-03-14 19:24:29 +00:00
|
|
|
idMapping idtools.IdentityMapping
|
2017-04-13 22:44:36 +00:00
|
|
|
disableCommit bool
|
|
|
|
imageSources *imageSources
|
|
|
|
pathCache pathCache
|
|
|
|
containerManager *containerManager
|
|
|
|
imageProber ImageProber
|
2023-05-08 09:57:52 +00:00
|
|
|
platform *ocispec.Platform
|
2016-01-20 23:32:02 +00:00
|
|
|
}
|
|
|
|
|
2017-04-13 18:37:32 +00:00
|
|
|
// newBuilder creates a new Dockerfile builder from an optional dockerfile and a Options.
|
2022-10-28 11:40:06 +00:00
|
|
|
func newBuilder(ctx context.Context, options builderOptions) (*Builder, error) {
|
2017-04-13 18:37:32 +00:00
|
|
|
config := options.Options
|
2015-09-06 17:26:40 +00:00
|
|
|
if config == nil {
|
2015-12-29 20:49:17 +00:00
|
|
|
config = new(types.ImageBuildOptions)
|
2015-09-06 17:26:40 +00:00
|
|
|
}
|
2017-05-18 00:08:01 +00:00
|
|
|
|
2022-10-28 11:40:06 +00:00
|
|
|
imageProber, err := newImageProber(ctx, options.Backend, config.CacheFrom, config.NoCache)
|
2022-10-26 16:13:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-04-13 18:37:32 +00:00
|
|
|
b := &Builder{
|
2017-04-13 22:44:36 +00:00
|
|
|
options: config,
|
|
|
|
Stdout: options.ProgressWriter.StdoutFormatter,
|
|
|
|
Stderr: options.ProgressWriter.StderrFormatter,
|
|
|
|
Aux: options.ProgressWriter.AuxFormatter,
|
|
|
|
Output: options.ProgressWriter.Output,
|
|
|
|
docker: options.Backend,
|
2017-11-16 06:20:33 +00:00
|
|
|
idMapping: options.IDMapping,
|
2022-10-28 11:40:06 +00:00
|
|
|
imageSources: newImageSources(options),
|
2017-04-13 22:44:36 +00:00
|
|
|
pathCache: options.PathCache,
|
2022-10-26 16:13:17 +00:00
|
|
|
imageProber: imageProber,
|
2017-04-13 22:44:36 +00:00
|
|
|
containerManager: newContainerManager(options.Backend),
|
2015-09-06 17:26:40 +00:00
|
|
|
}
|
2017-05-18 00:08:01 +00:00
|
|
|
|
2018-07-03 02:31:05 +00:00
|
|
|
// same as in Builder.Build in builder/builder-next/builder.go
|
|
|
|
// TODO: remove once config.Platform is of type specs.Platform
|
|
|
|
if config.Platform != "" {
|
|
|
|
sp, err := platforms.Parse(config.Platform)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
b.platform = &sp
|
|
|
|
}
|
|
|
|
|
|
|
|
return b, nil
|
2015-09-06 17:26:40 +00:00
|
|
|
}
|
|
|
|
|
2018-05-07 05:28:55 +00:00
|
|
|
// Build 'LABEL' command(s) from '--label' options and add to the last stage
|
|
|
|
func buildLabelOptions(labels map[string]string, stages []instructions.Stage) {
|
|
|
|
keys := []string{}
|
|
|
|
for key := range labels {
|
|
|
|
keys = append(keys, key)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort the label to have a repeatable order
|
|
|
|
sort.Strings(keys)
|
|
|
|
for _, key := range keys {
|
|
|
|
value := labels[key]
|
|
|
|
stages[len(stages)-1].AddCommand(instructions.NewLabelCommand(key, value, true))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-13 18:37:32 +00:00
|
|
|
// Build runs the Dockerfile builder by parsing the Dockerfile and executing
|
|
|
|
// the instructions from the file.
|
2022-10-26 16:13:17 +00:00
|
|
|
func (b *Builder) build(ctx context.Context, source builder.Source, dockerfile *parser.Result) (*builder.Result, error) {
|
2017-05-05 22:52:11 +00:00
|
|
|
defer b.imageSources.Unmount()
|
2017-03-15 22:28:06 +00:00
|
|
|
|
2017-05-22 15:21:17 +00:00
|
|
|
stages, metaArgs, err := instructions.Parse(dockerfile.AST)
|
|
|
|
if err != nil {
|
2022-03-18 15:01:18 +00:00
|
|
|
var uiErr *instructions.UnknownInstructionError
|
2020-06-15 05:28:06 +00:00
|
|
|
if errors.As(err, &uiErr) {
|
2017-05-22 15:21:17 +00:00
|
|
|
buildsFailed.WithValues(metricsUnknownInstructionError).Inc()
|
|
|
|
}
|
2017-11-29 04:09:37 +00:00
|
|
|
return nil, errdefs.InvalidParameter(err)
|
2017-04-04 20:34:19 +00:00
|
|
|
}
|
2017-05-22 15:21:17 +00:00
|
|
|
if b.options.Target != "" {
|
|
|
|
targetIx, found := instructions.HasStage(stages, b.options.Target)
|
|
|
|
if !found {
|
|
|
|
buildsFailed.WithValues(metricsBuildTargetNotReachableError).Inc()
|
2023-11-01 11:18:40 +00:00
|
|
|
return nil, errdefs.InvalidParameter(errors.Errorf("target stage %q could not be found", b.options.Target))
|
2017-05-22 15:21:17 +00:00
|
|
|
}
|
|
|
|
stages = stages[:targetIx+1]
|
|
|
|
}
|
2017-04-04 20:34:19 +00:00
|
|
|
|
2018-05-07 05:28:55 +00:00
|
|
|
// Add 'LABEL' command specified by '--label' option to the last stage
|
|
|
|
buildLabelOptions(b.options.Labels, stages)
|
|
|
|
|
2017-05-22 15:21:17 +00:00
|
|
|
dockerfile.PrintWarnings(b.Stderr)
|
2022-10-26 16:13:17 +00:00
|
|
|
dispatchState, err := b.dispatchDockerfileWithCancellation(ctx, stages, metaArgs, dockerfile.EscapeToken, source)
|
2017-04-04 20:34:19 +00:00
|
|
|
if err != nil {
|
2017-04-13 18:37:32 +00:00
|
|
|
return nil, err
|
2017-04-04 20:34:19 +00:00
|
|
|
}
|
2017-04-26 21:45:16 +00:00
|
|
|
if dispatchState.imageID == "" {
|
2017-04-24 11:32:01 +00:00
|
|
|
buildsFailed.WithValues(metricsDockerfileEmptyError).Inc()
|
2017-04-13 18:37:32 +00:00
|
|
|
return nil, errors.New("No image was generated. Is your Dockerfile empty?")
|
2017-04-04 20:34:19 +00:00
|
|
|
}
|
2017-04-26 21:45:16 +00:00
|
|
|
return &builder.Result{ImageID: dispatchState.imageID, FromImage: dispatchState.baseImage}, nil
|
2017-04-04 20:34:19 +00:00
|
|
|
}
|
|
|
|
|
2017-04-06 12:33:56 +00:00
|
|
|
func emitImageID(aux *streamformatter.AuxFormatter, state *dispatchState) error {
|
|
|
|
if aux == nil || state.imageID == "" {
|
|
|
|
return nil
|
|
|
|
}
|
2018-06-11 18:48:42 +00:00
|
|
|
return aux.Emit("", types.BuildResult{ID: state.imageID})
|
2017-04-06 12:33:56 +00:00
|
|
|
}
|
|
|
|
|
2018-05-07 17:49:13 +00:00
|
|
|
func processMetaArg(meta instructions.ArgCommand, shlex *shell.Lex, args *BuildArgs) error {
|
2018-01-30 23:58:21 +00:00
|
|
|
// shell.Lex currently only support the concatenated string format
|
2017-05-22 15:21:17 +00:00
|
|
|
envs := convertMapToEnvList(args.GetAllAllowed())
|
|
|
|
if err := meta.Expand(func(word string) (string, error) {
|
|
|
|
return shlex.ProcessWord(word, envs)
|
|
|
|
}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-11-13 02:14:57 +00:00
|
|
|
for _, arg := range meta.Args {
|
|
|
|
args.AddArg(arg.Key, arg.Value)
|
|
|
|
args.AddMetaArg(arg.Key, arg.Value)
|
|
|
|
}
|
2017-05-22 15:21:17 +00:00
|
|
|
return nil
|
|
|
|
}
|
2016-09-13 04:06:04 +00:00
|
|
|
|
2017-05-22 15:21:17 +00:00
|
|
|
func printCommand(out io.Writer, currentCommandIndex int, totalCommands int, cmd interface{}) int {
|
|
|
|
fmt.Fprintf(out, stepFormat, currentCommandIndex, totalCommands, cmd)
|
|
|
|
fmt.Fprintln(out)
|
|
|
|
return currentCommandIndex + 1
|
|
|
|
}
|
|
|
|
|
2022-10-26 16:13:17 +00:00
|
|
|
func (b *Builder) dispatchDockerfileWithCancellation(ctx context.Context, parseResult []instructions.Stage, metaArgs []instructions.ArgCommand, escapeToken rune, source builder.Source) (*dispatchState, error) {
|
2017-05-22 15:21:17 +00:00
|
|
|
dispatchRequest := dispatchRequest{}
|
2018-05-07 17:49:13 +00:00
|
|
|
buildArgs := NewBuildArgs(b.options.BuildArgs)
|
2017-05-22 15:21:17 +00:00
|
|
|
totalCommands := len(metaArgs) + len(parseResult)
|
|
|
|
currentCommandIndex := 1
|
|
|
|
for _, stage := range parseResult {
|
|
|
|
totalCommands += len(stage.Commands)
|
|
|
|
}
|
2018-01-30 23:58:21 +00:00
|
|
|
shlex := shell.NewLex(escapeToken)
|
2021-04-16 15:21:26 +00:00
|
|
|
for i := range metaArgs {
|
|
|
|
currentCommandIndex = printCommand(b.Stdout, currentCommandIndex, totalCommands, &metaArgs[i])
|
2017-05-22 15:21:17 +00:00
|
|
|
|
2021-04-16 15:21:26 +00:00
|
|
|
err := processMetaArg(metaArgs[i], shlex, buildArgs)
|
2017-05-22 15:21:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2017-04-06 12:33:56 +00:00
|
|
|
}
|
2017-05-22 15:21:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
stagesResults := newStagesBuildResults()
|
2017-04-06 12:33:56 +00:00
|
|
|
|
2021-04-16 15:21:26 +00:00
|
|
|
for _, s := range parseResult {
|
|
|
|
stage := s
|
2017-05-22 15:21:17 +00:00
|
|
|
if err := stagesResults.checkStageNameAvailable(stage.Name); err != nil {
|
|
|
|
return nil, err
|
2017-04-10 22:27:42 +00:00
|
|
|
}
|
2017-05-22 15:21:17 +00:00
|
|
|
dispatchRequest = newDispatchRequest(b, escapeToken, source, buildArgs, stagesResults)
|
2017-04-10 22:27:42 +00:00
|
|
|
|
2017-05-22 15:21:17 +00:00
|
|
|
currentCommandIndex = printCommand(b.Stdout, currentCommandIndex, totalCommands, stage.SourceCode)
|
2022-10-26 16:13:17 +00:00
|
|
|
if err := initializeStage(ctx, dispatchRequest, &stage); err != nil {
|
2017-05-22 15:21:17 +00:00
|
|
|
return nil, err
|
2017-04-26 21:45:16 +00:00
|
|
|
}
|
2017-05-22 15:21:17 +00:00
|
|
|
dispatchRequest.state.updateRunConfig()
|
|
|
|
fmt.Fprintf(b.Stdout, " ---> %s\n", stringid.TruncateID(dispatchRequest.state.imageID))
|
|
|
|
for _, cmd := range stage.Commands {
|
|
|
|
select {
|
2022-10-28 11:40:06 +00:00
|
|
|
case <-ctx.Done():
|
2023-06-23 00:33:17 +00:00
|
|
|
log.G(ctx).Debug("Builder: build cancelled!")
|
2017-05-22 15:21:17 +00:00
|
|
|
fmt.Fprint(b.Stdout, "Build cancelled\n")
|
|
|
|
buildsFailed.WithValues(metricsBuildCanceled).Inc()
|
|
|
|
return nil, errors.New("Build cancelled")
|
|
|
|
default:
|
|
|
|
// Not cancelled yet, keep going...
|
2015-09-06 17:26:40 +00:00
|
|
|
}
|
2017-05-22 15:21:17 +00:00
|
|
|
|
|
|
|
currentCommandIndex = printCommand(b.Stdout, currentCommandIndex, totalCommands, cmd)
|
|
|
|
|
2022-10-26 16:13:17 +00:00
|
|
|
if err := dispatch(ctx, dispatchRequest, cmd); err != nil {
|
2017-05-22 15:21:17 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
dispatchRequest.state.updateRunConfig()
|
|
|
|
fmt.Fprintf(b.Stdout, " ---> %s\n", stringid.TruncateID(dispatchRequest.state.imageID))
|
|
|
|
}
|
|
|
|
if err := emitImageID(b.Aux, dispatchRequest.state); err != nil {
|
2017-04-26 21:45:16 +00:00
|
|
|
return nil, err
|
2015-09-06 17:26:40 +00:00
|
|
|
}
|
2017-05-22 15:21:17 +00:00
|
|
|
buildArgs.MergeReferencedArgs(dispatchRequest.state.buildArgs)
|
|
|
|
if err := commitStage(dispatchRequest.state, stagesResults); err != nil {
|
|
|
|
return nil, err
|
2015-09-06 17:26:40 +00:00
|
|
|
}
|
|
|
|
}
|
2017-05-22 15:21:17 +00:00
|
|
|
buildArgs.WarnOnUnusedBuildArgs(b.Stdout)
|
|
|
|
return dispatchRequest.state, nil
|
2017-04-04 20:34:19 +00:00
|
|
|
}
|
2015-09-06 17:26:40 +00:00
|
|
|
|
2016-01-29 19:28:30 +00:00
|
|
|
// BuildFromConfig builds directly from `changes`, treating it as if it were the contents of a Dockerfile
|
|
|
|
// It will:
|
2016-01-05 13:33:20 +00:00
|
|
|
// - Call parse.Parse() to get an AST root for the concatenated Dockerfile entries.
|
|
|
|
// - Do build by calling builder.dispatch() to call all entries' handling routines
|
|
|
|
//
|
|
|
|
// BuildFromConfig is used by the /commit endpoint, with the changes
|
|
|
|
// coming from the query parameter of the same name.
|
|
|
|
//
|
|
|
|
// TODO: Remove?
|
2022-10-26 16:13:17 +00:00
|
|
|
func BuildFromConfig(ctx context.Context, config *container.Config, changes []string, os string) (*container.Config, error) {
|
2017-04-21 19:08:11 +00:00
|
|
|
if len(changes) == 0 {
|
|
|
|
return config, nil
|
|
|
|
}
|
|
|
|
|
2017-04-26 21:45:16 +00:00
|
|
|
dockerfile, err := parser.Parse(bytes.NewBufferString(strings.Join(changes, "\n")))
|
2015-09-06 17:26:40 +00:00
|
|
|
if err != nil {
|
2017-11-29 04:09:37 +00:00
|
|
|
return nil, errdefs.InvalidParameter(err)
|
2015-09-06 17:26:40 +00:00
|
|
|
}
|
|
|
|
|
2022-10-26 16:13:17 +00:00
|
|
|
b, err := newBuilder(ctx, builderOptions{
|
2017-08-08 19:43:48 +00:00
|
|
|
Options: &types.ImageBuildOptions{NoCache: true},
|
2017-08-24 18:48:16 +00:00
|
|
|
})
|
2018-07-03 02:31:05 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-05-18 00:08:01 +00:00
|
|
|
|
2015-09-06 17:26:40 +00:00
|
|
|
// ensure that the commands are valid
|
2017-04-26 21:45:16 +00:00
|
|
|
for _, n := range dockerfile.AST.Children {
|
2022-03-18 15:01:18 +00:00
|
|
|
if !validCommitCommands[strings.ToLower(n.Value)] {
|
2017-11-29 04:09:37 +00:00
|
|
|
return nil, errdefs.InvalidParameter(errors.Errorf("%s is not a valid change command", n.Value))
|
2015-09-06 17:26:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-24 10:10:50 +00:00
|
|
|
b.Stdout = io.Discard
|
|
|
|
b.Stderr = io.Discard
|
2015-09-06 17:26:40 +00:00
|
|
|
b.disableCommit = true
|
|
|
|
|
2018-05-19 11:38:54 +00:00
|
|
|
var commands []instructions.Command
|
2017-05-22 15:21:17 +00:00
|
|
|
for _, n := range dockerfile.AST.Children {
|
|
|
|
cmd, err := instructions.ParseCommand(n)
|
|
|
|
if err != nil {
|
2017-11-29 04:09:37 +00:00
|
|
|
return nil, errdefs.InvalidParameter(err)
|
2017-05-22 15:21:17 +00:00
|
|
|
}
|
|
|
|
commands = append(commands, cmd)
|
2017-04-04 20:34:19 +00:00
|
|
|
}
|
|
|
|
|
2018-05-07 17:49:13 +00:00
|
|
|
dispatchRequest := newDispatchRequest(b, dockerfile.EscapeToken, nil, NewBuildArgs(b.options.BuildArgs), newStagesBuildResults())
|
2017-11-22 21:31:26 +00:00
|
|
|
// We make mutations to the configuration, ensure we have a copy
|
|
|
|
dispatchRequest.state.runConfig = copyRunConfig(config)
|
2017-05-22 15:21:17 +00:00
|
|
|
dispatchRequest.state.imageID = config.Image
|
2017-09-19 19:14:46 +00:00
|
|
|
dispatchRequest.state.operatingSystem = os
|
2017-05-22 15:21:17 +00:00
|
|
|
for _, cmd := range commands {
|
2022-10-26 16:13:17 +00:00
|
|
|
err := dispatch(ctx, dispatchRequest, cmd)
|
2017-05-22 15:21:17 +00:00
|
|
|
if err != nil {
|
2017-11-29 04:09:37 +00:00
|
|
|
return nil, errdefs.InvalidParameter(err)
|
2016-09-13 04:06:04 +00:00
|
|
|
}
|
2017-05-22 15:21:17 +00:00
|
|
|
dispatchRequest.state.updateRunConfig()
|
2016-09-13 04:06:04 +00:00
|
|
|
}
|
2017-05-22 15:21:17 +00:00
|
|
|
|
|
|
|
return dispatchRequest.state.runConfig, nil
|
2017-04-04 20:34:19 +00:00
|
|
|
}
|
2016-09-13 04:06:04 +00:00
|
|
|
|
2017-05-22 15:21:17 +00:00
|
|
|
func convertMapToEnvList(m map[string]string) []string {
|
|
|
|
result := []string{}
|
|
|
|
for k, v := range m {
|
|
|
|
result = append(result, k+"="+v)
|
2015-09-06 17:26:40 +00:00
|
|
|
}
|
2017-05-22 15:21:17 +00:00
|
|
|
return result
|
2015-09-06 17:26:40 +00:00
|
|
|
}
|