124 lines
2.5 KiB
Go
124 lines
2.5 KiB
Go
package solver
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/docker/docker/pkg/symlink"
|
|
"github.com/moby/buildkit/client/llb"
|
|
"github.com/moby/buildkit/snapshot"
|
|
"github.com/moby/buildkit/solver/pb"
|
|
digest "github.com/opencontainers/go-digest"
|
|
"github.com/pkg/errors"
|
|
"golang.org/x/net/context"
|
|
)
|
|
|
|
const buildCacheType = "buildkit.build.v0"
|
|
|
|
type buildOp struct {
|
|
op *pb.BuildOp
|
|
s *Solver
|
|
v Vertex
|
|
}
|
|
|
|
func newBuildOp(v Vertex, op *pb.Op_Build, s *Solver) (Op, error) {
|
|
return &buildOp{
|
|
op: op.Build,
|
|
s: s,
|
|
v: v,
|
|
}, nil
|
|
}
|
|
|
|
func (b *buildOp) CacheKey(ctx context.Context) (digest.Digest, error) {
|
|
dt, err := json.Marshal(struct {
|
|
Type string
|
|
Exec *pb.BuildOp
|
|
}{
|
|
Type: buildCacheType,
|
|
Exec: b.op,
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return digest.FromBytes(dt), nil
|
|
}
|
|
|
|
func (b *buildOp) Run(ctx context.Context, inputs []Reference) (outputs []Reference, retErr error) {
|
|
if b.op.Builder != pb.LLBBuilder {
|
|
return nil, errors.Errorf("only llb builder is currently allowed")
|
|
}
|
|
|
|
builderInputs := b.op.Inputs
|
|
llbDef, ok := builderInputs[pb.LLBDefinitionInput]
|
|
if !ok {
|
|
return nil, errors.Errorf("no llb definition input %s found", pb.LLBDefinitionInput)
|
|
}
|
|
|
|
i := int(llbDef.Input)
|
|
if i >= len(inputs) {
|
|
return nil, errors.Errorf("invalid index %v", i) // TODO: this should be validated before
|
|
}
|
|
inp := inputs[i]
|
|
|
|
ref, ok := toImmutableRef(inp)
|
|
if !ok {
|
|
return nil, errors.Errorf("invalid reference for build %T", inp)
|
|
}
|
|
|
|
mount, err := ref.Mount(ctx, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
lm := snapshot.LocalMounter(mount)
|
|
|
|
root, err := lm.Mount()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer func() {
|
|
if retErr != nil && lm != nil {
|
|
lm.Unmount()
|
|
}
|
|
}()
|
|
|
|
fn := pb.LLBDefaultDefinitionFile
|
|
if override, ok := b.op.Attrs[pb.AttrLLBDefinitionFilename]; ok {
|
|
fn = override
|
|
}
|
|
|
|
newfn, err := symlink.FollowSymlinkInScope(filepath.Join(root, fn), root)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "working dir %s points to invalid target", fn)
|
|
}
|
|
|
|
f, err := os.Open(newfn)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to open %s", newfn)
|
|
}
|
|
|
|
def, err := llb.ReadFrom(f)
|
|
if err != nil {
|
|
f.Close()
|
|
return nil, err
|
|
}
|
|
f.Close()
|
|
lm.Unmount()
|
|
lm = nil
|
|
|
|
newref, err := b.s.subBuild(ctx, b.v.Digest(), SolveRequest{
|
|
Definition: def.ToPB(),
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return []Reference{newref}, err
|
|
}
|
|
|
|
func (b *buildOp) ContentMask(context.Context) (digest.Digest, [][]string, error) {
|
|
return "", nil, nil
|
|
}
|