github.com/rumpl/bof@v23.0.0-rc.2+incompatible/builder/dockerfile/evaluator.go (about) 1 // Package dockerfile is the evaluation step in the Dockerfile parse/evaluate pipeline. 2 // 3 // It incorporates a dispatch table based on the parser.Node values (see the 4 // parser package for more information) that are yielded from the parser itself. 5 // Calling newBuilder with the BuildOpts struct can be used to customize the 6 // experience for execution purposes only. Parsing is controlled in the parser 7 // package, and this division of responsibility should be respected. 8 // 9 // Please see the jump table targets for the actual invocations, most of which 10 // will call out to the functions in internals.go to deal with their tasks. 11 // 12 // ONBUILD is a special case, which is covered in the onbuild() func in 13 // dispatchers.go. 14 // 15 // The evaluator uses the concept of "steps", which are usually each processable 16 // line in the Dockerfile. Each step is numbered and certain actions are taken 17 // before and after each step, such as creating an image ID and removing temporary 18 // containers and images. Note that ONBUILD creates a kinda-sorta "sub run" which 19 // includes its own set of steps (usually only one of them). 20 package dockerfile // import "github.com/docker/docker/builder/dockerfile" 21 22 import ( 23 "reflect" 24 "strconv" 25 "strings" 26 27 "github.com/docker/docker/api/types/container" 28 "github.com/docker/docker/builder" 29 "github.com/docker/docker/errdefs" 30 "github.com/docker/docker/pkg/system" 31 "github.com/docker/docker/runconfig/opts" 32 "github.com/moby/buildkit/frontend/dockerfile/instructions" 33 "github.com/moby/buildkit/frontend/dockerfile/shell" 34 "github.com/pkg/errors" 35 ) 36 37 func dispatch(d dispatchRequest, cmd instructions.Command) (err error) { 38 if c, ok := cmd.(instructions.PlatformSpecific); ok { 39 err := c.CheckPlatform(d.state.operatingSystem) 40 if err != nil { 41 return errdefs.InvalidParameter(err) 42 } 43 } 44 runConfigEnv := d.state.runConfig.Env 45 envs := append(runConfigEnv, d.state.buildArgs.FilterAllowed(runConfigEnv)...) 46 47 if ex, ok := cmd.(instructions.SupportsSingleWordExpansion); ok { 48 err := ex.Expand(func(word string) (string, error) { 49 return d.shlex.ProcessWord(word, envs) 50 }) 51 if err != nil { 52 return errdefs.InvalidParameter(err) 53 } 54 } 55 56 defer func() { 57 if d.builder.options.ForceRemove { 58 d.builder.containerManager.RemoveAll(d.builder.Stdout) 59 return 60 } 61 if d.builder.options.Remove && err == nil { 62 d.builder.containerManager.RemoveAll(d.builder.Stdout) 63 return 64 } 65 }() 66 switch c := cmd.(type) { 67 case *instructions.EnvCommand: 68 return dispatchEnv(d, c) 69 case *instructions.MaintainerCommand: 70 return dispatchMaintainer(d, c) 71 case *instructions.LabelCommand: 72 return dispatchLabel(d, c) 73 case *instructions.AddCommand: 74 return dispatchAdd(d, c) 75 case *instructions.CopyCommand: 76 return dispatchCopy(d, c) 77 case *instructions.OnbuildCommand: 78 return dispatchOnbuild(d, c) 79 case *instructions.WorkdirCommand: 80 return dispatchWorkdir(d, c) 81 case *instructions.RunCommand: 82 return dispatchRun(d, c) 83 case *instructions.CmdCommand: 84 return dispatchCmd(d, c) 85 case *instructions.HealthCheckCommand: 86 return dispatchHealthcheck(d, c) 87 case *instructions.EntrypointCommand: 88 return dispatchEntrypoint(d, c) 89 case *instructions.ExposeCommand: 90 return dispatchExpose(d, c, envs) 91 case *instructions.UserCommand: 92 return dispatchUser(d, c) 93 case *instructions.VolumeCommand: 94 return dispatchVolume(d, c) 95 case *instructions.StopSignalCommand: 96 return dispatchStopSignal(d, c) 97 case *instructions.ArgCommand: 98 return dispatchArg(d, c) 99 case *instructions.ShellCommand: 100 return dispatchShell(d, c) 101 } 102 return errors.Errorf("unsupported command type: %v", reflect.TypeOf(cmd)) 103 } 104 105 // dispatchState is a data object which is modified by dispatchers 106 type dispatchState struct { 107 runConfig *container.Config 108 maintainer string 109 cmdSet bool 110 imageID string 111 baseImage builder.Image 112 stageName string 113 buildArgs *BuildArgs 114 operatingSystem string 115 } 116 117 func newDispatchState(baseArgs *BuildArgs) *dispatchState { 118 args := baseArgs.Clone() 119 args.ResetAllowed() 120 return &dispatchState{runConfig: &container.Config{}, buildArgs: args} 121 } 122 123 type stagesBuildResults struct { 124 flat []*container.Config 125 indexed map[string]*container.Config 126 } 127 128 func newStagesBuildResults() *stagesBuildResults { 129 return &stagesBuildResults{ 130 indexed: make(map[string]*container.Config), 131 } 132 } 133 134 func (r *stagesBuildResults) getByName(name string) (*container.Config, bool) { 135 c, ok := r.indexed[strings.ToLower(name)] 136 return c, ok 137 } 138 139 func (r *stagesBuildResults) validateIndex(i int) error { 140 if i == len(r.flat) { 141 return errors.New("refers to current build stage") 142 } 143 if i < 0 || i > len(r.flat) { 144 return errors.New("index out of bounds") 145 } 146 return nil 147 } 148 149 func (r *stagesBuildResults) get(nameOrIndex string) (*container.Config, error) { 150 if c, ok := r.getByName(nameOrIndex); ok { 151 return c, nil 152 } 153 ix, err := strconv.ParseInt(nameOrIndex, 10, 0) 154 if err != nil { 155 return nil, nil 156 } 157 if err := r.validateIndex(int(ix)); err != nil { 158 return nil, err 159 } 160 return r.flat[ix], nil 161 } 162 163 func (r *stagesBuildResults) checkStageNameAvailable(name string) error { 164 if name != "" { 165 if _, ok := r.getByName(name); ok { 166 return errors.Errorf("%s stage name already used", name) 167 } 168 } 169 return nil 170 } 171 172 func (r *stagesBuildResults) commitStage(name string, config *container.Config) error { 173 if name != "" { 174 if _, ok := r.getByName(name); ok { 175 return errors.Errorf("%s stage name already used", name) 176 } 177 r.indexed[strings.ToLower(name)] = config 178 } 179 r.flat = append(r.flat, config) 180 return nil 181 } 182 183 func commitStage(state *dispatchState, stages *stagesBuildResults) error { 184 return stages.commitStage(state.stageName, state.runConfig) 185 } 186 187 type dispatchRequest struct { 188 state *dispatchState 189 shlex *shell.Lex 190 builder *Builder 191 source builder.Source 192 stages *stagesBuildResults 193 } 194 195 func newDispatchRequest(builder *Builder, escapeToken rune, source builder.Source, buildArgs *BuildArgs, stages *stagesBuildResults) dispatchRequest { 196 return dispatchRequest{ 197 state: newDispatchState(buildArgs), 198 shlex: shell.NewLex(escapeToken), 199 builder: builder, 200 source: source, 201 stages: stages, 202 } 203 } 204 205 func (s *dispatchState) updateRunConfig() { 206 s.runConfig.Image = s.imageID 207 } 208 209 // hasFromImage returns true if the builder has processed a `FROM <image>` line 210 func (s *dispatchState) hasFromImage() bool { 211 return s.imageID != "" || (s.baseImage != nil && s.baseImage.ImageID() == "") 212 } 213 214 func (s *dispatchState) beginStage(stageName string, image builder.Image) error { 215 s.stageName = stageName 216 s.imageID = image.ImageID() 217 s.operatingSystem = image.OperatingSystem() 218 if !system.IsOSSupported(s.operatingSystem) { 219 return system.ErrNotSupportedOperatingSystem 220 } 221 222 if image.RunConfig() != nil { 223 // copy avoids referencing the same instance when 2 stages have the same base 224 s.runConfig = copyRunConfig(image.RunConfig()) 225 } else { 226 s.runConfig = &container.Config{} 227 } 228 s.baseImage = image 229 s.setDefaultPath() 230 s.runConfig.OpenStdin = false 231 s.runConfig.StdinOnce = false 232 return nil 233 } 234 235 // Add the default PATH to runConfig.ENV if one exists for the operating system and there 236 // is no PATH set. Note that Windows containers on Windows won't have one as it's set by HCS 237 func (s *dispatchState) setDefaultPath() { 238 defaultPath := system.DefaultPathEnv(s.operatingSystem) 239 if defaultPath == "" { 240 return 241 } 242 envMap := opts.ConvertKVStringsToMap(s.runConfig.Env) 243 if _, ok := envMap["PATH"]; !ok { 244 s.runConfig.Env = append(s.runConfig.Env, "PATH="+defaultPath) 245 } 246 }