dockerfile: clean up converter
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>docker-18.09
parent
aaff9d591e
commit
d258bcab7b
|
@ -162,7 +162,7 @@ func (cm *cacheManager) load(ctx context.Context, id string, opts ...RefOption)
|
|||
|
||||
if err := initializeMetadata(rec, opts...); err != nil {
|
||||
if parent != nil {
|
||||
parent.Release(ctx)
|
||||
parent.Release(context.TODO())
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ func (cm *cacheManager) New(ctx context.Context, s ImmutableRef, opts ...RefOpti
|
|||
|
||||
if _, err := cm.Snapshotter.Prepare(ctx, id, parentID); err != nil {
|
||||
if parent != nil {
|
||||
parent.Release(ctx)
|
||||
parent.Release(context.TODO())
|
||||
}
|
||||
return nil, errors.Wrapf(err, "failed to prepare %s", id)
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ func (cm *cacheManager) New(ctx context.Context, s ImmutableRef, opts ...RefOpti
|
|||
|
||||
if err := initializeMetadata(rec, opts...); err != nil {
|
||||
if parent != nil {
|
||||
parent.Release(ctx)
|
||||
parent.Release(context.TODO())
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -16,28 +16,31 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
keyTarget = "target"
|
||||
keyFilename = "filename"
|
||||
exporterImageConfig = "containerimage.config"
|
||||
keyTarget = "target"
|
||||
keyFilename = "filename"
|
||||
exporterImageConfig = "containerimage.config"
|
||||
defaultDockerfileName = "Dockerfile"
|
||||
localNameDockerfile = "dockerfile"
|
||||
buildArgPrefix = "build-arg:"
|
||||
)
|
||||
|
||||
type dfFrontend struct{}
|
||||
|
||||
func NewDockerfileFrontend() frontend.Frontend {
|
||||
return &dfFrontend{}
|
||||
}
|
||||
|
||||
type dfFrontend struct{}
|
||||
|
||||
func (f *dfFrontend) Solve(ctx context.Context, llbBridge frontend.FrontendLLBBridge, opts map[string]string) (retRef cache.ImmutableRef, exporterAttr map[string]interface{}, retErr error) {
|
||||
|
||||
filename := opts[keyFilename]
|
||||
if filename == "" {
|
||||
filename = "Dockerfile"
|
||||
filename = defaultDockerfileName
|
||||
}
|
||||
if path.Base(filename) != filename {
|
||||
return nil, nil, errors.Errorf("invalid filename %s", filename)
|
||||
}
|
||||
|
||||
src := llb.Local("dockerfile", llb.IncludePatterns([]string{filename}))
|
||||
src := llb.Local(localNameDockerfile, llb.IncludePatterns([]string{filename}))
|
||||
dt, err := src.Marshal()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -82,7 +85,7 @@ func (f *dfFrontend) Solve(ctx context.Context, llbBridge frontend.FrontendLLBBr
|
|||
}
|
||||
lm = nil
|
||||
|
||||
if err := ref.Release(ctx); err != nil {
|
||||
if err := ref.Release(context.TODO()); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ref = nil
|
||||
|
@ -115,8 +118,8 @@ func (f *dfFrontend) Solve(ctx context.Context, llbBridge frontend.FrontendLLBBr
|
|||
func filterBuildArgs(opt map[string]string) map[string]string {
|
||||
m := map[string]string{}
|
||||
for k, v := range opt {
|
||||
if strings.HasPrefix(k, "build-arg:") {
|
||||
m[strings.TrimPrefix(k, "build-arg:")] = v
|
||||
if strings.HasPrefix(k, buildArgPrefix) {
|
||||
m[strings.TrimPrefix(k, buildArgPrefix)] = v
|
||||
}
|
||||
}
|
||||
return m
|
||||
|
|
|
@ -20,7 +20,8 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
emptyImageName = "scratch"
|
||||
emptyImageName = "scratch"
|
||||
localNameContext = "context"
|
||||
)
|
||||
|
||||
type ConvertOpt struct {
|
||||
|
@ -45,16 +46,17 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
|
|||
}
|
||||
|
||||
for i := range metaArgs {
|
||||
metaArgs[i] = setArgValue(metaArgs[i], opt.BuildArgs)
|
||||
metaArgs[i] = setBuildArgValue(metaArgs[i], opt.BuildArgs)
|
||||
}
|
||||
|
||||
shlex := NewShellLex(dockerfile.EscapeToken)
|
||||
|
||||
var allStages []*dispatchState
|
||||
stagesByName := map[string]*dispatchState{}
|
||||
var allDispatchStates []*dispatchState
|
||||
dispatchStatesByName := map[string]*dispatchState{}
|
||||
|
||||
// set base state for every image
|
||||
for _, st := range stages {
|
||||
name, err := shlex.ProcessWord(st.BaseName, combineArgs([]string{}, metaArgs))
|
||||
name, err := shlex.ProcessWord(st.BaseName, toEnvList(metaArgs, nil))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -68,13 +70,13 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
|
|||
state: state,
|
||||
stage: st,
|
||||
}
|
||||
if d, ok := stagesByName[st.BaseName]; ok {
|
||||
if d, ok := dispatchStatesByName[st.BaseName]; ok {
|
||||
ds.base = d
|
||||
}
|
||||
|
||||
allStages = append(allStages, ds)
|
||||
allDispatchStates = append(allDispatchStates, ds)
|
||||
if st.Name != "" {
|
||||
stagesByName[strings.ToLower(st.Name)] = ds
|
||||
dispatchStatesByName[strings.ToLower(st.Name)] = ds
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,7 +86,8 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
|
|||
}
|
||||
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
for i, d := range allStages {
|
||||
for i, d := range allDispatchStates {
|
||||
// resolve image config for every stage
|
||||
if d.base == nil && d.stage.BaseName != emptyImageName {
|
||||
func(i int, d *dispatchState) {
|
||||
eg.Go(func() error {
|
||||
|
@ -103,7 +106,7 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
|
|||
if err := json.Unmarshal(dt, &img); err != nil {
|
||||
return err
|
||||
}
|
||||
allStages[i].image = img
|
||||
allDispatchStates[i].image = img
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
@ -115,14 +118,15 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
for _, d := range allStages {
|
||||
for _, d := range allDispatchStates {
|
||||
if d.base != nil {
|
||||
d.state = d.base.state
|
||||
d.image = clone(d.base.image)
|
||||
}
|
||||
|
||||
var args []instructions.ArgCommand
|
||||
var buildArgs []instructions.ArgCommand
|
||||
|
||||
// initialize base metadata from image conf
|
||||
for _, env := range d.image.Config.Env {
|
||||
parts := strings.SplitN(env, "=", 2)
|
||||
v := ""
|
||||
|
@ -138,11 +142,16 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
|
|||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
if d.image.Config.User != "" {
|
||||
if err = dispatchUser(d, &instructions.UserCommand{User: d.image.Config.User}); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, cmd := range d.stage.Commands {
|
||||
if ex, ok := cmd.(instructions.SupportsSingleWordExpansion); ok {
|
||||
err := ex.Expand(func(word string) (string, error) {
|
||||
return shlex.ProcessWord(word, combineArgs(d.image.Config.Env, args))
|
||||
return shlex.ProcessWord(word, toEnvList(buildArgs, d.image.Config.Env))
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -153,11 +162,11 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
|
|||
case *instructions.EnvCommand:
|
||||
err = dispatchEnv(d, c)
|
||||
case *instructions.RunCommand:
|
||||
err = dispatchRun(d, c, args)
|
||||
err = dispatchRun(d, c, buildArgs)
|
||||
case *instructions.WorkdirCommand:
|
||||
err = dispatchWorkdir(d, c)
|
||||
case *instructions.AddCommand:
|
||||
err = dispatchCopy(d, c.SourcesAndDest, llb.Local("context"))
|
||||
err = dispatchCopy(d, c.SourcesAndDest, llb.Local(localNameContext))
|
||||
case *instructions.LabelCommand:
|
||||
err = dispatchLabel(d, c)
|
||||
case *instructions.OnbuildCommand:
|
||||
|
@ -179,22 +188,22 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
|
|||
case *instructions.ShellCommand:
|
||||
err = dispatchShell(d, c)
|
||||
case *instructions.ArgCommand:
|
||||
args, err = dispatchArg(d, c, args, metaArgs, opt.BuildArgs)
|
||||
buildArgs, err = dispatchArg(d, c, buildArgs, metaArgs, opt.BuildArgs)
|
||||
case *instructions.CopyCommand:
|
||||
l := llb.Local("context")
|
||||
if c.From != "" {
|
||||
index, err := strconv.Atoi(c.From)
|
||||
if err != nil {
|
||||
stn, ok := stagesByName[strings.ToLower(c.From)]
|
||||
stn, ok := dispatchStatesByName[strings.ToLower(c.From)]
|
||||
if !ok {
|
||||
return nil, nil, errors.Errorf("stage %s not found", c.From)
|
||||
}
|
||||
l = stn.state
|
||||
} else {
|
||||
if index >= len(allStages) {
|
||||
if index >= len(allDispatchStates) {
|
||||
return nil, nil, errors.Errorf("invalid stage index %d", index)
|
||||
}
|
||||
l = allStages[index].state
|
||||
l = allDispatchStates[index].state
|
||||
}
|
||||
}
|
||||
err = dispatchCopy(d, c.SourcesAndDest, l)
|
||||
|
@ -209,10 +218,10 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
|
|||
}
|
||||
|
||||
if opt.Target == "" {
|
||||
return &allStages[len(allStages)-1].state, &allStages[len(allStages)-1].image, nil
|
||||
return &allDispatchStates[len(allDispatchStates)-1].state, &allDispatchStates[len(allDispatchStates)-1].image, nil
|
||||
}
|
||||
|
||||
state, ok := stagesByName[strings.ToLower(opt.Target)]
|
||||
state, ok := dispatchStatesByName[strings.ToLower(opt.Target)]
|
||||
if !ok {
|
||||
return nil, nil, errors.Errorf("target stage %s could not be found", opt.Target)
|
||||
}
|
||||
|
@ -263,7 +272,7 @@ func dispatchCopy(d *dispatchState, c instructions.SourcesAndDest, sourceState l
|
|||
// TODO: this should use CopyOp instead. Current implementation is inefficient and doesn't match Dockerfile path suffixes rules
|
||||
img := llb.Image("tonistiigi/copy@sha256:260a4355be76e0609518ebd7c0e026831c80b8908d4afd3f8e8c942645b1e5cf")
|
||||
|
||||
dest := path.Join("/dest", toWorkingDir(d.state, c.Dest()))
|
||||
dest := path.Join("/dest", pathRelativeToWorkingDir(d.state, c.Dest()))
|
||||
args := []string{"copy"}
|
||||
mounts := make([]llb.RunOption, 0, len(c.Sources()))
|
||||
for i, src := range c.Sources() {
|
||||
|
@ -282,13 +291,6 @@ func dispatchCopy(d *dispatchState, c instructions.SourcesAndDest, sourceState l
|
|||
return nil
|
||||
}
|
||||
|
||||
func toWorkingDir(s llb.State, p string) string {
|
||||
if path.IsAbs(p) {
|
||||
return p
|
||||
}
|
||||
return path.Join(s.GetDir(), p)
|
||||
}
|
||||
|
||||
func dispatchMaintainer(d *dispatchState, c instructions.MaintainerCommand) error {
|
||||
d.image.Author = c.Maintainer
|
||||
return nil
|
||||
|
@ -395,10 +397,17 @@ func dispatchArg(d *dispatchState, c *instructions.ArgCommand, args []instructio
|
|||
}
|
||||
}
|
||||
|
||||
args = append(args, setArgValue(*c, buildArgs))
|
||||
args = append(args, setBuildArgValue(*c, buildArgs))
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func pathRelativeToWorkingDir(s llb.State, p string) string {
|
||||
if path.IsAbs(p) {
|
||||
return p
|
||||
}
|
||||
return path.Join(s.GetDir(), p)
|
||||
}
|
||||
|
||||
func splitWildcards(name string) (string, string) {
|
||||
i := 0
|
||||
for ; i < len(name); i++ {
|
||||
|
@ -438,14 +447,14 @@ func equalEnvKeys(from, to string) bool {
|
|||
return from == to
|
||||
}
|
||||
|
||||
func setArgValue(c instructions.ArgCommand, values map[string]string) instructions.ArgCommand {
|
||||
func setBuildArgValue(c instructions.ArgCommand, values map[string]string) instructions.ArgCommand {
|
||||
if v, ok := values[c.Key]; ok {
|
||||
c.Value = &v
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func combineArgs(env []string, args []instructions.ArgCommand) []string {
|
||||
func toEnvList(args []instructions.ArgCommand, env []string) []string {
|
||||
for _, arg := range args {
|
||||
env = addEnv(env, arg.Key, getArgValue(arg), false)
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ func (e *execOp) Run(ctx context.Context, inputs []Reference) ([]Reference, erro
|
|||
defer func() {
|
||||
for _, o := range outputs {
|
||||
if o != nil {
|
||||
go o.Release(ctx)
|
||||
go o.Release(context.TODO())
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
|
Loading…
Reference in New Issue