in source.go [301:375]
func generateSourceFromImage(st llb.State, cmd *Command, sOpts SourceOpts, subPath string, opts ...llb.ConstraintsOpt) (llb.State, error) {
if len(cmd.Steps) == 0 {
return llb.Scratch(), fmt.Errorf("no steps defined for image source")
}
if subPath == "" {
// TODO: We should log a warning here since extracting an entire image while also running a command is
// probably not what the user really wanted to do here.
// The buildkit client provides functionality to do this we just need to wire it in.
subPath = "/"
}
for k, v := range cmd.Env {
st = st.AddEnv(k, v)
}
if cmd.Dir != "" {
st = st.Dir(cmd.Dir)
}
baseRunOpts := []llb.RunOption{CacheDirsToRunOpt(cmd.CacheDirs, "", "")}
for _, src := range cmd.Mounts {
if err := src.validate(subPath); err != nil {
return llb.Scratch(), err
}
srcSt, err := src.Spec.AsMount(internalMountSourceName, sOpts, opts...)
if err != nil {
return llb.Scratch(), err
}
var mountOpt []llb.MountOption
// This handles the case where we are mounting a source with a target extract path and
// no includes and excludes. In this case, we can extract the path here as a source mount
// if the source does not handle its own path extraction. This saves an extra llb.Copy operation
if src.Spec.Path != "" && len(src.Spec.Includes) == 0 && len(src.Spec.Excludes) == 0 &&
!src.Spec.handlesOwnPath() {
mountOpt = append(mountOpt, llb.SourcePath(src.Spec.Path))
}
if !SourceIsDir(src.Spec) {
mountOpt = append(mountOpt, llb.SourcePath(internalMountSourceName))
}
baseRunOpts = append(baseRunOpts, llb.AddMount(src.Dest, srcSt, mountOpt...))
}
out := llb.Scratch()
for i, step := range cmd.Steps {
rOpts := []llb.RunOption{llb.Args([]string{"/bin/sh", "-c", step.Command})}
rOpts = append(rOpts, baseRunOpts...)
for k, v := range step.Env {
rOpts = append(rOpts, llb.AddEnv(k, v))
}
rOpts = append(rOpts, withConstraints(opts))
cmdSt := st.Run(rOpts...)
// on first iteration with a root subpath
// do not use AddMount, as this will overwrite / with a
// scratch fs
if i == 0 && subPath == "/" {
out = cmdSt.Root()
} else {
out = cmdSt.AddMount(subPath, out)
}
// Update the base state so that changes to the rootfs propagate between
// steps.
st = cmdSt.Root()
}
return out, nil
}