Browse Source

vendor: update buildkit and fsutil

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Tonis Tiigi 6 năm trước cách đây
mục cha
commit
5166013119
79 tập tin đã thay đổi với 5934 bổ sung1072 xóa
  1. 8 5
      builder/builder-next/controller.go
  2. 3 2
      vendor.conf
  3. 492 0
      vendor/github.com/containerd/containerd/services/content/service.go
  4. 71 0
      vendor/github.com/containerd/containerd/services/content/store.go
  5. 36 0
      vendor/github.com/containerd/containerd/services/services.go
  6. 27 0
      vendor/github.com/gofrs/flock/LICENSE
  7. 40 0
      vendor/github.com/gofrs/flock/README.md
  8. 127 0
      vendor/github.com/gofrs/flock/flock.go
  9. 195 0
      vendor/github.com/gofrs/flock/flock_unix.go
  10. 76 0
      vendor/github.com/gofrs/flock/flock_winapi.go
  11. 140 0
      vendor/github.com/gofrs/flock/flock_windows.go
  12. 41 11
      vendor/github.com/moby/buildkit/README.md
  13. 685 149
      vendor/github.com/moby/buildkit/api/services/control/control.pb.go
  14. 26 4
      vendor/github.com/moby/buildkit/api/services/control/control.proto
  15. 101 28
      vendor/github.com/moby/buildkit/api/types/worker.pb.go
  16. 157 29
      vendor/github.com/moby/buildkit/cache/contenthash/checksum.go
  17. 141 57
      vendor/github.com/moby/buildkit/cache/contenthash/checksum.pb.go
  18. 26 12
      vendor/github.com/moby/buildkit/cache/remotecache/export.go
  19. 175 3
      vendor/github.com/moby/buildkit/cache/remotecache/import.go
  20. 99 0
      vendor/github.com/moby/buildkit/cache/remotecache/inline/inline.go
  21. 24 6
      vendor/github.com/moby/buildkit/cache/remotecache/registry/registry.go
  22. 61 12
      vendor/github.com/moby/buildkit/cache/remotecache/v1/cachestorage.go
  23. 27 0
      vendor/github.com/moby/buildkit/cache/remotecache/v1/chains.go
  24. 1 1
      vendor/github.com/moby/buildkit/cache/remotecache/v1/doc.go
  25. 11 3
      vendor/github.com/moby/buildkit/cache/remotecache/v1/parse.go
  26. 12 0
      vendor/github.com/moby/buildkit/cache/remotecache/v1/utils.go
  27. 1 1
      vendor/github.com/moby/buildkit/client/client_windows.go
  28. 1 0
      vendor/github.com/moby/buildkit/client/graph.go
  29. 6 2
      vendor/github.com/moby/buildkit/client/llb/state.go
  30. 113 0
      vendor/github.com/moby/buildkit/client/ociindex/ociindex.go
  31. 195 28
      vendor/github.com/moby/buildkit/client/solve.go
  32. 76 47
      vendor/github.com/moby/buildkit/control/control.go
  33. 56 7
      vendor/github.com/moby/buildkit/executor/oci/mounts.go
  34. 27 2
      vendor/github.com/moby/buildkit/executor/oci/spec_unix.go
  35. 5 1
      vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go
  36. 1 0
      vendor/github.com/moby/buildkit/exporter/containerimage/exptypes/types.go
  37. 148 0
      vendor/github.com/moby/buildkit/exporter/local/export.go
  38. 62 27
      vendor/github.com/moby/buildkit/frontend/dockerfile/builder/build.go
  39. 12 7
      vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert.go
  40. 2 0
      vendor/github.com/moby/buildkit/frontend/frontend.go
  41. 9 4
      vendor/github.com/moby/buildkit/frontend/gateway/client/client.go
  42. 4 4
      vendor/github.com/moby/buildkit/frontend/gateway/forwarder/forward.go
  43. 39 6
      vendor/github.com/moby/buildkit/frontend/gateway/gateway.go
  44. 21 1
      vendor/github.com/moby/buildkit/frontend/gateway/grpcclient/client.go
  45. 8 0
      vendor/github.com/moby/buildkit/frontend/gateway/pb/caps.go
  46. 712 140
      vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.pb.go
  47. 15 2
      vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.proto
  48. 84 29
      vendor/github.com/moby/buildkit/session/auth/auth.pb.go
  49. 132 0
      vendor/github.com/moby/buildkit/session/content/attachable.go
  50. 84 0
      vendor/github.com/moby/buildkit/session/content/caller.go
  51. 56 31
      vendor/github.com/moby/buildkit/session/filesync/filesync.pb.go
  52. 88 33
      vendor/github.com/moby/buildkit/session/secrets/secrets.pb.go
  53. 119 35
      vendor/github.com/moby/buildkit/session/sshforward/ssh.pb.go
  54. 80 3
      vendor/github.com/moby/buildkit/solver/cachemanager.go
  55. 1 1
      vendor/github.com/moby/buildkit/solver/cachestorage.go
  56. 20 7
      vendor/github.com/moby/buildkit/solver/combinedcache.go
  57. 38 3
      vendor/github.com/moby/buildkit/solver/edge.go
  58. 1 1
      vendor/github.com/moby/buildkit/solver/jobs.go
  59. 34 27
      vendor/github.com/moby/buildkit/solver/llbsolver/bridge.go
  60. 25 11
      vendor/github.com/moby/buildkit/solver/llbsolver/ops/exec.go
  61. 13 3
      vendor/github.com/moby/buildkit/solver/llbsolver/ops/source.go
  62. 1 1
      vendor/github.com/moby/buildkit/solver/llbsolver/result.go
  63. 83 24
      vendor/github.com/moby/buildkit/solver/llbsolver/solver.go
  64. 15 1
      vendor/github.com/moby/buildkit/solver/llbsolver/vertex.go
  65. 2 2
      vendor/github.com/moby/buildkit/solver/memorycachestorage.go
  66. 610 144
      vendor/github.com/moby/buildkit/solver/pb/ops.pb.go
  67. 1 1
      vendor/github.com/moby/buildkit/solver/types.go
  68. 5 1
      vendor/github.com/moby/buildkit/source/git/gitsource.go
  69. 9 1
      vendor/github.com/moby/buildkit/source/git/gitsource_unix.go
  70. 34 2
      vendor/github.com/moby/buildkit/source/http/httpsource.go
  71. 5 6
      vendor/github.com/moby/buildkit/source/local/local.go
  72. 4 3
      vendor/github.com/moby/buildkit/source/manager.go
  73. 53 21
      vendor/github.com/moby/buildkit/util/apicaps/pb/caps.pb.go
  74. 1 1
      vendor/github.com/moby/buildkit/util/contentutil/copy.go
  75. 8 4
      vendor/github.com/moby/buildkit/util/imageutil/config.go
  76. 0 69
      vendor/github.com/moby/buildkit/vendor.conf
  77. 2 2
      vendor/github.com/moby/buildkit/worker/cacheresult.go
  78. 4 3
      vendor/github.com/moby/buildkit/worker/worker.go
  79. 7 1
      vendor/github.com/tonistiigi/fsutil/receive.go

+ 8 - 5
builder/builder-next/controller.go

@@ -17,6 +17,7 @@ import (
 	units "github.com/docker/go-units"
 	units "github.com/docker/go-units"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/cache/metadata"
 	"github.com/moby/buildkit/cache/metadata"
+	"github.com/moby/buildkit/cache/remotecache"
 	registryremotecache "github.com/moby/buildkit/cache/remotecache/registry"
 	registryremotecache "github.com/moby/buildkit/cache/remotecache/registry"
 	"github.com/moby/buildkit/client"
 	"github.com/moby/buildkit/client"
 	"github.com/moby/buildkit/control"
 	"github.com/moby/buildkit/control"
@@ -167,11 +168,13 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
 	}
 	}
 
 
 	return control.NewController(control.Opt{
 	return control.NewController(control.Opt{
-		SessionManager:           opt.SessionManager,
-		WorkerController:         wc,
-		Frontends:                frontends,
-		CacheKeyStorage:          cacheStorage,
-		ResolveCacheImporterFunc: registryremotecache.ResolveCacheImporterFunc(opt.SessionManager, opt.ResolverOpt),
+		SessionManager:   opt.SessionManager,
+		WorkerController: wc,
+		Frontends:        frontends,
+		CacheKeyStorage:  cacheStorage,
+		ResolveCacheImporterFuncs: map[string]remotecache.ResolveCacheImporterFunc{
+			"registry": registryremotecache.ResolveCacheImporterFunc(opt.SessionManager, opt.ResolverOpt),
+		},
 		// TODO: set ResolveCacheExporterFunc for exporting cache
 		// TODO: set ResolveCacheExporterFunc for exporting cache
 	})
 	})
 }
 }

+ 3 - 2
vendor.conf

@@ -26,13 +26,14 @@ github.com/imdario/mergo v0.3.6
 golang.org/x/sync 1d60e4601c6fd243af51cc01ddf169918a5407ca
 golang.org/x/sync 1d60e4601c6fd243af51cc01ddf169918a5407ca
 
 
 # buildkit
 # buildkit
-github.com/moby/buildkit 34ff9c2366a878ada7938d2f9ede71741b0a220c
-github.com/tonistiigi/fsutil 2862f6bc5ac9b97124e552a5c108230b38a1b0ca
+github.com/moby/buildkit c35410878ab9070498c66f6c67d3e8bc3b92241f
+github.com/tonistiigi/fsutil 1ec1983587cde7e8ac2978e354ff5360af622464
 github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
 github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
 github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
 github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
 github.com/google/shlex 6f45313302b9c56850fc17f99e40caebce98c716
 github.com/google/shlex 6f45313302b9c56850fc17f99e40caebce98c716
 github.com/opentracing-contrib/go-stdlib  b1a47cfbdd7543e70e9ef3e73d0802ad306cc1cc
 github.com/opentracing-contrib/go-stdlib  b1a47cfbdd7543e70e9ef3e73d0802ad306cc1cc
 github.com/mitchellh/hashstructure 2bca23e0e452137f789efbc8610126fd8b94f73b
 github.com/mitchellh/hashstructure 2bca23e0e452137f789efbc8610126fd8b94f73b
+github.com/gofrs/flock 7f43ea2e6a643ad441fc12d0ecc0d3388b300c53 # v0.7.0
 
 
 #get libnetwork packages
 #get libnetwork packages
 
 

+ 492 - 0
vendor/github.com/containerd/containerd/services/content/service.go

@@ -0,0 +1,492 @@
+/*
+   Copyright The containerd Authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package content
+
+import (
+	"context"
+	"io"
+	"sync"
+
+	api "github.com/containerd/containerd/api/services/content/v1"
+	"github.com/containerd/containerd/content"
+	"github.com/containerd/containerd/errdefs"
+	"github.com/containerd/containerd/log"
+	"github.com/containerd/containerd/plugin"
+	"github.com/containerd/containerd/services"
+	ptypes "github.com/gogo/protobuf/types"
+	digest "github.com/opencontainers/go-digest"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/pkg/errors"
+	"github.com/sirupsen/logrus"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+)
+
+type service struct {
+	store content.Store
+}
+
+var bufPool = sync.Pool{
+	New: func() interface{} {
+		buffer := make([]byte, 1<<20)
+		return &buffer
+	},
+}
+
+var _ api.ContentServer = &service{}
+
+func init() {
+	plugin.Register(&plugin.Registration{
+		Type: plugin.GRPCPlugin,
+		ID:   "content",
+		Requires: []plugin.Type{
+			plugin.ServicePlugin,
+		},
+		InitFn: func(ic *plugin.InitContext) (interface{}, error) {
+			plugins, err := ic.GetByType(plugin.ServicePlugin)
+			if err != nil {
+				return nil, err
+			}
+			p, ok := plugins[services.ContentService]
+			if !ok {
+				return nil, errors.New("content store service not found")
+			}
+			cs, err := p.Instance()
+			if err != nil {
+				return nil, err
+			}
+			return NewService(cs.(content.Store)), nil
+		},
+	})
+}
+
+// NewService returns the content GRPC server
+func NewService(cs content.Store) api.ContentServer {
+	return &service{store: cs}
+}
+
+func (s *service) Register(server *grpc.Server) error {
+	api.RegisterContentServer(server, s)
+	return nil
+}
+
+func (s *service) Info(ctx context.Context, req *api.InfoRequest) (*api.InfoResponse, error) {
+	if err := req.Digest.Validate(); err != nil {
+		return nil, status.Errorf(codes.InvalidArgument, "%q failed validation", req.Digest)
+	}
+
+	bi, err := s.store.Info(ctx, req.Digest)
+	if err != nil {
+		return nil, errdefs.ToGRPC(err)
+	}
+
+	return &api.InfoResponse{
+		Info: infoToGRPC(bi),
+	}, nil
+}
+
+func (s *service) Update(ctx context.Context, req *api.UpdateRequest) (*api.UpdateResponse, error) {
+	if err := req.Info.Digest.Validate(); err != nil {
+		return nil, status.Errorf(codes.InvalidArgument, "%q failed validation", req.Info.Digest)
+	}
+
+	info, err := s.store.Update(ctx, infoFromGRPC(req.Info), req.UpdateMask.GetPaths()...)
+	if err != nil {
+		return nil, errdefs.ToGRPC(err)
+	}
+
+	return &api.UpdateResponse{
+		Info: infoToGRPC(info),
+	}, nil
+}
+
+func (s *service) List(req *api.ListContentRequest, session api.Content_ListServer) error {
+	var (
+		buffer    []api.Info
+		sendBlock = func(block []api.Info) error {
+			// send last block
+			return session.Send(&api.ListContentResponse{
+				Info: block,
+			})
+		}
+	)
+
+	if err := s.store.Walk(session.Context(), func(info content.Info) error {
+		buffer = append(buffer, api.Info{
+			Digest:    info.Digest,
+			Size_:     info.Size,
+			CreatedAt: info.CreatedAt,
+			Labels:    info.Labels,
+		})
+
+		if len(buffer) >= 100 {
+			if err := sendBlock(buffer); err != nil {
+				return err
+			}
+
+			buffer = buffer[:0]
+		}
+
+		return nil
+	}, req.Filters...); err != nil {
+		return err
+	}
+
+	if len(buffer) > 0 {
+		// send last block
+		if err := sendBlock(buffer); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (s *service) Delete(ctx context.Context, req *api.DeleteContentRequest) (*ptypes.Empty, error) {
+	log.G(ctx).WithField("digest", req.Digest).Debugf("delete content")
+	if err := req.Digest.Validate(); err != nil {
+		return nil, status.Errorf(codes.InvalidArgument, err.Error())
+	}
+
+	if err := s.store.Delete(ctx, req.Digest); err != nil {
+		return nil, errdefs.ToGRPC(err)
+	}
+
+	return &ptypes.Empty{}, nil
+}
+
+func (s *service) Read(req *api.ReadContentRequest, session api.Content_ReadServer) error {
+	if err := req.Digest.Validate(); err != nil {
+		return status.Errorf(codes.InvalidArgument, "%v: %v", req.Digest, err)
+	}
+
+	oi, err := s.store.Info(session.Context(), req.Digest)
+	if err != nil {
+		return errdefs.ToGRPC(err)
+	}
+
+	ra, err := s.store.ReaderAt(session.Context(), ocispec.Descriptor{Digest: req.Digest})
+	if err != nil {
+		return errdefs.ToGRPC(err)
+	}
+	defer ra.Close()
+
+	var (
+		offset = req.Offset
+		// size is read size, not the expected size of the blob (oi.Size), which the caller might not be aware of.
+		// offset+size can be larger than oi.Size.
+		size = req.Size_
+
+		// TODO(stevvooe): Using the global buffer pool. At 32KB, it is probably
+		// little inefficient for work over a fast network. We can tune this later.
+		p = bufPool.Get().(*[]byte)
+	)
+	defer bufPool.Put(p)
+
+	if offset < 0 {
+		offset = 0
+	}
+
+	if offset > oi.Size {
+		return status.Errorf(codes.OutOfRange, "read past object length %v bytes", oi.Size)
+	}
+
+	if size <= 0 || offset+size > oi.Size {
+		size = oi.Size - offset
+	}
+
+	_, err = io.CopyBuffer(
+		&readResponseWriter{session: session},
+		io.NewSectionReader(ra, offset, size), *p)
+	return errdefs.ToGRPC(err)
+}
+
+// readResponseWriter is a writer that places the output into ReadContentRequest messages.
+//
+// This allows io.CopyBuffer to do the heavy lifting of chunking the responses
+// into the buffer size.
+type readResponseWriter struct {
+	offset  int64
+	session api.Content_ReadServer
+}
+
+func (rw *readResponseWriter) Write(p []byte) (n int, err error) {
+	if err := rw.session.Send(&api.ReadContentResponse{
+		Offset: rw.offset,
+		Data:   p,
+	}); err != nil {
+		return 0, err
+	}
+
+	rw.offset += int64(len(p))
+	return len(p), nil
+}
+
+func (s *service) Status(ctx context.Context, req *api.StatusRequest) (*api.StatusResponse, error) {
+	status, err := s.store.Status(ctx, req.Ref)
+	if err != nil {
+		return nil, errdefs.ToGRPCf(err, "could not get status for ref %q", req.Ref)
+	}
+
+	var resp api.StatusResponse
+	resp.Status = &api.Status{
+		StartedAt: status.StartedAt,
+		UpdatedAt: status.UpdatedAt,
+		Ref:       status.Ref,
+		Offset:    status.Offset,
+		Total:     status.Total,
+		Expected:  status.Expected,
+	}
+
+	return &resp, nil
+}
+
+func (s *service) ListStatuses(ctx context.Context, req *api.ListStatusesRequest) (*api.ListStatusesResponse, error) {
+	statuses, err := s.store.ListStatuses(ctx, req.Filters...)
+	if err != nil {
+		return nil, errdefs.ToGRPC(err)
+	}
+
+	var resp api.ListStatusesResponse
+	for _, status := range statuses {
+		resp.Statuses = append(resp.Statuses, api.Status{
+			StartedAt: status.StartedAt,
+			UpdatedAt: status.UpdatedAt,
+			Ref:       status.Ref,
+			Offset:    status.Offset,
+			Total:     status.Total,
+			Expected:  status.Expected,
+		})
+	}
+
+	return &resp, nil
+}
+
+func (s *service) Write(session api.Content_WriteServer) (err error) {
+	var (
+		ctx      = session.Context()
+		msg      api.WriteContentResponse
+		req      *api.WriteContentRequest
+		ref      string
+		total    int64
+		expected digest.Digest
+	)
+
+	defer func(msg *api.WriteContentResponse) {
+		// pump through the last message if no error was encountered
+		if err != nil {
+			if s, ok := status.FromError(err); ok && s.Code() != codes.AlreadyExists {
+				// TODO(stevvooe): Really need a log line here to track which
+				// errors are actually causing failure on the server side. May want
+				// to configure the service with an interceptor to make this work
+				// identically across all GRPC methods.
+				//
+				// This is pretty noisy, so we can remove it but leave it for now.
+				log.G(ctx).WithError(err).Error("(*service).Write failed")
+			}
+
+			return
+		}
+
+		err = session.Send(msg)
+	}(&msg)
+
+	// handle the very first request!
+	req, err = session.Recv()
+	if err != nil {
+		return err
+	}
+
+	ref = req.Ref
+
+	if ref == "" {
+		return status.Errorf(codes.InvalidArgument, "first message must have a reference")
+	}
+
+	fields := logrus.Fields{
+		"ref": ref,
+	}
+	total = req.Total
+	expected = req.Expected
+	if total > 0 {
+		fields["total"] = total
+	}
+
+	if expected != "" {
+		fields["expected"] = expected
+	}
+
+	ctx = log.WithLogger(ctx, log.G(ctx).WithFields(fields))
+
+	log.G(ctx).Debug("(*service).Write started")
+	// this action locks the writer for the session.
+	wr, err := s.store.Writer(ctx,
+		content.WithRef(ref),
+		content.WithDescriptor(ocispec.Descriptor{Size: total, Digest: expected}))
+	if err != nil {
+		return errdefs.ToGRPC(err)
+	}
+	defer wr.Close()
+
+	for {
+		msg.Action = req.Action
+		ws, err := wr.Status()
+		if err != nil {
+			return errdefs.ToGRPC(err)
+		}
+
+		msg.Offset = ws.Offset // always set the offset.
+
+		// NOTE(stevvooe): In general, there are two cases underwhich a remote
+		// writer is used.
+		//
+		// For pull, we almost always have this before fetching large content,
+		// through descriptors. We allow predeclaration of the expected size
+		// and digest.
+		//
+		// For push, it is more complex. If we want to cut through content into
+		// storage, we may have no expectation until we are done processing the
+		// content. The case here is the following:
+		//
+		// 	1. Start writing content.
+		// 	2. Compress inline.
+		// 	3. Validate digest and size (maybe).
+		//
+		// Supporting these two paths is quite awkward but it lets both API
+		// users use the same writer style for each with a minimum of overhead.
+		if req.Expected != "" {
+			if expected != "" && expected != req.Expected {
+				log.G(ctx).Debugf("commit digest differs from writer digest: %v != %v", req.Expected, expected)
+			}
+			expected = req.Expected
+
+			if _, err := s.store.Info(session.Context(), req.Expected); err == nil {
+				if err := wr.Close(); err != nil {
+					log.G(ctx).WithError(err).Error("failed to close writer")
+				}
+				if err := s.store.Abort(session.Context(), ref); err != nil {
+					log.G(ctx).WithError(err).Error("failed to abort write")
+				}
+
+				return status.Errorf(codes.AlreadyExists, "blob with expected digest %v exists", req.Expected)
+			}
+		}
+
+		if req.Total > 0 {
+			// Update the expected total. Typically, this could be seen at
+			// negotiation time or on a commit message.
+			if total > 0 && req.Total != total {
+				log.G(ctx).Debugf("commit size differs from writer size: %v != %v", req.Total, total)
+			}
+			total = req.Total
+		}
+
+		switch req.Action {
+		case api.WriteActionStat:
+			msg.Digest = wr.Digest()
+			msg.StartedAt = ws.StartedAt
+			msg.UpdatedAt = ws.UpdatedAt
+			msg.Total = total
+		case api.WriteActionWrite, api.WriteActionCommit:
+			if req.Offset > 0 {
+				// validate the offset if provided
+				if req.Offset != ws.Offset {
+					return status.Errorf(codes.OutOfRange, "write @%v must occur at current offset %v", req.Offset, ws.Offset)
+				}
+			}
+
+			if req.Offset == 0 && ws.Offset > 0 {
+				if err := wr.Truncate(req.Offset); err != nil {
+					return errors.Wrapf(err, "truncate failed")
+				}
+				msg.Offset = req.Offset
+			}
+
+			// issue the write if we actually have data.
+			if len(req.Data) > 0 {
+				// While this looks like we could use io.WriterAt here, because we
+				// maintain the offset as append only, we just issue the write.
+				n, err := wr.Write(req.Data)
+				if err != nil {
+					return errdefs.ToGRPC(err)
+				}
+
+				if n != len(req.Data) {
+					// TODO(stevvooe): Perhaps, we can recover this by including it
+					// in the offset on the write return.
+					return status.Errorf(codes.DataLoss, "wrote %v of %v bytes", n, len(req.Data))
+				}
+
+				msg.Offset += int64(n)
+			}
+
+			if req.Action == api.WriteActionCommit {
+				var opts []content.Opt
+				if req.Labels != nil {
+					opts = append(opts, content.WithLabels(req.Labels))
+				}
+				if err := wr.Commit(ctx, total, expected, opts...); err != nil {
+					return errdefs.ToGRPC(err)
+				}
+			}
+
+			msg.Digest = wr.Digest()
+		}
+
+		if err := session.Send(&msg); err != nil {
+			return err
+		}
+
+		req, err = session.Recv()
+		if err != nil {
+			if err == io.EOF {
+				return nil
+			}
+
+			return err
+		}
+	}
+}
+
+func (s *service) Abort(ctx context.Context, req *api.AbortRequest) (*ptypes.Empty, error) {
+	if err := s.store.Abort(ctx, req.Ref); err != nil {
+		return nil, errdefs.ToGRPC(err)
+	}
+
+	return &ptypes.Empty{}, nil
+}
+
+func infoToGRPC(info content.Info) api.Info {
+	return api.Info{
+		Digest:    info.Digest,
+		Size_:     info.Size,
+		CreatedAt: info.CreatedAt,
+		UpdatedAt: info.UpdatedAt,
+		Labels:    info.Labels,
+	}
+}
+
+func infoFromGRPC(info api.Info) content.Info {
+	return content.Info{
+		Digest:    info.Digest,
+		Size:      info.Size_,
+		CreatedAt: info.CreatedAt,
+		UpdatedAt: info.UpdatedAt,
+		Labels:    info.Labels,
+	}
+}

+ 71 - 0
vendor/github.com/containerd/containerd/services/content/store.go

@@ -0,0 +1,71 @@
+/*
+   Copyright The containerd Authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package content
+
+import (
+	"context"
+
+	eventstypes "github.com/containerd/containerd/api/events"
+	"github.com/containerd/containerd/content"
+	"github.com/containerd/containerd/events"
+	"github.com/containerd/containerd/metadata"
+	"github.com/containerd/containerd/plugin"
+	"github.com/containerd/containerd/services"
+	digest "github.com/opencontainers/go-digest"
+)
+
+// store wraps content.Store with proper event published.
+type store struct {
+	content.Store
+	publisher events.Publisher
+}
+
+func init() {
+	plugin.Register(&plugin.Registration{
+		Type: plugin.ServicePlugin,
+		ID:   services.ContentService,
+		Requires: []plugin.Type{
+			plugin.MetadataPlugin,
+		},
+		InitFn: func(ic *plugin.InitContext) (interface{}, error) {
+			m, err := ic.Get(plugin.MetadataPlugin)
+			if err != nil {
+				return nil, err
+			}
+
+			s, err := newContentStore(m.(*metadata.DB).ContentStore(), ic.Events)
+			return s, err
+		},
+	})
+}
+
+func newContentStore(cs content.Store, publisher events.Publisher) (content.Store, error) {
+	return &store{
+		Store:     cs,
+		publisher: publisher,
+	}, nil
+}
+
+func (s *store) Delete(ctx context.Context, dgst digest.Digest) error {
+	if err := s.Store.Delete(ctx, dgst); err != nil {
+		return err
+	}
+	// TODO: Consider whether we should return error here.
+	return s.publisher.Publish(ctx, "/content/delete", &eventstypes.ContentDelete{
+		Digest: dgst,
+	})
+}

+ 36 - 0
vendor/github.com/containerd/containerd/services/services.go

@@ -0,0 +1,36 @@
+/*
+   Copyright The containerd Authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package services
+
+const (
+	// ContentService is id of content service.
+	ContentService = "content-service"
+	// SnapshotsService is id of snapshots service.
+	SnapshotsService = "snapshots-service"
+	// ImagesService is id of images service.
+	ImagesService = "images-service"
+	// ContainersService is id of containers service.
+	ContainersService = "containers-service"
+	// TasksService is id of tasks service.
+	TasksService = "tasks-service"
+	// NamespacesService is id of namespaces service.
+	NamespacesService = "namespaces-service"
+	// LeasesService is id of leases service.
+	LeasesService = "leases-service"
+	// DiffService is id of diff service.
+	DiffService = "diff-service"
+)

+ 27 - 0
vendor/github.com/gofrs/flock/LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2015, Tim Heckman
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* Neither the name of linode-netint nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 40 - 0
vendor/github.com/gofrs/flock/README.md

@@ -0,0 +1,40 @@
+# flock
+[![TravisCI Build Status](https://img.shields.io/travis/gofrs/flock/master.svg?style=flat)](https://travis-ci.org/gofrs/flock)
+[![GoDoc](https://img.shields.io/badge/godoc-go--flock-blue.svg?style=flat)](https://godoc.org/github.com/gofrs/flock)
+[![License](https://img.shields.io/badge/license-BSD_3--Clause-brightgreen.svg?style=flat)](https://github.com/gofrs/flock/blob/master/LICENSE)
+
+`flock` implements a thread-safe sync.Locker interface for file locking. It also
+includes a non-blocking TryLock() function to allow locking without blocking execution.
+
+## License
+`flock` is released under the BSD 3-Clause License. See the `LICENSE` file for more details.
+
+## Go Compatibility
+This package makes use of the `context` package that was introduced in Go 1.7. As such, this
+package has an implicit dependency on Go 1.7+.
+
+## Installation
+```
+go get -u github.com/gofrs/flock
+```
+
+## Usage
+```Go
+import "github.com/gofrs/flock"
+
+fileLock := flock.New("/var/lock/go-lock.lock")
+
+locked, err := fileLock.TryLock()
+
+if err != nil {
+	// handle locking error
+}
+
+if locked {
+	// do work
+	fileLock.Unlock()
+}
+```
+
+For more detailed usage information take a look at the package API docs on
+[GoDoc](https://godoc.org/github.com/gofrs/flock).

+ 127 - 0
vendor/github.com/gofrs/flock/flock.go

@@ -0,0 +1,127 @@
+// Copyright 2015 Tim Heckman. All rights reserved.
+// Use of this source code is governed by the BSD 3-Clause
+// license that can be found in the LICENSE file.
+
+// Package flock implements a thread-safe sync.Locker interface for file locking.
+// It also includes a non-blocking TryLock() function to allow locking
+// without blocking execution.
+//
+// Package flock is released under the BSD 3-Clause License. See the LICENSE file
+// for more details.
+//
+// While using this library, remember that the locking behaviors are not
+// guaranteed to be the same on each platform. For example, some UNIX-like
+// operating systems will transparently convert a shared lock to an exclusive
+// lock. If you Unlock() the flock from a location where you believe that you
+// have the shared lock, you may accidently drop the exclusive lock.
+package flock
+
+import (
+	"context"
+	"os"
+	"sync"
+	"time"
+)
+
+// Flock is the struct type to handle file locking. All fields are unexported,
+// with access to some of the fields provided by getter methods (Path() and Locked()).
+type Flock struct {
+	path string
+	m    sync.RWMutex
+	fh   *os.File
+	l    bool
+	r    bool
+}
+
+// New returns a new instance of *Flock. The only parameter
+// it takes is the path to the desired lockfile.
+func New(path string) *Flock {
+	return &Flock{path: path}
+}
+
+// NewFlock returns a new instance of *Flock. The only parameter
+// it takes is the path to the desired lockfile.
+//
+// Deprecated: Use New instead.
+func NewFlock(path string) *Flock {
+	return New(path)
+}
+
+// Close is equivalent to calling Unlock.
+//
+// This will release the lock and close the underlying file descriptor.
+// It will not remove the file from disk, that's up to your application.
+func (f *Flock) Close() error {
+	return f.Unlock()
+}
+
+// Path returns the path as provided in NewFlock().
+func (f *Flock) Path() string {
+	return f.path
+}
+
+// Locked returns the lock state (locked: true, unlocked: false).
+//
+// Warning: by the time you use the returned value, the state may have changed.
+func (f *Flock) Locked() bool {
+	f.m.RLock()
+	defer f.m.RUnlock()
+	return f.l
+}
+
+// RLocked returns the read lock state (locked: true, unlocked: false).
+//
+// Warning: by the time you use the returned value, the state may have changed.
+func (f *Flock) RLocked() bool {
+	f.m.RLock()
+	defer f.m.RUnlock()
+	return f.r
+}
+
+func (f *Flock) String() string {
+	return f.path
+}
+
+// TryLockContext repeatedly tries to take an exclusive lock until one of the
+// conditions is met: TryLock succeeds, TryLock fails with error, or Context
+// Done channel is closed.
+func (f *Flock) TryLockContext(ctx context.Context, retryDelay time.Duration) (bool, error) {
+	return tryCtx(f.TryLock, ctx, retryDelay)
+}
+
+// TryRLockContext repeatedly tries to take a shared lock until one of the
+// conditions is met: TryRLock succeeds, TryRLock fails with error, or Context
+// Done channel is closed.
+func (f *Flock) TryRLockContext(ctx context.Context, retryDelay time.Duration) (bool, error) {
+	return tryCtx(f.TryRLock, ctx, retryDelay)
+}
+
+func tryCtx(fn func() (bool, error), ctx context.Context, retryDelay time.Duration) (bool, error) {
+	if ctx.Err() != nil {
+		return false, ctx.Err()
+	}
+	for {
+		if ok, err := fn(); ok || err != nil {
+			return ok, err
+		}
+		select {
+		case <-ctx.Done():
+			return false, ctx.Err()
+		case <-time.After(retryDelay):
+			// try again
+		}
+	}
+}
+
+func (f *Flock) setFh() error {
+	// open a new os.File instance
+	// create it if it doesn't exist, and open the file read-only.
+	fh, err := os.OpenFile(f.path, os.O_CREATE|os.O_RDONLY, os.FileMode(0600))
+	if err != nil {
+		return err
+	}
+
+	// set the filehandle on the struct
+	f.fh = fh
+	return nil
+}

+ 195 - 0
vendor/github.com/gofrs/flock/flock_unix.go

@@ -0,0 +1,195 @@
+// Copyright 2015 Tim Heckman. All rights reserved.
+// Use of this source code is governed by the BSD 3-Clause
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+package flock
+
+import (
+	"os"
+	"syscall"
+)
+
+// Lock is a blocking call to try and take an exclusive file lock. It will wait
+// until it is able to obtain the exclusive file lock. It's recommended that
+// TryLock() be used over this function. This function may block the ability to
+// query the current Locked() or RLocked() status due to a RW-mutex lock.
+//
+// If we are already exclusive-locked, this function short-circuits and returns
+// immediately assuming it can take the mutex lock.
+//
+// If the *Flock has a shared lock (RLock), this may transparently replace the
+// shared lock with an exclusive lock on some UNIX-like operating systems. Be
+// careful when using exclusive locks in conjunction with shared locks
+// (RLock()), because calling Unlock() may accidentally release the exclusive
+// lock that was once a shared lock.
+func (f *Flock) Lock() error {
+	return f.lock(&f.l, syscall.LOCK_EX)
+}
+
+// RLock is a blocking call to try and take a shared file lock. It will wait
+// until it is able to obtain the shared file lock. It's recommended that
+// TryRLock() be used over this function. This function may block the ability to
+// query the current Locked() or RLocked() status due to a RW-mutex lock.
+//
+// If we are already shared-locked, this function short-circuits and returns
+// immediately assuming it can take the mutex lock.
+func (f *Flock) RLock() error {
+	return f.lock(&f.r, syscall.LOCK_SH)
+}
+
+func (f *Flock) lock(locked *bool, flag int) error {
+	f.m.Lock()
+	defer f.m.Unlock()
+
+	if *locked {
+		return nil
+	}
+
+	if f.fh == nil {
+		if err := f.setFh(); err != nil {
+			return err
+		}
+	}
+
+	if err := syscall.Flock(int(f.fh.Fd()), flag); err != nil {
+		shouldRetry, reopenErr := f.reopenFDOnError(err)
+		if reopenErr != nil {
+			return reopenErr
+		}
+
+		if !shouldRetry {
+			return err
+		}
+
+		if err = syscall.Flock(int(f.fh.Fd()), flag); err != nil {
+			return err
+		}
+	}
+
+	*locked = true
+	return nil
+}
+
+// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so
+// while it is running the Locked() and RLocked() functions will be blocked.
+//
+// This function short-circuits if we are unlocked already. If not, it calls
+// syscall.LOCK_UN on the file and closes the file descriptor. It does not
+// remove the file from disk. It's up to your application to do.
+//
+// Please note, if your shared lock became an exclusive lock this may
+// unintentionally drop the exclusive lock if called by the consumer that
+// believes they have a shared lock. Please see Lock() for more details.
+func (f *Flock) Unlock() error {
+	f.m.Lock()
+	defer f.m.Unlock()
+
+	// if we aren't locked or if the lockfile instance is nil
+	// just return a nil error because we are unlocked
+	if (!f.l && !f.r) || f.fh == nil {
+		return nil
+	}
+
+	// mark the file as unlocked
+	if err := syscall.Flock(int(f.fh.Fd()), syscall.LOCK_UN); err != nil {
+		return err
+	}
+
+	f.fh.Close()
+
+	f.l = false
+	f.r = false
+	f.fh = nil
+
+	return nil
+}
+
+// TryLock is the preferred function for taking an exclusive file lock. This
+// function takes an RW-mutex lock before it tries to lock the file, so there is
+// the possibility that this function may block for a short time if another
+// goroutine is trying to take any action.
+//
+// The actual file lock is non-blocking. If we are unable to get the exclusive
+// file lock, the function will return false instead of waiting for the lock. If
+// we get the lock, we also set the *Flock instance as being exclusive-locked.
+func (f *Flock) TryLock() (bool, error) {
+	return f.try(&f.l, syscall.LOCK_EX)
+}
+
+// TryRLock is the preferred function for taking a shared file lock. This
+// function takes an RW-mutex lock before it tries to lock the file, so there is
+// the possibility that this function may block for a short time if another
+// goroutine is trying to take any action.
+//
+// The actual file lock is non-blocking. If we are unable to get the shared file
+// lock, the function will return false instead of waiting for the lock. If we
+// get the lock, we also set the *Flock instance as being share-locked.
+func (f *Flock) TryRLock() (bool, error) {
+	return f.try(&f.r, syscall.LOCK_SH)
+}
+
+func (f *Flock) try(locked *bool, flag int) (bool, error) {
+	f.m.Lock()
+	defer f.m.Unlock()
+
+	if *locked {
+		return true, nil
+	}
+
+	if f.fh == nil {
+		if err := f.setFh(); err != nil {
+			return false, err
+		}
+	}
+
+	var retried bool
+retry:
+	err := syscall.Flock(int(f.fh.Fd()), flag|syscall.LOCK_NB)
+
+	switch err {
+	case syscall.EWOULDBLOCK:
+		return false, nil
+	case nil:
+		*locked = true
+		return true, nil
+	}
+	if !retried {
+		if shouldRetry, reopenErr := f.reopenFDOnError(err); reopenErr != nil {
+			return false, reopenErr
+		} else if shouldRetry {
+			retried = true
+			goto retry
+		}
+	}
+
+	return false, err
+}
+
+// reopenFDOnError determines whether we should reopen the file handle
+// in readwrite mode and try again. This comes from util-linux/sys-utils/flock.c:
+//  Since Linux 3.4 (commit 55725513)
+//  Probably NFSv4 where flock() is emulated by fcntl().
+func (f *Flock) reopenFDOnError(err error) (bool, error) {
+	if err != syscall.EIO && err != syscall.EBADF {
+		return false, nil
+	}
+	if st, err := f.fh.Stat(); err == nil {
+		// if the file is able to be read and written
+		if st.Mode()&0600 == 0600 {
+			f.fh.Close()
+			f.fh = nil
+
+			// reopen in read-write mode and set the filehandle
+			fh, err := os.OpenFile(f.path, os.O_CREATE|os.O_RDWR, os.FileMode(0600))
+			if err != nil {
+				return false, err
+			}
+			f.fh = fh
+			return true, nil
+		}
+	}
+
+	return false, nil
+}

+ 76 - 0
vendor/github.com/gofrs/flock/flock_winapi.go

@@ -0,0 +1,76 @@
+// Copyright 2015 Tim Heckman. All rights reserved.
+// Use of this source code is governed by the BSD 3-Clause
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package flock
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+var (
+	kernel32, _         = syscall.LoadLibrary("kernel32.dll")
+	procLockFileEx, _   = syscall.GetProcAddress(kernel32, "LockFileEx")
+	procUnlockFileEx, _ = syscall.GetProcAddress(kernel32, "UnlockFileEx")
+)
+
+const (
+	winLockfileFailImmediately = 0x00000001
+	winLockfileExclusiveLock   = 0x00000002
+	winLockfileSharedLock      = 0x00000000
+)
+
+// Use of 0x00000000 for the shared lock is a guess based on some the MS Windows
+// `LockFileEX` docs, which document the `LOCKFILE_EXCLUSIVE_LOCK` flag as:
+//
+// > The function requests an exclusive lock. Otherwise, it requests a shared
+// > lock.
+//
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
+
+func lockFileEx(handle syscall.Handle, flags uint32, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (bool, syscall.Errno) {
+	r1, _, errNo := syscall.Syscall6(
+		uintptr(procLockFileEx),
+		6,
+		uintptr(handle),
+		uintptr(flags),
+		uintptr(reserved),
+		uintptr(numberOfBytesToLockLow),
+		uintptr(numberOfBytesToLockHigh),
+		uintptr(unsafe.Pointer(offset)))
+
+	if r1 != 1 {
+		if errNo == 0 {
+			return false, syscall.EINVAL
+		}
+
+		return false, errNo
+	}
+
+	return true, 0
+}
+
+func unlockFileEx(handle syscall.Handle, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (bool, syscall.Errno) {
+	r1, _, errNo := syscall.Syscall6(
+		uintptr(procUnlockFileEx),
+		5,
+		uintptr(handle),
+		uintptr(reserved),
+		uintptr(numberOfBytesToLockLow),
+		uintptr(numberOfBytesToLockHigh),
+		uintptr(unsafe.Pointer(offset)),
+		0)
+
+	if r1 != 1 {
+		if errNo == 0 {
+			return false, syscall.EINVAL
+		}
+
+		return false, errNo
+	}
+
+	return true, 0
+}

+ 140 - 0
vendor/github.com/gofrs/flock/flock_windows.go

@@ -0,0 +1,140 @@
+// Copyright 2015 Tim Heckman. All rights reserved.
+// Use of this source code is governed by the BSD 3-Clause
+// license that can be found in the LICENSE file.
+
+package flock
+
+import (
+	"syscall"
+)
+
+// ErrorLockViolation is the error code returned from the Windows syscall when a
+// lock would block and you ask to fail immediately.
+const ErrorLockViolation syscall.Errno = 0x21 // 33
+
+// Lock is a blocking call to try and take an exclusive file lock. It will wait
+// until it is able to obtain the exclusive file lock. It's recommended that
+// TryLock() be used over this function. This function may block the ability to
+// query the current Locked() or RLocked() status due to a RW-mutex lock.
+//
+// If we are already locked, this function short-circuits and returns
+// immediately assuming it can take the mutex lock.
+func (f *Flock) Lock() error {
+	return f.lock(&f.l, winLockfileExclusiveLock)
+}
+
+// RLock is a blocking call to try and take a shared file lock. It will wait
+// until it is able to obtain the shared file lock. It's recommended that
+// TryRLock() be used over this function. This function may block the ability to
+// query the current Locked() or RLocked() status due to a RW-mutex lock.
+//
+// If we are already locked, this function short-circuits and returns
+// immediately assuming it can take the mutex lock.
+func (f *Flock) RLock() error {
+	return f.lock(&f.r, winLockfileSharedLock)
+}
+
+func (f *Flock) lock(locked *bool, flag uint32) error {
+	f.m.Lock()
+	defer f.m.Unlock()
+
+	if *locked {
+		return nil
+	}
+
+	if f.fh == nil {
+		if err := f.setFh(); err != nil {
+			return err
+		}
+	}
+
+	if _, errNo := lockFileEx(syscall.Handle(f.fh.Fd()), flag, 0, 1, 0, &syscall.Overlapped{}); errNo > 0 {
+		return errNo
+	}
+
+	*locked = true
+	return nil
+}
+
+// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so
+// while it is running the Locked() and RLocked() functions will be blocked.
+//
+// This function short-circuits if we are unlocked already. If not, it calls
+// UnlockFileEx() on the file and closes the file descriptor. It does not remove
+// the file from disk. It's up to your application to do.
+func (f *Flock) Unlock() error {
+	f.m.Lock()
+	defer f.m.Unlock()
+
+	// if we aren't locked or if the lockfile instance is nil
+	// just return a nil error because we are unlocked
+	if (!f.l && !f.r) || f.fh == nil {
+		return nil
+	}
+
+	// mark the file as unlocked
+	if _, errNo := unlockFileEx(syscall.Handle(f.fh.Fd()), 0, 1, 0, &syscall.Overlapped{}); errNo > 0 {
+		return errNo
+	}
+
+	f.fh.Close()
+
+	f.l = false
+	f.r = false
+	f.fh = nil
+
+	return nil
+}
+
+// TryLock is the preferred function for taking an exclusive file lock. This
+// function does take a RW-mutex lock before it tries to lock the file, so there
+// is the possibility that this function may block for a short time if another
+// goroutine is trying to take any action.
+//
+// The actual file lock is non-blocking. If we are unable to get the exclusive
+// file lock, the function will return false instead of waiting for the lock. If
+// we get the lock, we also set the *Flock instance as being exclusive-locked.
+func (f *Flock) TryLock() (bool, error) {
+	return f.try(&f.l, winLockfileExclusiveLock)
+}
+
+// TryRLock is the preferred function for taking a shared file lock. This
+// function does take a RW-mutex lock before it tries to lock the file, so there
+// is the possibility that this function may block for a short time if another
+// goroutine is trying to take any action.
+//
+// The actual file lock is non-blocking. If we are unable to get the shared file
+// lock, the function will return false instead of waiting for the lock. If we
+// get the lock, we also set the *Flock instance as being shared-locked.
+func (f *Flock) TryRLock() (bool, error) {
+	return f.try(&f.r, winLockfileSharedLock)
+}
+
+func (f *Flock) try(locked *bool, flag uint32) (bool, error) {
+	f.m.Lock()
+	defer f.m.Unlock()
+
+	if *locked {
+		return true, nil
+	}
+
+	if f.fh == nil {
+		if err := f.setFh(); err != nil {
+			return false, err
+		}
+	}
+
+	_, errNo := lockFileEx(syscall.Handle(f.fh.Fd()), flag|winLockfileFailImmediately, 0, 1, 0, &syscall.Overlapped{})
+
+	if errNo > 0 {
+		if errNo == ErrorLockViolation || errNo == syscall.ERROR_IO_PENDING {
+			return false, nil
+		}
+
+		return false, errNo
+	}
+
+	*locked = true
+
+	return true, nil
+}

+ 41 - 11
vendor/github.com/moby/buildkit/README.md

@@ -122,7 +122,7 @@ During development, Dockerfile frontend (dockerfile.v0) is also part of the Buil
 
 
 ```
 ```
 buildctl build --frontend=dockerfile.v0 --local context=. --local dockerfile=.
 buildctl build --frontend=dockerfile.v0 --local context=. --local dockerfile=.
-buildctl build --frontend=dockerfile.v0 --local context=. --local dockerfile=. --frontend-opt target=foo --frontend-opt build-arg:foo=bar
+buildctl build --frontend=dockerfile.v0 --local context=. --local dockerfile=. --opt target=foo --opt build-arg:foo=bar
 ```
 ```
 
 
 `--local` exposes local source files from client to the builder. `context` and `dockerfile` are the names Dockerfile frontend looks for build context and Dockerfile location.
 `--local` exposes local source files from client to the builder. `context` and `dockerfile` are the names Dockerfile frontend looks for build context and Dockerfile location.
@@ -146,31 +146,31 @@ docker inspect myimage
 External versions of the Dockerfile frontend are pushed to https://hub.docker.com/r/docker/dockerfile-upstream and https://hub.docker.com/r/docker/dockerfile and can be used with the gateway frontend. The source for the external frontend is currently located in `./frontend/dockerfile/cmd/dockerfile-frontend` but will move out of this repository in the future ([#163](https://github.com/moby/buildkit/issues/163)). For automatic build from master branch of this repository `docker/dockerfile-upsteam:master` or `docker/dockerfile-upstream:master-experimental` image can be used.
 External versions of the Dockerfile frontend are pushed to https://hub.docker.com/r/docker/dockerfile-upstream and https://hub.docker.com/r/docker/dockerfile and can be used with the gateway frontend. The source for the external frontend is currently located in `./frontend/dockerfile/cmd/dockerfile-frontend` but will move out of this repository in the future ([#163](https://github.com/moby/buildkit/issues/163)). For automatic build from master branch of this repository `docker/dockerfile-upsteam:master` or `docker/dockerfile-upstream:master-experimental` image can be used.
 
 
 ```
 ```
-buildctl build --frontend=gateway.v0 --frontend-opt=source=docker/dockerfile --local context=. --local dockerfile=.
-buildctl build --frontend gateway.v0 --frontend-opt=source=docker/dockerfile --frontend-opt=context=git://github.com/moby/moby --frontend-opt build-arg:APT_MIRROR=cdn-fastly.deb.debian.org
+buildctl build --frontend gateway.v0 --opt source=docker/dockerfile --local context=. --local dockerfile=.
+buildctl build --frontend gateway.v0 --opt source=docker/dockerfile --opt context=git://github.com/moby/moby --opt build-arg:APT_MIRROR=cdn-fastly.deb.debian.org
 ````
 ````
 
 
 ##### Building a Dockerfile with experimental features like `RUN --mount=type=(bind|cache|tmpfs|secret|ssh)`
 ##### Building a Dockerfile with experimental features like `RUN --mount=type=(bind|cache|tmpfs|secret|ssh)`
 
 
 See [`frontend/dockerfile/docs/experimental.md`](frontend/dockerfile/docs/experimental.md).
 See [`frontend/dockerfile/docs/experimental.md`](frontend/dockerfile/docs/experimental.md).
 
 
-### Exporters
+### Output
 
 
-By default, the build result and intermediate cache will only remain internally in BuildKit. Exporter needs to be specified to retrieve the result.
+By default, the build result and intermediate cache will only remain internally in BuildKit. An output needs to be specified to retrieve the result.
 
 
 ##### Exporting resulting image to containerd
 ##### Exporting resulting image to containerd
 
 
 The containerd worker needs to be used
 The containerd worker needs to be used
 
 
 ```
 ```
-buildctl build ... --exporter=image --exporter-opt name=docker.io/username/image
+buildctl build ... --output type=image,name=docker.io/username/image
 ctr --namespace=buildkit images ls
 ctr --namespace=buildkit images ls
 ```
 ```
 
 
 ##### Push resulting image to registry
 ##### Push resulting image to registry
 
 
 ```
 ```
-buildctl build ... --exporter=image --exporter-opt name=docker.io/username/image --exporter-opt push=true
+buildctl build ... --output type=image,name=docker.io/username/image,push=true
 ```
 ```
 
 
 If credentials are required, `buildctl` will attempt to read Docker configuration file.
 If credentials are required, `buildctl` will attempt to read Docker configuration file.
@@ -181,23 +181,52 @@ If credentials are required, `buildctl` will attempt to read Docker configuratio
 The local client will copy the files directly to the client. This is useful if BuildKit is being used for building something else than container images.
 The local client will copy the files directly to the client. This is useful if BuildKit is being used for building something else than container images.
 
 
 ```
 ```
-buildctl build ... --exporter=local --exporter-opt output=path/to/output-dir
+buildctl build ... --output type=local,dest=path/to/output-dir
 ```
 ```
 
 
 ##### Exporting built image to Docker
 ##### Exporting built image to Docker
 
 
 ```
 ```
 # exported tarball is also compatible with OCI spec
 # exported tarball is also compatible with OCI spec
-buildctl build ... --exporter=docker --exporter-opt name=myimage | docker load
+buildctl build ... --output type=docker,name=myimage | docker load
 ```
 ```
 
 
 ##### Exporting [OCI Image Format](https://github.com/opencontainers/image-spec) tarball to client
 ##### Exporting [OCI Image Format](https://github.com/opencontainers/image-spec) tarball to client
 
 
 ```
 ```
-buildctl build ... --exporter=oci --exporter-opt output=path/to/output.tar
-buildctl build ... --exporter=oci > output.tar
+buildctl build ... --output type=oci,dest=path/to/output.tar
+buildctl build ... --output type=oci > output.tar
 ```
 ```
 
 
+### Exporting/Importing build cache (not image itself)
+
+#### To/From registry
+
+```
+buildctl build ... --export-cache type=registry,ref=localhost:5000/myrepo:buildcache
+buildctl build ... --import-cache type=registry,ref=localhost:5000/myrepo:buildcache
+```
+
+#### To/From local filesystem
+
+```
+buildctl build ... --export-cache type=local,src=path/to/input-dir
+buildctl build ... --import-cache type=local,dest=path/to/output-dir
+```
+
+The directory layout conforms to OCI Image Spec v1.0.
+
+#### `--export-cache` options
+* `mode=min` (default): only export layers for the resulting image
+* `mode=max`: export all the layers of all intermediate steps
+* `ref=docker.io/user/image:tag`: reference for `registry` cache exporter
+* `src=path/to/output-dir`: directory for `local` cache exporter
+
+#### `--import-cache` options
+* `ref=docker.io/user/image:tag`: reference for `registry` cache importer
+* `dest=path/to/input-dir`: directory for `local` cache importer
+* `digest=sha256:deadbeef`: digest of the manifest list to import for `local` cache importer. Defaults to the digest of "latest" tag in `index.json`
+
 ### Other
 ### Other
 
 
 #### View build cache
 #### View build cache
@@ -232,6 +261,7 @@ buildctl build --help
 ```
 ```
 
 
 The images can be also built locally using `./hack/dockerfiles/test.Dockerfile` (or `./hack/dockerfiles/test.buildkit.Dockerfile` if you already have BuildKit).
 The images can be also built locally using `./hack/dockerfiles/test.Dockerfile` (or `./hack/dockerfiles/test.buildkit.Dockerfile` if you already have BuildKit).
+Run `make images` to build the images as `moby/buildkit:local` and `moby/buildkit:local-rootless`.
 
 
 ### Opentracing support
 ### Opentracing support
 
 

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 685 - 149
vendor/github.com/moby/buildkit/api/services/control/control.pb.go


+ 26 - 4
vendor/github.com/moby/buildkit/api/services/control/control.proto

@@ -66,9 +66,31 @@ message SolveRequest {
 }
 }
 
 
 message CacheOptions {
 message CacheOptions {
-	string ExportRef = 1;
-	repeated string ImportRefs = 2;
-	map<string, string> ExportAttrs = 3;
+	// ExportRefDeprecated is deprecated in favor or the new Exports since BuildKit v0.4.0.
+	// When ExportRefDeprecated is set, the solver appends
+	// {.Type = "registry", .Attrs = ExportAttrs.add("ref", ExportRef)}
+	// to Exports for compatibility. (planned to be removed)
+	string ExportRefDeprecated = 1;
+	// ImportRefsDeprecated is deprecated in favor or the new Imports since BuildKit v0.4.0.
+	// When ImportRefsDeprecated is set, the solver appends
+	// {.Type = "registry", .Attrs = {"ref": importRef}}
+	// for each of the ImportRefs entry to Imports for compatibility. (planned to be removed)
+	repeated string ImportRefsDeprecated = 2;
+	// ExportAttrsDeprecated is deprecated since BuildKit v0.4.0.
+	// See the description of ExportRefDeprecated.
+	map<string, string> ExportAttrsDeprecated = 3;
+	// Exports was introduced in BuildKit v0.4.0.
+	repeated CacheOptionsEntry Exports = 4;
+	// Imports was introduced in BuildKit v0.4.0.
+	repeated CacheOptionsEntry Imports = 5;
+}
+
+message CacheOptionsEntry {
+	// Type is like "registry" or "local"
+	string Type = 1;
+	// Attrs are like mode=(min,max), ref=example.com:5000/foo/bar .
+	// See cache importer/exporter implementations' documentation.
+	map<string, string> Attrs = 2;
 }
 }
 
 
 message SolveResponse {
 message SolveResponse {
@@ -124,4 +146,4 @@ message ListWorkersRequest {
 
 
 message ListWorkersResponse {
 message ListWorkersResponse {
 	repeated moby.buildkit.v1.types.WorkerRecord record = 1;
 	repeated moby.buildkit.v1.types.WorkerRecord record = 1;
-}
+}

+ 101 - 28
vendor/github.com/moby/buildkit/api/types/worker.pb.go

@@ -1,16 +1,6 @@
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // source: worker.proto
 // source: worker.proto
 
 
-/*
-	Package moby_buildkit_v1_types is a generated protocol buffer package.
-
-	It is generated from these files:
-		worker.proto
-
-	It has these top-level messages:
-		WorkerRecord
-		GCPolicy
-*/
 package moby_buildkit_v1_types
 package moby_buildkit_v1_types
 
 
 import proto "github.com/gogo/protobuf/proto"
 import proto "github.com/gogo/protobuf/proto"
@@ -33,16 +23,47 @@ var _ = math.Inf
 const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
 const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
 
 
 type WorkerRecord struct {
 type WorkerRecord struct {
-	ID        string            `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
-	Labels    map[string]string `protobuf:"bytes,2,rep,name=Labels" json:"Labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
-	Platforms []pb.Platform     `protobuf:"bytes,3,rep,name=platforms" json:"platforms"`
-	GCPolicy  []*GCPolicy       `protobuf:"bytes,4,rep,name=GCPolicy" json:"GCPolicy,omitempty"`
+	ID                   string            `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
+	Labels               map[string]string `protobuf:"bytes,2,rep,name=Labels,proto3" json:"Labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	Platforms            []pb.Platform     `protobuf:"bytes,3,rep,name=platforms,proto3" json:"platforms"`
+	GCPolicy             []*GCPolicy       `protobuf:"bytes,4,rep,name=GCPolicy,proto3" json:"GCPolicy,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}          `json:"-"`
+	XXX_unrecognized     []byte            `json:"-"`
+	XXX_sizecache        int32             `json:"-"`
 }
 }
 
 
-func (m *WorkerRecord) Reset()                    { *m = WorkerRecord{} }
-func (m *WorkerRecord) String() string            { return proto.CompactTextString(m) }
-func (*WorkerRecord) ProtoMessage()               {}
-func (*WorkerRecord) Descriptor() ([]byte, []int) { return fileDescriptorWorker, []int{0} }
+func (m *WorkerRecord) Reset()         { *m = WorkerRecord{} }
+func (m *WorkerRecord) String() string { return proto.CompactTextString(m) }
+func (*WorkerRecord) ProtoMessage()    {}
+func (*WorkerRecord) Descriptor() ([]byte, []int) {
+	return fileDescriptor_worker_1d0a62be5114ecbf, []int{0}
+}
+func (m *WorkerRecord) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *WorkerRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_WorkerRecord.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (dst *WorkerRecord) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_WorkerRecord.Merge(dst, src)
+}
+func (m *WorkerRecord) XXX_Size() int {
+	return m.Size()
+}
+func (m *WorkerRecord) XXX_DiscardUnknown() {
+	xxx_messageInfo_WorkerRecord.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_WorkerRecord proto.InternalMessageInfo
 
 
 func (m *WorkerRecord) GetID() string {
 func (m *WorkerRecord) GetID() string {
 	if m != nil {
 	if m != nil {
@@ -73,16 +94,47 @@ func (m *WorkerRecord) GetGCPolicy() []*GCPolicy {
 }
 }
 
 
 type GCPolicy struct {
 type GCPolicy struct {
-	All          bool     `protobuf:"varint,1,opt,name=all,proto3" json:"all,omitempty"`
-	KeepDuration int64    `protobuf:"varint,2,opt,name=keepDuration,proto3" json:"keepDuration,omitempty"`
-	KeepBytes    int64    `protobuf:"varint,3,opt,name=keepBytes,proto3" json:"keepBytes,omitempty"`
-	Filters      []string `protobuf:"bytes,4,rep,name=filters" json:"filters,omitempty"`
+	All                  bool     `protobuf:"varint,1,opt,name=all,proto3" json:"all,omitempty"`
+	KeepDuration         int64    `protobuf:"varint,2,opt,name=keepDuration,proto3" json:"keepDuration,omitempty"`
+	KeepBytes            int64    `protobuf:"varint,3,opt,name=keepBytes,proto3" json:"keepBytes,omitempty"`
+	Filters              []string `protobuf:"bytes,4,rep,name=filters,proto3" json:"filters,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *GCPolicy) Reset()         { *m = GCPolicy{} }
+func (m *GCPolicy) String() string { return proto.CompactTextString(m) }
+func (*GCPolicy) ProtoMessage()    {}
+func (*GCPolicy) Descriptor() ([]byte, []int) {
+	return fileDescriptor_worker_1d0a62be5114ecbf, []int{1}
+}
+func (m *GCPolicy) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *GCPolicy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_GCPolicy.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (dst *GCPolicy) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_GCPolicy.Merge(dst, src)
+}
+func (m *GCPolicy) XXX_Size() int {
+	return m.Size()
+}
+func (m *GCPolicy) XXX_DiscardUnknown() {
+	xxx_messageInfo_GCPolicy.DiscardUnknown(m)
 }
 }
 
 
-func (m *GCPolicy) Reset()                    { *m = GCPolicy{} }
-func (m *GCPolicy) String() string            { return proto.CompactTextString(m) }
-func (*GCPolicy) ProtoMessage()               {}
-func (*GCPolicy) Descriptor() ([]byte, []int) { return fileDescriptorWorker, []int{1} }
+var xxx_messageInfo_GCPolicy proto.InternalMessageInfo
 
 
 func (m *GCPolicy) GetAll() bool {
 func (m *GCPolicy) GetAll() bool {
 	if m != nil {
 	if m != nil {
@@ -114,6 +166,7 @@ func (m *GCPolicy) GetFilters() []string {
 
 
 func init() {
 func init() {
 	proto.RegisterType((*WorkerRecord)(nil), "moby.buildkit.v1.types.WorkerRecord")
 	proto.RegisterType((*WorkerRecord)(nil), "moby.buildkit.v1.types.WorkerRecord")
+	proto.RegisterMapType((map[string]string)(nil), "moby.buildkit.v1.types.WorkerRecord.LabelsEntry")
 	proto.RegisterType((*GCPolicy)(nil), "moby.buildkit.v1.types.GCPolicy")
 	proto.RegisterType((*GCPolicy)(nil), "moby.buildkit.v1.types.GCPolicy")
 }
 }
 func (m *WorkerRecord) Marshal() (dAtA []byte, err error) {
 func (m *WorkerRecord) Marshal() (dAtA []byte, err error) {
@@ -178,6 +231,9 @@ func (m *WorkerRecord) MarshalTo(dAtA []byte) (int, error) {
 			i += n
 			i += n
 		}
 		}
 	}
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 	return i, nil
 }
 }
 
 
@@ -231,6 +287,9 @@ func (m *GCPolicy) MarshalTo(dAtA []byte) (int, error) {
 			i += copy(dAtA[i:], s)
 			i += copy(dAtA[i:], s)
 		}
 		}
 	}
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 	return i, nil
 }
 }
 
 
@@ -244,6 +303,9 @@ func encodeVarintWorker(dAtA []byte, offset int, v uint64) int {
 	return offset + 1
 	return offset + 1
 }
 }
 func (m *WorkerRecord) Size() (n int) {
 func (m *WorkerRecord) Size() (n int) {
+	if m == nil {
+		return 0
+	}
 	var l int
 	var l int
 	_ = l
 	_ = l
 	l = len(m.ID)
 	l = len(m.ID)
@@ -270,10 +332,16 @@ func (m *WorkerRecord) Size() (n int) {
 			n += 1 + l + sovWorker(uint64(l))
 			n += 1 + l + sovWorker(uint64(l))
 		}
 		}
 	}
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 	return n
 }
 }
 
 
 func (m *GCPolicy) Size() (n int) {
 func (m *GCPolicy) Size() (n int) {
+	if m == nil {
+		return 0
+	}
 	var l int
 	var l int
 	_ = l
 	_ = l
 	if m.All {
 	if m.All {
@@ -291,6 +359,9 @@ func (m *GCPolicy) Size() (n int) {
 			n += 1 + l + sovWorker(uint64(l))
 			n += 1 + l + sovWorker(uint64(l))
 		}
 		}
 	}
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 	return n
 }
 }
 
 
@@ -557,6 +628,7 @@ func (m *WorkerRecord) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 				return io.ErrUnexpectedEOF
 			}
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 			iNdEx += skippy
 		}
 		}
 	}
 	}
@@ -694,6 +766,7 @@ func (m *GCPolicy) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 				return io.ErrUnexpectedEOF
 			}
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 			iNdEx += skippy
 		}
 		}
 	}
 	}
@@ -808,9 +881,9 @@ var (
 	ErrIntOverflowWorker   = fmt.Errorf("proto: integer overflow")
 	ErrIntOverflowWorker   = fmt.Errorf("proto: integer overflow")
 )
 )
 
 
-func init() { proto.RegisterFile("worker.proto", fileDescriptorWorker) }
+func init() { proto.RegisterFile("worker.proto", fileDescriptor_worker_1d0a62be5114ecbf) }
 
 
-var fileDescriptorWorker = []byte{
+var fileDescriptor_worker_1d0a62be5114ecbf = []byte{
 	// 355 bytes of a gzipped FileDescriptorProto
 	// 355 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0xc1, 0x4e, 0xea, 0x40,
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0xc1, 0x4e, 0xea, 0x40,
 	0x14, 0x86, 0x6f, 0x5b, 0x2e, 0x97, 0x0e, 0xcd, 0x8d, 0x99, 0x18, 0xd3, 0x10, 0x83, 0x84, 0x15,
 	0x14, 0x86, 0x6f, 0x5b, 0x2e, 0x97, 0x0e, 0xcd, 0x8d, 0x99, 0x18, 0xd3, 0x10, 0x83, 0x84, 0x15,

+ 157 - 29
vendor/github.com/moby/buildkit/cache/contenthash/checksum.go

@@ -43,8 +43,8 @@ func getDefaultManager() *cacheManager {
 // header, "/dir" is for contents. For the root node "" (empty string) is the
 // header, "/dir" is for contents. For the root node "" (empty string) is the
 // key for root, "/" for the root header
 // key for root, "/" for the root header
 
 
-func Checksum(ctx context.Context, ref cache.ImmutableRef, path string) (digest.Digest, error) {
-	return getDefaultManager().Checksum(ctx, ref, path)
+func Checksum(ctx context.Context, ref cache.ImmutableRef, path string, followLinks bool) (digest.Digest, error) {
+	return getDefaultManager().Checksum(ctx, ref, path, followLinks)
 }
 }
 
 
 func GetCacheContext(ctx context.Context, md *metadata.StorageItem) (CacheContext, error) {
 func GetCacheContext(ctx context.Context, md *metadata.StorageItem) (CacheContext, error) {
@@ -56,7 +56,8 @@ func SetCacheContext(ctx context.Context, md *metadata.StorageItem, cc CacheCont
 }
 }
 
 
 type CacheContext interface {
 type CacheContext interface {
-	Checksum(ctx context.Context, ref cache.Mountable, p string) (digest.Digest, error)
+	Checksum(ctx context.Context, ref cache.Mountable, p string, followLinks bool) (digest.Digest, error)
+	ChecksumWildcard(ctx context.Context, ref cache.Mountable, p string, followLinks bool) (digest.Digest, error)
 	HandleChange(kind fsutil.ChangeKind, p string, fi os.FileInfo, err error) error
 	HandleChange(kind fsutil.ChangeKind, p string, fi os.FileInfo, err error) error
 }
 }
 
 
@@ -64,18 +65,23 @@ type Hashed interface {
 	Digest() digest.Digest
 	Digest() digest.Digest
 }
 }
 
 
+type Wildcard struct {
+	Path   string
+	Record *CacheRecord
+}
+
 type cacheManager struct {
 type cacheManager struct {
 	locker *locker.Locker
 	locker *locker.Locker
 	lru    *simplelru.LRU
 	lru    *simplelru.LRU
 	lruMu  sync.Mutex
 	lruMu  sync.Mutex
 }
 }
 
 
-func (cm *cacheManager) Checksum(ctx context.Context, ref cache.ImmutableRef, p string) (digest.Digest, error) {
+func (cm *cacheManager) Checksum(ctx context.Context, ref cache.ImmutableRef, p string, followLinks bool) (digest.Digest, error) {
 	cc, err := cm.GetCacheContext(ctx, ensureOriginMetadata(ref.Metadata()))
 	cc, err := cm.GetCacheContext(ctx, ensureOriginMetadata(ref.Metadata()))
 	if err != nil {
 	if err != nil {
 		return "", nil
 		return "", nil
 	}
 	}
-	return cc.Checksum(ctx, ref, p)
+	return cc.Checksum(ctx, ref, p, followLinks)
 }
 }
 
 
 func (cm *cacheManager) GetCacheContext(ctx context.Context, md *metadata.StorageItem) (CacheContext, error) {
 func (cm *cacheManager) GetCacheContext(ctx context.Context, md *metadata.StorageItem) (CacheContext, error) {
@@ -317,10 +323,49 @@ func (cc *cacheContext) HandleChange(kind fsutil.ChangeKind, p string, fi os.Fil
 	return nil
 	return nil
 }
 }
 
 
-func (cc *cacheContext) Checksum(ctx context.Context, mountable cache.Mountable, p string) (digest.Digest, error) {
+func (cc *cacheContext) ChecksumWildcard(ctx context.Context, mountable cache.Mountable, p string, followLinks bool) (digest.Digest, error) {
 	m := &mount{mountable: mountable}
 	m := &mount{mountable: mountable}
 	defer m.clean()
 	defer m.clean()
 
 
+	wildcards, err := cc.wildcards(ctx, m, p)
+	if err != nil {
+		return "", nil
+	}
+
+	if followLinks {
+		for i, w := range wildcards {
+			if w.Record.Type == CacheRecordTypeSymlink {
+				dgst, err := cc.checksumFollow(ctx, m, w.Path, followLinks)
+				if err != nil {
+					return "", err
+				}
+				wildcards[i].Record = &CacheRecord{Digest: dgst}
+			}
+		}
+	}
+
+	if len(wildcards) > 1 {
+		digester := digest.Canonical.Digester()
+		for i, w := range wildcards {
+			if i != 0 {
+				digester.Hash().Write([]byte{0})
+			}
+			digester.Hash().Write([]byte(w.Record.Digest))
+		}
+		return digester.Digest(), nil
+	} else {
+		return wildcards[0].Record.Digest, nil
+	}
+}
+
+func (cc *cacheContext) Checksum(ctx context.Context, mountable cache.Mountable, p string, followLinks bool) (digest.Digest, error) {
+	m := &mount{mountable: mountable}
+	defer m.clean()
+
+	return cc.checksumFollow(ctx, m, p, followLinks)
+}
+
+func (cc *cacheContext) checksumFollow(ctx context.Context, m *mount, p string, follow bool) (digest.Digest, error) {
 	const maxSymlinkLimit = 255
 	const maxSymlinkLimit = 255
 	i := 0
 	i := 0
 	for {
 	for {
@@ -331,7 +376,7 @@ func (cc *cacheContext) Checksum(ctx context.Context, mountable cache.Mountable,
 		if err != nil {
 		if err != nil {
 			return "", err
 			return "", err
 		}
 		}
-		if cr.Type == CacheRecordTypeSymlink {
+		if cr.Type == CacheRecordTypeSymlink && follow {
 			link := cr.Linkname
 			link := cr.Linkname
 			if !path.IsAbs(cr.Linkname) {
 			if !path.IsAbs(cr.Linkname) {
 				link = path.Join(path.Dir(p), link)
 				link = path.Join(path.Dir(p), link)
@@ -344,6 +389,82 @@ func (cc *cacheContext) Checksum(ctx context.Context, mountable cache.Mountable,
 	}
 	}
 }
 }
 
 
+func (cc *cacheContext) wildcards(ctx context.Context, m *mount, p string) ([]*Wildcard, error) {
+	cc.mu.Lock()
+	defer cc.mu.Unlock()
+
+	if cc.txn != nil {
+		cc.commitActiveTransaction()
+	}
+
+	root := cc.tree.Root()
+	scan, err := cc.needsScan(root, "")
+	if err != nil {
+		return nil, err
+	}
+	if scan {
+		if err := cc.scanPath(ctx, m, ""); err != nil {
+			return nil, err
+		}
+	}
+
+	defer func() {
+		if cc.dirty {
+			go cc.save()
+			cc.dirty = false
+		}
+	}()
+
+	p = path.Join("/", filepath.ToSlash(p))
+	if p == "/" {
+		p = ""
+	}
+
+	wildcards := make([]*Wildcard, 0, 2)
+
+	txn := cc.tree.Txn()
+	root = txn.Root()
+	var updated bool
+
+	iter := root.Seek([]byte{})
+	for {
+		k, _, ok := iter.Next()
+		if !ok {
+			break
+		}
+		if len(k) > 0 && k[len(k)-1] == byte(0) {
+			continue
+		}
+		fn := convertKeyToPath(k)
+		b, err := path.Match(p, string(fn))
+		if err != nil {
+			return nil, err
+		}
+		if !b {
+			continue
+		}
+
+		cr, upt, err := cc.checksum(ctx, root, txn, m, k, false)
+		if err != nil {
+			return nil, err
+		}
+		if upt {
+			updated = true
+		}
+
+		wildcards = append(wildcards, &Wildcard{Path: string(fn), Record: cr})
+
+		if cr.Type == CacheRecordTypeDir {
+			iter = root.Seek(append(k, 0, 0xff))
+		}
+	}
+
+	cc.tree = txn.Commit()
+	cc.dirty = updated
+
+	return wildcards, nil
+}
+
 func (cc *cacheContext) checksumNoFollow(ctx context.Context, m *mount, p string) (*CacheRecord, error) {
 func (cc *cacheContext) checksumNoFollow(ctx context.Context, m *mount, p string) (*CacheRecord, error) {
 	p = path.Join("/", filepath.ToSlash(p))
 	p = path.Join("/", filepath.ToSlash(p))
 	if p == "/" {
 	if p == "/" {
@@ -412,7 +533,7 @@ func (cc *cacheContext) lazyChecksum(ctx context.Context, m *mount, p string) (*
 	k := convertPathToKey([]byte(p))
 	k := convertPathToKey([]byte(p))
 	txn := cc.tree.Txn()
 	txn := cc.tree.Txn()
 	root = txn.Root()
 	root = txn.Root()
-	cr, updated, err := cc.checksum(ctx, root, txn, m, k)
+	cr, updated, err := cc.checksum(ctx, root, txn, m, k, true)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -421,8 +542,8 @@ func (cc *cacheContext) lazyChecksum(ctx context.Context, m *mount, p string) (*
 	return cr, err
 	return cr, err
 }
 }
 
 
-func (cc *cacheContext) checksum(ctx context.Context, root *iradix.Node, txn *iradix.Txn, m *mount, k []byte) (*CacheRecord, bool, error) {
-	k, cr, err := getFollowLinks(root, k)
+func (cc *cacheContext) checksum(ctx context.Context, root *iradix.Node, txn *iradix.Txn, m *mount, k []byte, follow bool) (*CacheRecord, bool, error) {
+	k, cr, err := getFollowLinks(root, k, follow)
 	if err != nil {
 	if err != nil {
 		return nil, false, err
 		return nil, false, err
 	}
 	}
@@ -447,7 +568,7 @@ func (cc *cacheContext) checksum(ctx context.Context, root *iradix.Node, txn *ir
 			}
 			}
 			h.Write(bytes.TrimPrefix(subk, k))
 			h.Write(bytes.TrimPrefix(subk, k))
 
 
-			subcr, _, err := cc.checksum(ctx, root, txn, m, subk)
+			subcr, _, err := cc.checksum(ctx, root, txn, m, subk, true)
 			if err != nil {
 			if err != nil {
 				return nil, false, err
 				return nil, false, err
 			}
 			}
@@ -599,42 +720,49 @@ func (cc *cacheContext) scanPath(ctx context.Context, m *mount, p string) (retEr
 	return nil
 	return nil
 }
 }
 
 
-func getFollowLinks(root *iradix.Node, k []byte) ([]byte, *CacheRecord, error) {
+func getFollowLinks(root *iradix.Node, k []byte, follow bool) ([]byte, *CacheRecord, error) {
 	var linksWalked int
 	var linksWalked int
-	return getFollowLinksWalk(root, k, &linksWalked)
+	return getFollowLinksWalk(root, k, follow, &linksWalked)
 }
 }
 
 
-func getFollowLinksWalk(root *iradix.Node, k []byte, linksWalked *int) ([]byte, *CacheRecord, error) {
+func getFollowLinksWalk(root *iradix.Node, k []byte, follow bool, linksWalked *int) ([]byte, *CacheRecord, error) {
 	v, ok := root.Get(k)
 	v, ok := root.Get(k)
 	if ok {
 	if ok {
 		return k, v.(*CacheRecord), nil
 		return k, v.(*CacheRecord), nil
 	}
 	}
-	if len(k) == 0 {
+	if !follow || len(k) == 0 {
 		return nil, nil, nil
 		return nil, nil, nil
 	}
 	}
 
 
 	dir, file := splitKey(k)
 	dir, file := splitKey(k)
 
 
-	_, parent, err := getFollowLinksWalk(root, dir, linksWalked)
+	k, parent, err := getFollowLinksWalk(root, dir, follow, linksWalked)
 	if err != nil {
 	if err != nil {
 		return nil, nil, err
 		return nil, nil, err
 	}
 	}
-	if parent != nil && parent.Type == CacheRecordTypeSymlink {
-		*linksWalked++
-		if *linksWalked > 255 {
-			return nil, nil, errors.Errorf("too many links")
-		}
-		dirPath := path.Clean(string(convertKeyToPath(dir)))
-		if dirPath == "." || dirPath == "/" {
-			dirPath = ""
+	if parent != nil {
+		if parent.Type == CacheRecordTypeSymlink {
+			*linksWalked++
+			if *linksWalked > 255 {
+				return nil, nil, errors.Errorf("too many links")
+			}
+			dirPath := path.Clean(string(convertKeyToPath(dir)))
+			if dirPath == "." || dirPath == "/" {
+				dirPath = ""
+			}
+			link := path.Clean(parent.Linkname)
+			if !path.IsAbs(link) {
+				link = path.Join("/", path.Join(path.Dir(dirPath), link))
+			}
+			return getFollowLinksWalk(root, append(convertPathToKey([]byte(link)), file...), follow, linksWalked)
 		}
 		}
-		link := path.Clean(parent.Linkname)
-		if !path.IsAbs(link) {
-			link = path.Join("/", path.Join(path.Dir(dirPath), link))
+
+		k = append(k, file...)
+		v, ok = root.Get(k)
+		if ok {
+			return k, v.(*CacheRecord), nil
 		}
 		}
-		return getFollowLinksWalk(root, append(convertPathToKey([]byte(link)), file...), linksWalked)
 	}
 	}
-
 	return nil, nil, nil
 	return nil, nil, nil
 }
 }
 
 

+ 141 - 57
vendor/github.com/moby/buildkit/cache/contenthash/checksum.pb.go

@@ -1,17 +1,6 @@
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // source: checksum.proto
 // source: checksum.proto
 
 
-/*
-	Package contenthash is a generated protocol buffer package.
-
-	It is generated from these files:
-		checksum.proto
-
-	It has these top-level messages:
-		CacheRecord
-		CacheRecordWithPath
-		CacheRecords
-*/
 package contenthash
 package contenthash
 
 
 import proto "github.com/gogo/protobuf/proto"
 import proto "github.com/gogo/protobuf/proto"
@@ -59,7 +48,9 @@ var CacheRecordType_value = map[string]int32{
 func (x CacheRecordType) String() string {
 func (x CacheRecordType) String() string {
 	return proto.EnumName(CacheRecordType_name, int32(x))
 	return proto.EnumName(CacheRecordType_name, int32(x))
 }
 }
-func (CacheRecordType) EnumDescriptor() ([]byte, []int) { return fileDescriptorChecksum, []int{0} }
+func (CacheRecordType) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor_checksum_efc6501bf3727db3, []int{0}
+}
 
 
 type CacheRecord struct {
 type CacheRecord struct {
 	Digest   github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"`
 	Digest   github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"`
@@ -67,10 +58,38 @@ type CacheRecord struct {
 	Linkname string                                     `protobuf:"bytes,3,opt,name=linkname,proto3" json:"linkname,omitempty"`
 	Linkname string                                     `protobuf:"bytes,3,opt,name=linkname,proto3" json:"linkname,omitempty"`
 }
 }
 
 
-func (m *CacheRecord) Reset()                    { *m = CacheRecord{} }
-func (m *CacheRecord) String() string            { return proto.CompactTextString(m) }
-func (*CacheRecord) ProtoMessage()               {}
-func (*CacheRecord) Descriptor() ([]byte, []int) { return fileDescriptorChecksum, []int{0} }
+func (m *CacheRecord) Reset()         { *m = CacheRecord{} }
+func (m *CacheRecord) String() string { return proto.CompactTextString(m) }
+func (*CacheRecord) ProtoMessage()    {}
+func (*CacheRecord) Descriptor() ([]byte, []int) {
+	return fileDescriptor_checksum_efc6501bf3727db3, []int{0}
+}
+func (m *CacheRecord) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *CacheRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_CacheRecord.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (dst *CacheRecord) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_CacheRecord.Merge(dst, src)
+}
+func (m *CacheRecord) XXX_Size() int {
+	return m.Size()
+}
+func (m *CacheRecord) XXX_DiscardUnknown() {
+	xxx_messageInfo_CacheRecord.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CacheRecord proto.InternalMessageInfo
 
 
 func (m *CacheRecord) GetType() CacheRecordType {
 func (m *CacheRecord) GetType() CacheRecordType {
 	if m != nil {
 	if m != nil {
@@ -88,13 +107,41 @@ func (m *CacheRecord) GetLinkname() string {
 
 
 type CacheRecordWithPath struct {
 type CacheRecordWithPath struct {
 	Path   string       `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
 	Path   string       `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
-	Record *CacheRecord `protobuf:"bytes,2,opt,name=record" json:"record,omitempty"`
+	Record *CacheRecord `protobuf:"bytes,2,opt,name=record,proto3" json:"record,omitempty"`
+}
+
+func (m *CacheRecordWithPath) Reset()         { *m = CacheRecordWithPath{} }
+func (m *CacheRecordWithPath) String() string { return proto.CompactTextString(m) }
+func (*CacheRecordWithPath) ProtoMessage()    {}
+func (*CacheRecordWithPath) Descriptor() ([]byte, []int) {
+	return fileDescriptor_checksum_efc6501bf3727db3, []int{1}
+}
+func (m *CacheRecordWithPath) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *CacheRecordWithPath) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_CacheRecordWithPath.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (dst *CacheRecordWithPath) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_CacheRecordWithPath.Merge(dst, src)
+}
+func (m *CacheRecordWithPath) XXX_Size() int {
+	return m.Size()
+}
+func (m *CacheRecordWithPath) XXX_DiscardUnknown() {
+	xxx_messageInfo_CacheRecordWithPath.DiscardUnknown(m)
 }
 }
 
 
-func (m *CacheRecordWithPath) Reset()                    { *m = CacheRecordWithPath{} }
-func (m *CacheRecordWithPath) String() string            { return proto.CompactTextString(m) }
-func (*CacheRecordWithPath) ProtoMessage()               {}
-func (*CacheRecordWithPath) Descriptor() ([]byte, []int) { return fileDescriptorChecksum, []int{1} }
+var xxx_messageInfo_CacheRecordWithPath proto.InternalMessageInfo
 
 
 func (m *CacheRecordWithPath) GetPath() string {
 func (m *CacheRecordWithPath) GetPath() string {
 	if m != nil {
 	if m != nil {
@@ -111,13 +158,41 @@ func (m *CacheRecordWithPath) GetRecord() *CacheRecord {
 }
 }
 
 
 type CacheRecords struct {
 type CacheRecords struct {
-	Paths []*CacheRecordWithPath `protobuf:"bytes,1,rep,name=paths" json:"paths,omitempty"`
+	Paths []*CacheRecordWithPath `protobuf:"bytes,1,rep,name=paths,proto3" json:"paths,omitempty"`
+}
+
+func (m *CacheRecords) Reset()         { *m = CacheRecords{} }
+func (m *CacheRecords) String() string { return proto.CompactTextString(m) }
+func (*CacheRecords) ProtoMessage()    {}
+func (*CacheRecords) Descriptor() ([]byte, []int) {
+	return fileDescriptor_checksum_efc6501bf3727db3, []int{2}
+}
+func (m *CacheRecords) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *CacheRecords) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_CacheRecords.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (dst *CacheRecords) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_CacheRecords.Merge(dst, src)
+}
+func (m *CacheRecords) XXX_Size() int {
+	return m.Size()
+}
+func (m *CacheRecords) XXX_DiscardUnknown() {
+	xxx_messageInfo_CacheRecords.DiscardUnknown(m)
 }
 }
 
 
-func (m *CacheRecords) Reset()                    { *m = CacheRecords{} }
-func (m *CacheRecords) String() string            { return proto.CompactTextString(m) }
-func (*CacheRecords) ProtoMessage()               {}
-func (*CacheRecords) Descriptor() ([]byte, []int) { return fileDescriptorChecksum, []int{2} }
+var xxx_messageInfo_CacheRecords proto.InternalMessageInfo
 
 
 func (m *CacheRecords) GetPaths() []*CacheRecordWithPath {
 func (m *CacheRecords) GetPaths() []*CacheRecordWithPath {
 	if m != nil {
 	if m != nil {
@@ -241,6 +316,9 @@ func encodeVarintChecksum(dAtA []byte, offset int, v uint64) int {
 	return offset + 1
 	return offset + 1
 }
 }
 func (m *CacheRecord) Size() (n int) {
 func (m *CacheRecord) Size() (n int) {
+	if m == nil {
+		return 0
+	}
 	var l int
 	var l int
 	_ = l
 	_ = l
 	l = len(m.Digest)
 	l = len(m.Digest)
@@ -258,6 +336,9 @@ func (m *CacheRecord) Size() (n int) {
 }
 }
 
 
 func (m *CacheRecordWithPath) Size() (n int) {
 func (m *CacheRecordWithPath) Size() (n int) {
+	if m == nil {
+		return 0
+	}
 	var l int
 	var l int
 	_ = l
 	_ = l
 	l = len(m.Path)
 	l = len(m.Path)
@@ -272,6 +353,9 @@ func (m *CacheRecordWithPath) Size() (n int) {
 }
 }
 
 
 func (m *CacheRecords) Size() (n int) {
 func (m *CacheRecords) Size() (n int) {
+	if m == nil {
+		return 0
+	}
 	var l int
 	var l int
 	_ = l
 	_ = l
 	if len(m.Paths) > 0 {
 	if len(m.Paths) > 0 {
@@ -721,35 +805,35 @@ var (
 	ErrIntOverflowChecksum   = fmt.Errorf("proto: integer overflow")
 	ErrIntOverflowChecksum   = fmt.Errorf("proto: integer overflow")
 )
 )
 
 
-func init() { proto.RegisterFile("checksum.proto", fileDescriptorChecksum) }
-
-var fileDescriptorChecksum = []byte{
-	// 418 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xc1, 0x6a, 0xd4, 0x40,
-	0x18, 0xc7, 0x77, 0xba, 0xeb, 0xaa, 0xdf, 0x4a, 0x0d, 0x53, 0x68, 0xc3, 0x50, 0xb2, 0xe3, 0x5e,
-	0x5c, 0x8a, 0xcd, 0x96, 0x08, 0xde, 0xad, 0xd9, 0xa5, 0xd1, 0x2a, 0x32, 0x15, 0x44, 0x3c, 0x48,
-	0x36, 0x3b, 0x66, 0x42, 0x9b, 0x4c, 0x48, 0x66, 0x0f, 0xfb, 0x06, 0x92, 0x93, 0x2f, 0x90, 0x93,
-	0x82, 0xef, 0xe0, 0x5d, 0xe8, 0xd1, 0xb3, 0x87, 0x22, 0xeb, 0x8b, 0x48, 0x26, 0x55, 0x42, 0xca,
-	0x9e, 0xe6, 0xfb, 0x66, 0x7e, 0xdf, 0xff, 0xff, 0x9f, 0x61, 0x60, 0x3b, 0x10, 0x3c, 0x38, 0xcf,
-	0x97, 0xb1, 0x9d, 0x66, 0x52, 0x49, 0x3c, 0x08, 0x64, 0xa2, 0x78, 0xa2, 0x84, 0x9f, 0x0b, 0x72,
-	0x18, 0x46, 0x4a, 0x2c, 0xe7, 0x76, 0x20, 0xe3, 0x49, 0x28, 0x43, 0x39, 0xd1, 0xcc, 0x7c, 0xf9,
-	0x51, 0x77, 0xba, 0xd1, 0x55, 0x3d, 0x3b, 0xfa, 0x86, 0x60, 0xf0, 0xcc, 0x0f, 0x04, 0x67, 0x3c,
-	0x90, 0xd9, 0x02, 0x3f, 0x87, 0xfe, 0x22, 0x0a, 0x79, 0xae, 0x4c, 0x44, 0xd1, 0xf8, 0xee, 0xb1,
-	0x73, 0x79, 0x35, 0xec, 0xfc, 0xba, 0x1a, 0x1e, 0x34, 0x64, 0x65, 0xca, 0x93, 0xca, 0xd2, 0x8f,
-	0x12, 0x9e, 0xe5, 0x93, 0x50, 0x1e, 0xd6, 0x23, 0xb6, 0xab, 0x17, 0x76, 0xad, 0x80, 0x8f, 0xa0,
-	0xa7, 0x56, 0x29, 0x37, 0xb7, 0x28, 0x1a, 0x6f, 0x3b, 0xfb, 0x76, 0x23, 0xa6, 0xdd, 0xf0, 0x7c,
-	0xb3, 0x4a, 0x39, 0xd3, 0x24, 0x26, 0x70, 0xe7, 0x22, 0x4a, 0xce, 0x13, 0x3f, 0xe6, 0x66, 0xb7,
-	0xf2, 0x67, 0xff, 0xfb, 0xd1, 0x7b, 0xd8, 0x69, 0x0c, 0xbd, 0x8d, 0x94, 0x78, 0xed, 0x2b, 0x81,
-	0x31, 0xf4, 0x52, 0x5f, 0x89, 0x3a, 0x2e, 0xd3, 0x35, 0x3e, 0x82, 0x7e, 0xa6, 0x29, 0x6d, 0x3d,
-	0x70, 0xcc, 0x4d, 0xd6, 0xec, 0x9a, 0x1b, 0xcd, 0xe0, 0x5e, 0x63, 0x3b, 0xc7, 0x4f, 0xe0, 0x56,
-	0xa5, 0x94, 0x9b, 0x88, 0x76, 0xc7, 0x03, 0x87, 0x6e, 0x12, 0xf8, 0x17, 0x83, 0xd5, 0xf8, 0xc1,
-	0x0f, 0x04, 0xf7, 0x5b, 0x57, 0xc3, 0x0f, 0xa0, 0x37, 0xf3, 0x4e, 0xa7, 0x46, 0x87, 0xec, 0x15,
-	0x25, 0xdd, 0x69, 0x1d, 0xcf, 0xa2, 0x0b, 0x8e, 0x87, 0xd0, 0x75, 0x3d, 0x66, 0x20, 0xb2, 0x5b,
-	0x94, 0x14, 0xb7, 0x08, 0x37, 0xca, 0xf0, 0x23, 0x00, 0xd7, 0x63, 0x1f, 0x4e, 0xa6, 0x4f, 0xdd,
-	0x29, 0x33, 0xb6, 0xc8, 0x7e, 0x51, 0x52, 0xf3, 0x26, 0x77, 0xc2, 0xfd, 0x05, 0xcf, 0xf0, 0x43,
-	0xb8, 0x7d, 0xf6, 0xee, 0xe5, 0xa9, 0xf7, 0xea, 0x85, 0xd1, 0x25, 0xa4, 0x28, 0xe9, 0x6e, 0x0b,
-	0x3d, 0x5b, 0xc5, 0xd5, 0xbb, 0x92, 0xbd, 0x4f, 0x5f, 0xac, 0xce, 0xf7, 0xaf, 0x56, 0x3b, 0xf3,
-	0xb1, 0x71, 0xb9, 0xb6, 0xd0, 0xcf, 0xb5, 0x85, 0x7e, 0xaf, 0x2d, 0xf4, 0xf9, 0x8f, 0xd5, 0x99,
-	0xf7, 0xf5, 0x7f, 0x79, 0xfc, 0x37, 0x00, 0x00, 0xff, 0xff, 0x55, 0xf2, 0x2e, 0x06, 0x7d, 0x02,
-	0x00, 0x00,
+func init() { proto.RegisterFile("checksum.proto", fileDescriptor_checksum_efc6501bf3727db3) }
+
+var fileDescriptor_checksum_efc6501bf3727db3 = []byte{
+	// 426 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xc1, 0x6a, 0x13, 0x41,
+	0x18, 0xc7, 0x77, 0x9a, 0x18, 0xf5, 0x8b, 0xd4, 0x30, 0x85, 0x76, 0x19, 0xca, 0x64, 0xcc, 0xc5,
+	0x50, 0xec, 0xa6, 0x44, 0xf0, 0x6e, 0xdd, 0x84, 0x46, 0xab, 0xc8, 0x54, 0x10, 0xf1, 0x20, 0x9b,
+	0xcd, 0xb8, 0xb3, 0xb4, 0xd9, 0x59, 0x76, 0x27, 0x87, 0xbc, 0x81, 0xec, 0xc9, 0x17, 0xd8, 0x93,
+	0x82, 0xef, 0xe0, 0x5d, 0xe8, 0xb1, 0x47, 0xf1, 0x50, 0x24, 0x79, 0x11, 0xd9, 0xd9, 0x2a, 0xcb,
+	0x4a, 0x4e, 0xf3, 0x7d, 0x33, 0xbf, 0xef, 0xff, 0xff, 0xcf, 0x30, 0xb0, 0xed, 0x4b, 0xe1, 0x9f,
+	0xa7, 0x8b, 0xb9, 0x13, 0x27, 0x4a, 0x2b, 0xdc, 0xf6, 0x55, 0xa4, 0x45, 0xa4, 0xa5, 0x97, 0x4a,
+	0x72, 0x18, 0x84, 0x5a, 0x2e, 0xa6, 0x8e, 0xaf, 0xe6, 0x83, 0x40, 0x05, 0x6a, 0x60, 0x98, 0xe9,
+	0xe2, 0xa3, 0xe9, 0x4c, 0x63, 0xaa, 0x72, 0xb6, 0xf7, 0x0d, 0x41, 0xfb, 0x99, 0xe7, 0x4b, 0xc1,
+	0x85, 0xaf, 0x92, 0x19, 0x7e, 0x0e, 0xad, 0x59, 0x18, 0x88, 0x54, 0xdb, 0x88, 0xa1, 0xfe, 0xdd,
+	0xe3, 0xe1, 0xe5, 0x75, 0xd7, 0xfa, 0x75, 0xdd, 0x3d, 0xa8, 0xc8, 0xaa, 0x58, 0x44, 0x85, 0xa5,
+	0x17, 0x46, 0x22, 0x49, 0x07, 0x81, 0x3a, 0x2c, 0x47, 0x1c, 0xd7, 0x2c, 0xfc, 0x46, 0x01, 0x1f,
+	0x41, 0x53, 0x2f, 0x63, 0x61, 0x6f, 0x31, 0xd4, 0xdf, 0x1e, 0xee, 0x3b, 0x95, 0x98, 0x4e, 0xc5,
+	0xf3, 0xcd, 0x32, 0x16, 0xdc, 0x90, 0x98, 0xc0, 0x9d, 0x8b, 0x30, 0x3a, 0x8f, 0xbc, 0xb9, 0xb0,
+	0x1b, 0x85, 0x3f, 0xff, 0xd7, 0xf7, 0xde, 0xc3, 0x4e, 0x65, 0xe8, 0x6d, 0xa8, 0xe5, 0x6b, 0x4f,
+	0x4b, 0x8c, 0xa1, 0x19, 0x7b, 0x5a, 0x96, 0x71, 0xb9, 0xa9, 0xf1, 0x11, 0xb4, 0x12, 0x43, 0x19,
+	0xeb, 0xf6, 0xd0, 0xde, 0x64, 0xcd, 0x6f, 0xb8, 0xde, 0x18, 0xee, 0x55, 0xb6, 0x53, 0xfc, 0x04,
+	0x6e, 0x15, 0x4a, 0xa9, 0x8d, 0x58, 0xa3, 0xdf, 0x1e, 0xb2, 0x4d, 0x02, 0x7f, 0x63, 0xf0, 0x12,
+	0x3f, 0xf8, 0x81, 0xe0, 0x7e, 0xed, 0x6a, 0xf8, 0x01, 0x34, 0xc7, 0x93, 0xd3, 0x51, 0xc7, 0x22,
+	0x7b, 0x59, 0xce, 0x76, 0x6a, 0xc7, 0xe3, 0xf0, 0x42, 0xe0, 0x2e, 0x34, 0xdc, 0x09, 0xef, 0x20,
+	0xb2, 0x9b, 0xe5, 0x0c, 0xd7, 0x08, 0x37, 0x4c, 0xf0, 0x23, 0x00, 0x77, 0xc2, 0x3f, 0x9c, 0x8c,
+	0x9e, 0xba, 0x23, 0xde, 0xd9, 0x22, 0xfb, 0x59, 0xce, 0xec, 0xff, 0xb9, 0x13, 0xe1, 0xcd, 0x44,
+	0x82, 0x1f, 0xc2, 0xed, 0xb3, 0x77, 0x2f, 0x4f, 0x27, 0xaf, 0x5e, 0x74, 0x1a, 0x84, 0x64, 0x39,
+	0xdb, 0xad, 0xa1, 0x67, 0xcb, 0x79, 0xf1, 0xae, 0x64, 0xef, 0xd3, 0x17, 0x6a, 0x7d, 0xff, 0x4a,
+	0xeb, 0x99, 0x8f, 0xed, 0xcb, 0x15, 0x45, 0x57, 0x2b, 0x8a, 0x7e, 0xaf, 0x28, 0xfa, 0xbc, 0xa6,
+	0xd6, 0xd5, 0x9a, 0x5a, 0x3f, 0xd7, 0xd4, 0x9a, 0xb6, 0xcc, 0xbf, 0x79, 0xfc, 0x27, 0x00, 0x00,
+	0xff, 0xff, 0xfd, 0xd7, 0xd8, 0x37, 0x85, 0x02, 0x00, 0x00,
 }
 }

+ 26 - 12
vendor/github.com/moby/buildkit/cache/remotecache/export.go

@@ -19,7 +19,7 @@ import (
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 )
 )
 
 
-type ResolveCacheExporterFunc func(ctx context.Context, typ, target string) (Exporter, error)
+type ResolveCacheExporterFunc func(ctx context.Context, attrs map[string]string) (Exporter, error)
 
 
 func oneOffProgress(ctx context.Context, id string) func(err error) error {
 func oneOffProgress(ctx context.Context, id string) func(err error) error {
 	pw, _, _ := progress.FromContext(ctx)
 	pw, _, _ := progress.FromContext(ctx)
@@ -39,9 +39,17 @@ func oneOffProgress(ctx context.Context, id string) func(err error) error {
 
 
 type Exporter interface {
 type Exporter interface {
 	solver.CacheExporterTarget
 	solver.CacheExporterTarget
-	Finalize(ctx context.Context) error
+	// Finalize finalizes and return metadata that are returned to the client
+	// e.g. ExporterResponseManifestDesc
+	Finalize(ctx context.Context) (map[string]string, error)
 }
 }
 
 
+const (
+	// ExportResponseManifestDesc is a key for the map returned from Exporter.Finalize.
+	// The map value is a JSON string of an OCI desciptor of a manifest.
+	ExporterResponseManifestDesc = "cache.manifest"
+)
+
 type contentCacheExporter struct {
 type contentCacheExporter struct {
 	solver.CacheExporterTarget
 	solver.CacheExporterTarget
 	chains   *v1.CacheChains
 	chains   *v1.CacheChains
@@ -53,14 +61,15 @@ func NewExporter(ingester content.Ingester) Exporter {
 	return &contentCacheExporter{CacheExporterTarget: cc, chains: cc, ingester: ingester}
 	return &contentCacheExporter{CacheExporterTarget: cc, chains: cc, ingester: ingester}
 }
 }
 
 
-func (ce *contentCacheExporter) Finalize(ctx context.Context) error {
+func (ce *contentCacheExporter) Finalize(ctx context.Context) (map[string]string, error) {
 	return export(ctx, ce.ingester, ce.chains)
 	return export(ctx, ce.ingester, ce.chains)
 }
 }
 
 
-func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains) error {
+func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains) (map[string]string, error) {
+	res := make(map[string]string)
 	config, descs, err := cc.Marshal()
 	config, descs, err := cc.Marshal()
 	if err != nil {
 	if err != nil {
-		return err
+		return nil, err
 	}
 	}
 
 
 	// own type because oci type can't be pushed and docker type doesn't have annotations
 	// own type because oci type can't be pushed and docker type doesn't have annotations
@@ -80,11 +89,11 @@ func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains)
 	for _, l := range config.Layers {
 	for _, l := range config.Layers {
 		dgstPair, ok := descs[l.Blob]
 		dgstPair, ok := descs[l.Blob]
 		if !ok {
 		if !ok {
-			return errors.Errorf("missing blob %s", l.Blob)
+			return nil, errors.Errorf("missing blob %s", l.Blob)
 		}
 		}
 		layerDone := oneOffProgress(ctx, fmt.Sprintf("writing layer %s", l.Blob))
 		layerDone := oneOffProgress(ctx, fmt.Sprintf("writing layer %s", l.Blob))
 		if err := contentutil.Copy(ctx, ingester, dgstPair.Provider, dgstPair.Descriptor); err != nil {
 		if err := contentutil.Copy(ctx, ingester, dgstPair.Provider, dgstPair.Descriptor); err != nil {
-			return layerDone(errors.Wrap(err, "error writing layer blob"))
+			return nil, layerDone(errors.Wrap(err, "error writing layer blob"))
 		}
 		}
 		layerDone(nil)
 		layerDone(nil)
 		mfst.Manifests = append(mfst.Manifests, dgstPair.Descriptor)
 		mfst.Manifests = append(mfst.Manifests, dgstPair.Descriptor)
@@ -92,7 +101,7 @@ func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains)
 
 
 	dt, err := json.Marshal(config)
 	dt, err := json.Marshal(config)
 	if err != nil {
 	if err != nil {
-		return err
+		return nil, err
 	}
 	}
 	dgst := digest.FromBytes(dt)
 	dgst := digest.FromBytes(dt)
 	desc := ocispec.Descriptor{
 	desc := ocispec.Descriptor{
@@ -102,7 +111,7 @@ func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains)
 	}
 	}
 	configDone := oneOffProgress(ctx, fmt.Sprintf("writing config %s", dgst))
 	configDone := oneOffProgress(ctx, fmt.Sprintf("writing config %s", dgst))
 	if err := content.WriteBlob(ctx, ingester, dgst.String(), bytes.NewReader(dt), desc); err != nil {
 	if err := content.WriteBlob(ctx, ingester, dgst.String(), bytes.NewReader(dt), desc); err != nil {
-		return configDone(errors.Wrap(err, "error writing config blob"))
+		return nil, configDone(errors.Wrap(err, "error writing config blob"))
 	}
 	}
 	configDone(nil)
 	configDone(nil)
 
 
@@ -110,7 +119,7 @@ func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains)
 
 
 	dt, err = json.Marshal(mfst)
 	dt, err = json.Marshal(mfst)
 	if err != nil {
 	if err != nil {
-		return errors.Wrap(err, "failed to marshal manifest")
+		return nil, errors.Wrap(err, "failed to marshal manifest")
 	}
 	}
 	dgst = digest.FromBytes(dt)
 	dgst = digest.FromBytes(dt)
 
 
@@ -121,8 +130,13 @@ func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains)
 	}
 	}
 	mfstDone := oneOffProgress(ctx, fmt.Sprintf("writing manifest %s", dgst))
 	mfstDone := oneOffProgress(ctx, fmt.Sprintf("writing manifest %s", dgst))
 	if err := content.WriteBlob(ctx, ingester, dgst.String(), bytes.NewReader(dt), desc); err != nil {
 	if err := content.WriteBlob(ctx, ingester, dgst.String(), bytes.NewReader(dt), desc); err != nil {
-		return mfstDone(errors.Wrap(err, "error writing manifest blob"))
+		return nil, mfstDone(errors.Wrap(err, "error writing manifest blob"))
+	}
+	descJSON, err := json.Marshal(desc)
+	if err != nil {
+		return nil, err
 	}
 	}
+	res[ExporterResponseManifestDesc] = string(descJSON)
 	mfstDone(nil)
 	mfstDone(nil)
-	return nil
+	return res, nil
 }
 }

+ 175 - 3
vendor/github.com/moby/buildkit/cache/remotecache/import.go

@@ -4,18 +4,24 @@ import (
 	"context"
 	"context"
 	"encoding/json"
 	"encoding/json"
 	"io"
 	"io"
+	"sync"
+	"time"
 
 
 	"github.com/containerd/containerd/content"
 	"github.com/containerd/containerd/content"
+	"github.com/containerd/containerd/images"
 	v1 "github.com/moby/buildkit/cache/remotecache/v1"
 	v1 "github.com/moby/buildkit/cache/remotecache/v1"
 	"github.com/moby/buildkit/solver"
 	"github.com/moby/buildkit/solver"
+	"github.com/moby/buildkit/util/imageutil"
 	"github.com/moby/buildkit/worker"
 	"github.com/moby/buildkit/worker"
+	digest "github.com/opencontainers/go-digest"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
+	"github.com/sirupsen/logrus"
+	"golang.org/x/sync/errgroup"
 )
 )
 
 
 // ResolveCacheImporterFunc returns importer and descriptor.
 // ResolveCacheImporterFunc returns importer and descriptor.
-// Currently typ needs to be an empty string.
-type ResolveCacheImporterFunc func(ctx context.Context, typ, ref string) (Importer, ocispec.Descriptor, error)
+type ResolveCacheImporterFunc func(ctx context.Context, attrs map[string]string) (Importer, ocispec.Descriptor, error)
 
 
 type Importer interface {
 type Importer interface {
 	Resolve(ctx context.Context, desc ocispec.Descriptor, id string, w worker.Worker) (solver.CacheManager, error)
 	Resolve(ctx context.Context, desc ocispec.Descriptor, id string, w worker.Worker) (solver.CacheManager, error)
@@ -56,7 +62,7 @@ func (ci *contentCacheImporter) Resolve(ctx context.Context, desc ocispec.Descri
 	}
 	}
 
 
 	if configDesc.Digest == "" {
 	if configDesc.Digest == "" {
-		return nil, errors.Errorf("invalid build cache from %+v", desc)
+		return ci.importInlineCache(ctx, dt, id, w)
 	}
 	}
 
 
 	dt, err = readBlob(ctx, ci.provider, configDesc)
 	dt, err = readBlob(ctx, ci.provider, configDesc)
@@ -96,3 +102,169 @@ func readBlob(ctx context.Context, provider content.Provider, desc ocispec.Descr
 	}
 	}
 	return dt, err
 	return dt, err
 }
 }
+
+func (ci *contentCacheImporter) importInlineCache(ctx context.Context, dt []byte, id string, w worker.Worker) (solver.CacheManager, error) {
+	m := map[digest.Digest][]byte{}
+
+	if err := ci.allDistributionManifests(ctx, dt, m); err != nil {
+		return nil, err
+	}
+
+	var mu sync.Mutex
+	cc := v1.NewCacheChains()
+
+	eg, ctx := errgroup.WithContext(ctx)
+	for dgst, dt := range m {
+		func(dgst digest.Digest, dt []byte) {
+			eg.Go(func() error {
+				var m ocispec.Manifest
+
+				if err := json.Unmarshal(dt, &m); err != nil {
+					return err
+				}
+
+				if m.Config.Digest == "" || len(m.Layers) == 0 {
+					return nil
+				}
+
+				p, err := content.ReadBlob(ctx, ci.provider, m.Config)
+				if err != nil {
+					return err
+				}
+
+				var img image
+
+				if err := json.Unmarshal(p, &img); err != nil {
+					return err
+				}
+
+				if len(img.Rootfs.DiffIDs) != len(m.Layers) {
+					logrus.Warnf("invalid image with mismatching manifest and config")
+					return nil
+				}
+
+				if img.Cache == nil {
+					return nil
+				}
+
+				var config v1.CacheConfig
+				if err := json.Unmarshal(img.Cache, &config.Records); err != nil {
+					return err
+				}
+
+				createdDates, createdMsg, err := parseCreatedLayerInfo(img)
+				if err != nil {
+					return err
+				}
+
+				layers := v1.DescriptorProvider{}
+				for i, m := range m.Layers {
+					if m.Annotations == nil {
+						m.Annotations = map[string]string{}
+					}
+					if createdAt := createdDates[i]; createdAt != "" {
+						m.Annotations["buildkit/createdat"] = createdAt
+					}
+					if createdBy := createdMsg[i]; createdBy != "" {
+						m.Annotations["buildkit/description"] = createdBy
+					}
+					m.Annotations["containerd.io/uncompressed"] = img.Rootfs.DiffIDs[i].String()
+					layers[m.Digest] = v1.DescriptorProviderPair{
+						Descriptor: m,
+						Provider:   ci.provider,
+					}
+					config.Layers = append(config.Layers, v1.CacheLayer{
+						Blob:        m.Digest,
+						ParentIndex: i - 1,
+					})
+				}
+
+				dt, err = json.Marshal(config)
+				if err != nil {
+					return err
+				}
+
+				mu.Lock()
+				if err := v1.ParseConfig(config, layers, cc); err != nil {
+					return err
+				}
+				mu.Unlock()
+				return nil
+			})
+		}(dgst, dt)
+	}
+
+	if err := eg.Wait(); err != nil {
+		return nil, err
+	}
+
+	keysStorage, resultStorage, err := v1.NewCacheKeyStorage(cc, w)
+	if err != nil {
+		return nil, err
+	}
+	return solver.NewCacheManager(id, keysStorage, resultStorage), nil
+}
+
+func (ci *contentCacheImporter) allDistributionManifests(ctx context.Context, dt []byte, m map[digest.Digest][]byte) error {
+	mt, err := imageutil.DetectManifestBlobMediaType(dt)
+	if err != nil {
+		return err
+	}
+
+	switch mt {
+	case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+		m[digest.FromBytes(dt)] = dt
+	case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
+		var index ocispec.Index
+		if err := json.Unmarshal(dt, &index); err != nil {
+			return err
+		}
+
+		for _, d := range index.Manifests {
+			if _, ok := m[d.Digest]; ok {
+				continue
+			}
+			p, err := content.ReadBlob(ctx, ci.provider, d)
+			if err != nil {
+				return err
+			}
+			if err := ci.allDistributionManifests(ctx, p, m); err != nil {
+				return err
+			}
+		}
+	}
+
+	return nil
+}
+
+type image struct {
+	Rootfs struct {
+		DiffIDs []digest.Digest `json:"diff_ids"`
+	} `json:"rootfs"`
+	Cache   []byte `json:"moby.buildkit.cache.v0"`
+	History []struct {
+		Created    *time.Time `json:"created,omitempty"`
+		CreatedBy  string     `json:"created_by,omitempty"`
+		EmptyLayer bool       `json:"empty_layer,omitempty"`
+	} `json:"history,omitempty"`
+}
+
+func parseCreatedLayerInfo(img image) ([]string, []string, error) {
+	dates := make([]string, 0, len(img.Rootfs.DiffIDs))
+	createdBy := make([]string, 0, len(img.Rootfs.DiffIDs))
+	for _, h := range img.History {
+		if !h.EmptyLayer {
+			str := ""
+			if h.Created != nil {
+				dt, err := h.Created.MarshalText()
+				if err != nil {
+					return nil, nil, err
+				}
+				str = string(dt)
+			}
+			dates = append(dates, str)
+			createdBy = append(createdBy, h.CreatedBy)
+		}
+	}
+	return dates, createdBy, nil
+}

+ 99 - 0
vendor/github.com/moby/buildkit/cache/remotecache/inline/inline.go

@@ -0,0 +1,99 @@
+package registry
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/moby/buildkit/cache/remotecache"
+	v1 "github.com/moby/buildkit/cache/remotecache/v1"
+	"github.com/moby/buildkit/solver"
+	digest "github.com/opencontainers/go-digest"
+	"github.com/sirupsen/logrus"
+)
+
+func ResolveCacheExporterFunc() remotecache.ResolveCacheExporterFunc {
+	return func(ctx context.Context, _ map[string]string) (remotecache.Exporter, error) {
+		return NewExporter(), nil
+	}
+}
+
+func NewExporter() remotecache.Exporter {
+	cc := v1.NewCacheChains()
+	return &exporter{CacheExporterTarget: cc, chains: cc}
+}
+
+type exporter struct {
+	solver.CacheExporterTarget
+	chains *v1.CacheChains
+}
+
+func (ce *exporter) Finalize(ctx context.Context) (map[string]string, error) {
+	return nil, nil
+}
+
+func (ce *exporter) ExportForLayers(layers []digest.Digest) ([]byte, error) {
+	config, descs, err := ce.chains.Marshal()
+	if err != nil {
+		return nil, err
+	}
+
+	descs2 := map[digest.Digest]v1.DescriptorProviderPair{}
+	for _, k := range layers {
+		if v, ok := descs[k]; ok {
+			descs2[k] = v
+			continue
+		}
+		// fallback for uncompressed digests
+		for _, v := range descs {
+			if uc := v.Descriptor.Annotations["containerd.io/uncompressed"]; uc == string(k) {
+				descs2[v.Descriptor.Digest] = v
+			}
+		}
+	}
+
+	cc := v1.NewCacheChains()
+	if err := v1.ParseConfig(*config, descs2, cc); err != nil {
+		return nil, err
+	}
+
+	cfg, _, err := cc.Marshal()
+	if err != nil {
+		return nil, err
+	}
+
+	if len(cfg.Layers) == 0 {
+		logrus.Warn("failed to match any cache with layers")
+		return nil, nil
+	}
+
+	cache := map[digest.Digest]int{}
+
+	// reorder layers based on the order in the image
+	for i, r := range cfg.Records {
+		for j, rr := range r.Results {
+			n := getSortedLayerIndex(rr.LayerIndex, cfg.Layers, cache)
+			rr.LayerIndex = n
+			r.Results[j] = rr
+			cfg.Records[i] = r
+		}
+	}
+
+	dt, err := json.Marshal(cfg.Records)
+	if err != nil {
+		return nil, err
+	}
+
+	return dt, nil
+}
+
+func getSortedLayerIndex(idx int, layers []v1.CacheLayer, cache map[digest.Digest]int) int {
+	if idx == -1 {
+		return -1
+	}
+	l := layers[idx]
+	if i, ok := cache[l.Blob]; ok {
+		return i
+	}
+	cache[l.Blob] = getSortedLayerIndex(l.ParentIndex, layers, cache) + 1
+	return cache[l.Blob]
+}

+ 24 - 6
vendor/github.com/moby/buildkit/cache/remotecache/registry/registry.go

@@ -6,6 +6,7 @@ import (
 
 
 	"github.com/containerd/containerd/remotes"
 	"github.com/containerd/containerd/remotes"
 	"github.com/containerd/containerd/remotes/docker"
 	"github.com/containerd/containerd/remotes/docker"
+	"github.com/docker/distribution/reference"
 	"github.com/moby/buildkit/cache/remotecache"
 	"github.com/moby/buildkit/cache/remotecache"
 	"github.com/moby/buildkit/session"
 	"github.com/moby/buildkit/session"
 	"github.com/moby/buildkit/session/auth"
 	"github.com/moby/buildkit/session/auth"
@@ -15,10 +16,26 @@ import (
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 )
 )
 
 
+func canonicalizeRef(rawRef string) (string, error) {
+	if rawRef == "" {
+		return "", errors.New("missing ref")
+	}
+	parsed, err := reference.ParseNormalizedNamed(rawRef)
+	if err != nil {
+		return "", err
+	}
+	return reference.TagNameOnly(parsed).String(), nil
+}
+
+const (
+	attrRef = "ref"
+)
+
 func ResolveCacheExporterFunc(sm *session.Manager, resolverOpt resolver.ResolveOptionsFunc) remotecache.ResolveCacheExporterFunc {
 func ResolveCacheExporterFunc(sm *session.Manager, resolverOpt resolver.ResolveOptionsFunc) remotecache.ResolveCacheExporterFunc {
-	return func(ctx context.Context, typ, ref string) (remotecache.Exporter, error) {
-		if typ != "" {
-			return nil, errors.Errorf("unsupported cache exporter type: %s", typ)
+	return func(ctx context.Context, attrs map[string]string) (remotecache.Exporter, error) {
+		ref, err := canonicalizeRef(attrs[attrRef])
+		if err != nil {
+			return nil, err
 		}
 		}
 		remote := newRemoteResolver(ctx, resolverOpt, sm, ref)
 		remote := newRemoteResolver(ctx, resolverOpt, sm, ref)
 		pusher, err := remote.Pusher(ctx, ref)
 		pusher, err := remote.Pusher(ctx, ref)
@@ -30,9 +47,10 @@ func ResolveCacheExporterFunc(sm *session.Manager, resolverOpt resolver.ResolveO
 }
 }
 
 
 func ResolveCacheImporterFunc(sm *session.Manager, resolverOpt resolver.ResolveOptionsFunc) remotecache.ResolveCacheImporterFunc {
 func ResolveCacheImporterFunc(sm *session.Manager, resolverOpt resolver.ResolveOptionsFunc) remotecache.ResolveCacheImporterFunc {
-	return func(ctx context.Context, typ, ref string) (remotecache.Importer, specs.Descriptor, error) {
-		if typ != "" {
-			return nil, specs.Descriptor{}, errors.Errorf("unsupported cache importer type: %s", typ)
+	return func(ctx context.Context, attrs map[string]string) (remotecache.Importer, specs.Descriptor, error) {
+		ref, err := canonicalizeRef(attrs[attrRef])
+		if err != nil {
+			return nil, specs.Descriptor{}, err
 		}
 		}
 		remote := newRemoteResolver(ctx, resolverOpt, sm, ref)
 		remote := newRemoteResolver(ctx, resolverOpt, sm, ref)
 		xref, desc, err := remote.Resolve(ctx, ref)
 		xref, desc, err := remote.Resolve(ctx, ref)

+ 61 - 12
vendor/github.com/moby/buildkit/cache/remotecache/v1/cachestorage.go

@@ -2,6 +2,7 @@ package cacheimport
 
 
 import (
 import (
 	"context"
 	"context"
+	"time"
 
 
 	"github.com/moby/buildkit/identity"
 	"github.com/moby/buildkit/identity"
 	"github.com/moby/buildkit/solver"
 	"github.com/moby/buildkit/solver"
@@ -26,6 +27,7 @@ func NewCacheKeyStorage(cc *CacheChains, w worker.Worker) (solver.CacheKeyStorag
 	results := &cacheResultStorage{
 	results := &cacheResultStorage{
 		w:        w,
 		w:        w,
 		byID:     storage.byID,
 		byID:     storage.byID,
+		byItem:   storage.byItem,
 		byResult: storage.byResult,
 		byResult: storage.byResult,
 	}
 	}
 
 
@@ -154,8 +156,22 @@ func (cs *cacheKeyStorage) WalkLinks(id string, link solver.CacheInfoLink, fn fu
 	return nil
 	return nil
 }
 }
 
 
-// TODO:
 func (cs *cacheKeyStorage) WalkBacklinks(id string, fn func(id string, link solver.CacheInfoLink) error) error {
 func (cs *cacheKeyStorage) WalkBacklinks(id string, fn func(id string, link solver.CacheInfoLink) error) error {
+	for k, it := range cs.byID {
+		for nl, ids := range it.links {
+			for _, id2 := range ids {
+				if id == id2 {
+					if err := fn(k, solver.CacheInfoLink{
+						Input:    solver.Index(nl.input),
+						Selector: digest.Digest(nl.selector),
+						Digest:   nl.dgst,
+					}); err != nil {
+						return err
+					}
+				}
+			}
+		}
+	}
 	return nil
 	return nil
 }
 }
 
 
@@ -189,19 +205,54 @@ type cacheResultStorage struct {
 	w        worker.Worker
 	w        worker.Worker
 	byID     map[string]*itemWithOutgoingLinks
 	byID     map[string]*itemWithOutgoingLinks
 	byResult map[string]map[string]struct{}
 	byResult map[string]map[string]struct{}
+	byItem   map[*item]string
 }
 }
 
 
-func (cs *cacheResultStorage) Save(res solver.Result) (solver.CacheResult, error) {
+func (cs *cacheResultStorage) Save(res solver.Result, createdAt time.Time) (solver.CacheResult, error) {
 	return solver.CacheResult{}, errors.Errorf("importer is immutable")
 	return solver.CacheResult{}, errors.Errorf("importer is immutable")
 }
 }
 
 
-func (cs *cacheResultStorage) Load(ctx context.Context, res solver.CacheResult) (solver.Result, error) {
-	remote, err := cs.LoadRemote(ctx, res)
-	if err != nil {
+func (cs *cacheResultStorage) LoadWithParents(ctx context.Context, res solver.CacheResult) (map[string]solver.Result, error) {
+	v := cs.byResultID(res.ID)
+	if v == nil || v.result == nil {
+		return nil, errors.WithStack(solver.ErrNotFound)
+	}
+
+	m := map[string]solver.Result{}
+
+	if err := v.walkAllResults(func(i *item) error {
+		if i.result == nil {
+			return nil
+		}
+		id, ok := cs.byItem[i]
+		if !ok {
+			return nil
+		}
+		if isSubRemote(*i.result, *v.result) {
+			ref, err := cs.w.FromRemote(ctx, i.result)
+			if err != nil {
+				return err
+			}
+			m[id] = worker.NewWorkerRefResult(ref, cs.w)
+		}
+		return nil
+	}); err != nil {
+		for _, v := range m {
+			v.Release(context.TODO())
+		}
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	ref, err := cs.w.FromRemote(ctx, remote)
+	return m, nil
+}
+
+func (cs *cacheResultStorage) Load(ctx context.Context, res solver.CacheResult) (solver.Result, error) {
+	item := cs.byResultID(res.ID)
+	if item == nil || item.result == nil {
+		return nil, errors.WithStack(solver.ErrNotFound)
+	}
+
+	ref, err := cs.w.FromRemote(ctx, item.result)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -209,8 +260,8 @@ func (cs *cacheResultStorage) Load(ctx context.Context, res solver.CacheResult)
 }
 }
 
 
 func (cs *cacheResultStorage) LoadRemote(ctx context.Context, res solver.CacheResult) (*solver.Remote, error) {
 func (cs *cacheResultStorage) LoadRemote(ctx context.Context, res solver.CacheResult) (*solver.Remote, error) {
-	if r := cs.byResultID(res.ID); r != nil {
-		return r, nil
+	if r := cs.byResultID(res.ID); r != nil && r.result != nil {
+		return r.result, nil
 	}
 	}
 	return nil, errors.WithStack(solver.ErrNotFound)
 	return nil, errors.WithStack(solver.ErrNotFound)
 }
 }
@@ -219,7 +270,7 @@ func (cs *cacheResultStorage) Exists(id string) bool {
 	return cs.byResultID(id) != nil
 	return cs.byResultID(id) != nil
 }
 }
 
 
-func (cs *cacheResultStorage) byResultID(resultID string) *solver.Remote {
+func (cs *cacheResultStorage) byResultID(resultID string) *itemWithOutgoingLinks {
 	m, ok := cs.byResult[resultID]
 	m, ok := cs.byResult[resultID]
 	if !ok || len(m) == 0 {
 	if !ok || len(m) == 0 {
 		return nil
 		return nil
@@ -228,9 +279,7 @@ func (cs *cacheResultStorage) byResultID(resultID string) *solver.Remote {
 	for id := range m {
 	for id := range m {
 		it, ok := cs.byID[id]
 		it, ok := cs.byID[id]
 		if ok {
 		if ok {
-			if r := it.result; r != nil {
-				return r
-			}
+			return it
 		}
 		}
 	}
 	}
 
 

+ 27 - 0
vendor/github.com/moby/buildkit/cache/remotecache/v1/chains.go

@@ -1,6 +1,7 @@
 package cacheimport
 package cacheimport
 
 
 import (
 import (
+	"strings"
 	"time"
 	"time"
 
 
 	"github.com/containerd/containerd/content"
 	"github.com/containerd/containerd/content"
@@ -19,6 +20,9 @@ type CacheChains struct {
 }
 }
 
 
 func (c *CacheChains) Add(dgst digest.Digest) solver.CacheExporterRecord {
 func (c *CacheChains) Add(dgst digest.Digest) solver.CacheExporterRecord {
+	if strings.HasPrefix(dgst.String(), "random:") {
+		return &nopRecord{}
+	}
 	it := &item{c: c, dgst: dgst}
 	it := &item{c: c, dgst: dgst}
 	c.items = append(c.items, it)
 	c.items = append(c.items, it)
 	return it
 	return it
@@ -124,4 +128,27 @@ func (c *item) LinkFrom(rec solver.CacheExporterRecord, index int, selector stri
 	c.links[index][link{src: src, selector: selector}] = struct{}{}
 	c.links[index][link{src: src, selector: selector}] = struct{}{}
 }
 }
 
 
+func (c *item) walkAllResults(fn func(i *item) error) error {
+	if err := fn(c); err != nil {
+		return err
+	}
+	for _, links := range c.links {
+		for l := range links {
+			if err := l.src.walkAllResults(fn); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+type nopRecord struct {
+}
+
+func (c *nopRecord) AddResult(createdAt time.Time, result *solver.Remote) {
+}
+
+func (c *nopRecord) LinkFrom(rec solver.CacheExporterRecord, index int, selector string) {
+}
+
 var _ solver.CacheExporterTarget = &CacheChains{}
 var _ solver.CacheExporterTarget = &CacheChains{}

+ 1 - 1
vendor/github.com/moby/buildkit/cache/remotecache/v1/doc.go

@@ -6,7 +6,7 @@ package cacheimport
 // https://github.com/opencontainers/image-spec/blob/master/image-index.md .
 // https://github.com/opencontainers/image-spec/blob/master/image-index.md .
 // Manifests array contains descriptors to the cache layers and one instance of
 // Manifests array contains descriptors to the cache layers and one instance of
 // build cache config with media type application/vnd.buildkit.cacheconfig.v0 .
 // build cache config with media type application/vnd.buildkit.cacheconfig.v0 .
-// The cache layer descripts need to have an annotation with uncompressed digest
+// The cache layer descriptors need to have an annotation with uncompressed digest
 // to allow deduplication on extraction and optionally "buildkit/createdat"
 // to allow deduplication on extraction and optionally "buildkit/createdat"
 // annotation to support maintaining original timestamps.
 // annotation to support maintaining original timestamps.
 //
 //

+ 11 - 3
vendor/github.com/moby/buildkit/cache/remotecache/v1/parse.go

@@ -15,6 +15,10 @@ func Parse(configJSON []byte, provider DescriptorProvider, t solver.CacheExporte
 		return err
 		return err
 	}
 	}
 
 
+	return ParseConfig(config, provider, t)
+}
+
+func ParseConfig(config CacheConfig, provider DescriptorProvider, t solver.CacheExporterTarget) error {
 	cache := map[int]solver.CacheExporterRecord{}
 	cache := map[int]solver.CacheExporterRecord{}
 
 
 	for i := range config.Records {
 	for i := range config.Records {
@@ -22,7 +26,6 @@ func Parse(configJSON []byte, provider DescriptorProvider, t solver.CacheExporte
 			return err
 			return err
 		}
 		}
 	}
 	}
-
 	return nil
 	return nil
 }
 }
 
 
@@ -57,7 +60,9 @@ func parseRecord(cc CacheConfig, idx int, provider DescriptorProvider, t solver.
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		r.AddResult(res.CreatedAt, remote)
+		if remote != nil {
+			r.AddResult(res.CreatedAt, remote)
+		}
 	}
 	}
 
 
 	cache[idx] = r
 	cache[idx] = r
@@ -78,7 +83,7 @@ func getRemoteChain(layers []CacheLayer, idx int, provider DescriptorProvider, v
 
 
 	descPair, ok := provider[l.Blob]
 	descPair, ok := provider[l.Blob]
 	if !ok {
 	if !ok {
-		return nil, errors.Errorf("missing blob for %s", l.Blob)
+		return nil, nil
 	}
 	}
 
 
 	var r *solver.Remote
 	var r *solver.Remote
@@ -88,6 +93,9 @@ func getRemoteChain(layers []CacheLayer, idx int, provider DescriptorProvider, v
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
+		if r == nil {
+			return nil, nil
+		}
 		r.Descriptors = append(r.Descriptors, descPair.Descriptor)
 		r.Descriptors = append(r.Descriptors, descPair.Descriptor)
 		mp := contentutil.NewMultiProvider(r.Provider)
 		mp := contentutil.NewMultiProvider(r.Provider)
 		mp.Add(descPair.Descriptor.Digest, descPair.Provider)
 		mp.Add(descPair.Descriptor.Digest, descPair.Provider)

+ 12 - 0
vendor/github.com/moby/buildkit/cache/remotecache/v1/utils.go

@@ -304,3 +304,15 @@ func marshalItem(it *item, state *marshalState) error {
 	state.records = append(state.records, rec)
 	state.records = append(state.records, rec)
 	return nil
 	return nil
 }
 }
+
+func isSubRemote(sub, main solver.Remote) bool {
+	if len(sub.Descriptors) > len(main.Descriptors) {
+		return false
+	}
+	for i := range sub.Descriptors {
+		if sub.Descriptors[i].Digest != main.Descriptors[i].Digest {
+			return false
+		}
+	}
+	return true
+}

+ 1 - 1
vendor/github.com/moby/buildkit/client/client_windows.go

@@ -16,7 +16,7 @@ func dialer(address string, timeout time.Duration) (net.Conn, error) {
 	}
 	}
 	switch addrParts[0] {
 	switch addrParts[0] {
 	case "npipe":
 	case "npipe":
-		address = strings.Replace(addrParts[1], "/", "\\", 0)
+		address = strings.Replace(addrParts[1], "/", "\\", -1)
 		return winio.DialPipe(address, &timeout)
 		return winio.DialPipe(address, &timeout)
 	default:
 	default:
 		return net.DialTimeout(addrParts[0], addrParts[1], timeout)
 		return net.DialTimeout(addrParts[0], addrParts[1], timeout)

+ 1 - 0
vendor/github.com/moby/buildkit/client/graph.go

@@ -41,5 +41,6 @@ type SolveStatus struct {
 }
 }
 
 
 type SolveResponse struct {
 type SolveResponse struct {
+	// ExporterResponse is also used for CacheExporter
 	ExporterResponse map[string]string
 	ExporterResponse map[string]string
 }
 }

+ 6 - 2
vendor/github.com/moby/buildkit/client/llb/state.go

@@ -405,12 +405,16 @@ func WithDescription(m map[string]string) ConstraintsOpt {
 	})
 	})
 }
 }
 
 
-func WithCustomName(name string, a ...interface{}) ConstraintsOpt {
+func WithCustomName(name string) ConstraintsOpt {
 	return WithDescription(map[string]string{
 	return WithDescription(map[string]string{
-		"llb.customname": fmt.Sprintf(name, a...),
+		"llb.customname": name,
 	})
 	})
 }
 }
 
 
+func WithCustomNamef(name string, a ...interface{}) ConstraintsOpt {
+	return WithCustomName(fmt.Sprintf(name, a...))
+}
+
 // WithExportCache forces results for this vertex to be exported with the cache
 // WithExportCache forces results for this vertex to be exported with the cache
 func WithExportCache() ConstraintsOpt {
 func WithExportCache() ConstraintsOpt {
 	return constraintsOptFunc(func(c *Constraints) {
 	return constraintsOptFunc(func(c *Constraints) {

+ 113 - 0
vendor/github.com/moby/buildkit/client/ociindex/ociindex.go

@@ -0,0 +1,113 @@
+package ociindex
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"os"
+
+	"github.com/gofrs/flock"
+	"github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/pkg/errors"
+)
+
+const (
+	// IndexJSONLockFileSuffix is the suffix of the lock file
+	IndexJSONLockFileSuffix = ".lock"
+)
+
+// PutDescToIndex puts desc to index with tag.
+// Existing manifests with the same tag will be removed from the index.
+func PutDescToIndex(index *v1.Index, desc v1.Descriptor, tag string) error {
+	if index == nil {
+		index = &v1.Index{}
+	}
+	if index.SchemaVersion == 0 {
+		index.SchemaVersion = 2
+	}
+	if tag != "" {
+		if desc.Annotations == nil {
+			desc.Annotations = make(map[string]string)
+		}
+		desc.Annotations[v1.AnnotationRefName] = tag
+		// remove existing manifests with the same tag
+		var manifests []v1.Descriptor
+		for _, m := range index.Manifests {
+			if m.Annotations[v1.AnnotationRefName] != tag {
+				manifests = append(manifests, m)
+			}
+		}
+		index.Manifests = manifests
+	}
+	index.Manifests = append(index.Manifests, desc)
+	return nil
+}
+
+func PutDescToIndexJSONFileLocked(indexJSONPath string, desc v1.Descriptor, tag string) error {
+	lockPath := indexJSONPath + IndexJSONLockFileSuffix
+	lock := flock.New(lockPath)
+	locked, err := lock.TryLock()
+	if err != nil {
+		return errors.Wrapf(err, "could not lock %s", lockPath)
+	}
+	if !locked {
+		return errors.Errorf("could not lock %s", lockPath)
+	}
+	defer func() {
+		lock.Unlock()
+		os.RemoveAll(lockPath)
+	}()
+	f, err := os.OpenFile(indexJSONPath, os.O_RDWR|os.O_CREATE, 0644)
+	if err != nil {
+		return errors.Wrapf(err, "could not open %s", indexJSONPath)
+	}
+	defer f.Close()
+	var idx v1.Index
+	b, err := ioutil.ReadAll(f)
+	if err != nil {
+		return errors.Wrapf(err, "could not read %s", indexJSONPath)
+	}
+	if len(b) > 0 {
+		if err := json.Unmarshal(b, &idx); err != nil {
+			return errors.Wrapf(err, "could not unmarshal %s (%q)", indexJSONPath, string(b))
+		}
+	}
+	if err = PutDescToIndex(&idx, desc, tag); err != nil {
+		return err
+	}
+	b, err = json.Marshal(idx)
+	if err != nil {
+		return err
+	}
+	if _, err = f.WriteAt(b, 0); err != nil {
+		return err
+	}
+	if err = f.Truncate(int64(len(b))); err != nil {
+		return err
+	}
+	return nil
+}
+
+func ReadIndexJSONFileLocked(indexJSONPath string) (*v1.Index, error) {
+	lockPath := indexJSONPath + IndexJSONLockFileSuffix
+	lock := flock.New(lockPath)
+	locked, err := lock.TryRLock()
+	if err != nil {
+		return nil, errors.Wrapf(err, "could not lock %s", lockPath)
+	}
+	if !locked {
+		return nil, errors.Errorf("could not lock %s", lockPath)
+	}
+	defer func() {
+		lock.Unlock()
+		os.RemoveAll(lockPath)
+	}()
+	b, err := ioutil.ReadFile(indexJSONPath)
+	if err != nil {
+		return nil, errors.Wrapf(err, "could not read %s", indexJSONPath)
+	}
+	var idx v1.Index
+	if err := json.Unmarshal(b, &idx); err != nil {
+		return nil, errors.Wrapf(err, "could not unmarshal %s (%q)", indexJSONPath, string(b))
+	}
+	return &idx, nil
+}

+ 195 - 28
vendor/github.com/moby/buildkit/client/solve.go

@@ -2,20 +2,26 @@ package client
 
 
 import (
 import (
 	"context"
 	"context"
+	"encoding/json"
 	"io"
 	"io"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
+	"github.com/containerd/containerd/content"
+	contentlocal "github.com/containerd/containerd/content/local"
 	controlapi "github.com/moby/buildkit/api/services/control"
 	controlapi "github.com/moby/buildkit/api/services/control"
 	"github.com/moby/buildkit/client/llb"
 	"github.com/moby/buildkit/client/llb"
+	"github.com/moby/buildkit/client/ociindex"
 	"github.com/moby/buildkit/identity"
 	"github.com/moby/buildkit/identity"
 	"github.com/moby/buildkit/session"
 	"github.com/moby/buildkit/session"
+	sessioncontent "github.com/moby/buildkit/session/content"
 	"github.com/moby/buildkit/session/filesync"
 	"github.com/moby/buildkit/session/filesync"
 	"github.com/moby/buildkit/session/grpchijack"
 	"github.com/moby/buildkit/session/grpchijack"
 	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/util/entitlements"
 	"github.com/moby/buildkit/util/entitlements"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	opentracing "github.com/opentracing/opentracing-go"
 	opentracing "github.com/opentracing/opentracing-go"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
@@ -24,21 +30,29 @@ import (
 )
 )
 
 
 type SolveOpt struct {
 type SolveOpt struct {
-	Exporter            string
-	ExporterAttrs       map[string]string
-	ExporterOutput      io.WriteCloser // for ExporterOCI and ExporterDocker
-	ExporterOutputDir   string         // for ExporterLocal
+	Exports             []ExportEntry
 	LocalDirs           map[string]string
 	LocalDirs           map[string]string
 	SharedKey           string
 	SharedKey           string
 	Frontend            string
 	Frontend            string
 	FrontendAttrs       map[string]string
 	FrontendAttrs       map[string]string
-	ExportCache         string
-	ExportCacheAttrs    map[string]string
-	ImportCache         []string
+	CacheExports        []CacheOptionsEntry
+	CacheImports        []CacheOptionsEntry
 	Session             []session.Attachable
 	Session             []session.Attachable
 	AllowedEntitlements []entitlements.Entitlement
 	AllowedEntitlements []entitlements.Entitlement
 }
 }
 
 
+type ExportEntry struct {
+	Type      string
+	Attrs     map[string]string
+	Output    io.WriteCloser // for ExporterOCI and ExporterDocker
+	OutputDir string         // for ExporterLocal
+}
+
+type CacheOptionsEntry struct {
+	Type  string
+	Attrs map[string]string
+}
+
 // Solve calls Solve on the controller.
 // Solve calls Solve on the controller.
 // def must be nil if (and only if) opt.Frontend is set.
 // def must be nil if (and only if) opt.Frontend is set.
 func (c *Client) Solve(ctx context.Context, def *llb.Definition, opt SolveOpt, statusChan chan *SolveStatus) (*SolveResponse, error) {
 func (c *Client) Solve(ctx context.Context, def *llb.Definition, opt SolveOpt, statusChan chan *SolveStatus) (*SolveResponse, error) {
@@ -93,32 +107,51 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
 		s.Allow(a)
 		s.Allow(a)
 	}
 	}
 
 
-	switch opt.Exporter {
+	var ex ExportEntry
+	if len(opt.Exports) > 1 {
+		return nil, errors.New("currently only single Exports can be specified")
+	}
+	if len(opt.Exports) == 1 {
+		ex = opt.Exports[0]
+	}
+
+	switch ex.Type {
 	case ExporterLocal:
 	case ExporterLocal:
-		if opt.ExporterOutput != nil {
+		if ex.Output != nil {
 			return nil, errors.New("output file writer is not supported by local exporter")
 			return nil, errors.New("output file writer is not supported by local exporter")
 		}
 		}
-		if opt.ExporterOutputDir == "" {
+		if ex.OutputDir == "" {
 			return nil, errors.New("output directory is required for local exporter")
 			return nil, errors.New("output directory is required for local exporter")
 		}
 		}
-		s.Allow(filesync.NewFSSyncTargetDir(opt.ExporterOutputDir))
+		s.Allow(filesync.NewFSSyncTargetDir(ex.OutputDir))
 	case ExporterOCI, ExporterDocker:
 	case ExporterOCI, ExporterDocker:
-		if opt.ExporterOutputDir != "" {
-			return nil, errors.Errorf("output directory %s is not supported by %s exporter", opt.ExporterOutputDir, opt.Exporter)
+		if ex.OutputDir != "" {
+			return nil, errors.Errorf("output directory %s is not supported by %s exporter", ex.OutputDir, ex.Type)
 		}
 		}
-		if opt.ExporterOutput == nil {
-			return nil, errors.Errorf("output file writer is required for %s exporter", opt.Exporter)
+		if ex.Output == nil {
+			return nil, errors.Errorf("output file writer is required for %s exporter", ex.Type)
 		}
 		}
-		s.Allow(filesync.NewFSSyncTarget(opt.ExporterOutput))
+		s.Allow(filesync.NewFSSyncTarget(ex.Output))
 	default:
 	default:
-		if opt.ExporterOutput != nil {
-			return nil, errors.Errorf("output file writer is not supported by %s exporter", opt.Exporter)
+		if ex.Output != nil {
+			return nil, errors.Errorf("output file writer is not supported by %s exporter", ex.Type)
 		}
 		}
-		if opt.ExporterOutputDir != "" {
-			return nil, errors.Errorf("output directory %s is not supported by %s exporter", opt.ExporterOutputDir, opt.Exporter)
+		if ex.OutputDir != "" {
+			return nil, errors.Errorf("output directory %s is not supported by %s exporter", ex.OutputDir, ex.Type)
 		}
 		}
 	}
 	}
 
 
+	cacheOpt, err := parseCacheOptions(opt)
+	if err != nil {
+		return nil, err
+	}
+	if len(cacheOpt.contentStores) > 0 {
+		s.Allow(sessioncontent.NewAttachable(cacheOpt.contentStores))
+	}
+	for k, v := range cacheOpt.frontendAttrs {
+		opt.FrontendAttrs[k] = v
+	}
+
 	eg.Go(func() error {
 	eg.Go(func() error {
 		return s.Run(statusContext, grpchijack.Dialer(c.controlClient()))
 		return s.Run(statusContext, grpchijack.Dialer(c.controlClient()))
 	})
 	})
@@ -144,17 +177,13 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
 		resp, err := c.controlClient().Solve(ctx, &controlapi.SolveRequest{
 		resp, err := c.controlClient().Solve(ctx, &controlapi.SolveRequest{
 			Ref:           ref,
 			Ref:           ref,
 			Definition:    pbd,
 			Definition:    pbd,
-			Exporter:      opt.Exporter,
-			ExporterAttrs: opt.ExporterAttrs,
+			Exporter:      ex.Type,
+			ExporterAttrs: ex.Attrs,
 			Session:       s.ID(),
 			Session:       s.ID(),
 			Frontend:      opt.Frontend,
 			Frontend:      opt.Frontend,
 			FrontendAttrs: opt.FrontendAttrs,
 			FrontendAttrs: opt.FrontendAttrs,
-			Cache: controlapi.CacheOptions{
-				ExportRef:   opt.ExportCache,
-				ImportRefs:  opt.ImportCache,
-				ExportAttrs: opt.ExportCacheAttrs,
-			},
-			Entitlements: opt.AllowedEntitlements,
+			Cache:         cacheOpt.options,
+			Entitlements:  opt.AllowedEntitlements,
 		})
 		})
 		if err != nil {
 		if err != nil {
 			return errors.Wrap(err, "failed to solve")
 			return errors.Wrap(err, "failed to solve")
@@ -243,6 +272,19 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
 	if err := eg.Wait(); err != nil {
 	if err := eg.Wait(); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
+	// Update index.json of exported cache content store
+	// FIXME(AkihiroSuda): dedupe const definition of cache/remotecache.ExporterResponseManifestDesc = "cache.manifest"
+	if manifestDescJSON := res.ExporterResponse["cache.manifest"]; manifestDescJSON != "" {
+		var manifestDesc ocispec.Descriptor
+		if err = json.Unmarshal([]byte(manifestDescJSON), &manifestDesc); err != nil {
+			return nil, err
+		}
+		for indexJSONPath, tag := range cacheOpt.indicesToUpdate {
+			if err = ociindex.PutDescToIndexJSONFileLocked(indexJSONPath, manifestDesc, tag); err != nil {
+				return nil, err
+			}
+		}
+	}
 	return res, nil
 	return res, nil
 }
 }
 
 
@@ -295,3 +337,128 @@ func defaultSessionName() string {
 	}
 	}
 	return filepath.Base(wd)
 	return filepath.Base(wd)
 }
 }
+
+type cacheOptions struct {
+	options         controlapi.CacheOptions
+	contentStores   map[string]content.Store // key: ID of content store ("local:" + csDir)
+	indicesToUpdate map[string]string        // key: index.JSON file name, value: tag
+	frontendAttrs   map[string]string
+}
+
+func parseCacheOptions(opt SolveOpt) (*cacheOptions, error) {
+	var (
+		cacheExports []*controlapi.CacheOptionsEntry
+		cacheImports []*controlapi.CacheOptionsEntry
+		// legacy API is used for registry caches, because the daemon might not support the new API
+		legacyExportRef  string
+		legacyImportRefs []string
+	)
+	contentStores := make(map[string]content.Store)
+	indicesToUpdate := make(map[string]string) // key: index.JSON file name, value: tag
+	frontendAttrs := make(map[string]string)
+	legacyExportAttrs := make(map[string]string)
+	for _, ex := range opt.CacheExports {
+		if ex.Type == "local" {
+			csDir := ex.Attrs["dest"]
+			if csDir == "" {
+				return nil, errors.New("local cache exporter requires dest")
+			}
+			if err := os.MkdirAll(csDir, 0755); err != nil {
+				return nil, err
+			}
+			cs, err := contentlocal.NewStore(csDir)
+			if err != nil {
+				return nil, err
+			}
+			contentStores["local:"+csDir] = cs
+			// TODO(AkihiroSuda): support custom index JSON path and tag
+			indexJSONPath := filepath.Join(csDir, "index.json")
+			indicesToUpdate[indexJSONPath] = "latest"
+		}
+		if ex.Type == "registry" && legacyExportRef == "" {
+			legacyExportRef = ex.Attrs["ref"]
+			for k, v := range ex.Attrs {
+				if k != "ref" {
+					legacyExportAttrs[k] = v
+				}
+			}
+		} else {
+			cacheExports = append(cacheExports, &controlapi.CacheOptionsEntry{
+				Type:  ex.Type,
+				Attrs: ex.Attrs,
+			})
+		}
+	}
+	for _, im := range opt.CacheImports {
+		attrs := im.Attrs
+		if im.Type == "local" {
+			csDir := im.Attrs["src"]
+			if csDir == "" {
+				return nil, errors.New("local cache importer requires src")
+			}
+			if err := os.MkdirAll(csDir, 0755); err != nil {
+				return nil, err
+			}
+			cs, err := contentlocal.NewStore(csDir)
+			if err != nil {
+				return nil, err
+			}
+			contentStores["local:"+csDir] = cs
+
+			// if digest is not specified, load from "latest" tag
+			if attrs["digest"] == "" {
+				idx, err := ociindex.ReadIndexJSONFileLocked(filepath.Join(csDir, "index.json"))
+				if err != nil {
+					return nil, err
+				}
+				for _, m := range idx.Manifests {
+					if m.Annotations[ocispec.AnnotationRefName] == "latest" {
+						attrs["digest"] = string(m.Digest)
+						break
+					}
+				}
+				if attrs["digest"] == "" {
+					return nil, errors.New("local cache importer requires either explicit digest or \"latest\" tag on index.json")
+				}
+			}
+		}
+		if im.Type == "registry" {
+			legacyImportRef := attrs["ref"]
+			legacyImportRefs = append(legacyImportRefs, legacyImportRef)
+		} else {
+			cacheImports = append(cacheImports, &controlapi.CacheOptionsEntry{
+				Type:  im.Type,
+				Attrs: attrs,
+			})
+		}
+	}
+	if opt.Frontend != "" {
+		// use legacy API for registry importers, because the frontend might not support the new API
+		if len(legacyImportRefs) > 0 {
+			frontendAttrs["cache-from"] = strings.Join(legacyImportRefs, ",")
+		}
+		// use new API for other importers
+		if len(cacheImports) > 0 {
+			s, err := json.Marshal(cacheImports)
+			if err != nil {
+				return nil, err
+			}
+			frontendAttrs["cache-imports"] = string(s)
+		}
+	}
+	res := cacheOptions{
+		options: controlapi.CacheOptions{
+			// old API (for registry caches, planned to be removed in early 2019)
+			ExportRefDeprecated:   legacyExportRef,
+			ExportAttrsDeprecated: legacyExportAttrs,
+			ImportRefsDeprecated:  legacyImportRefs,
+			// new API
+			Exports: cacheExports,
+			Imports: cacheImports,
+		},
+		contentStores:   contentStores,
+		indicesToUpdate: indicesToUpdate,
+		frontendAttrs:   frontendAttrs,
+	}
+	return &res, nil
+}

+ 76 - 47
vendor/github.com/moby/buildkit/control/control.go

@@ -5,7 +5,6 @@ import (
 	"sync"
 	"sync"
 	"time"
 	"time"
 
 
-	"github.com/docker/distribution/reference"
 	controlapi "github.com/moby/buildkit/api/services/control"
 	controlapi "github.com/moby/buildkit/api/services/control"
 	apitypes "github.com/moby/buildkit/api/types"
 	apitypes "github.com/moby/buildkit/api/types"
 	"github.com/moby/buildkit/cache/remotecache"
 	"github.com/moby/buildkit/cache/remotecache"
@@ -26,15 +25,13 @@ import (
 	"google.golang.org/grpc"
 	"google.golang.org/grpc"
 )
 )
 
 
-type ResolveCacheExporterFunc func(ctx context.Context, typ, target string) (remotecache.Exporter, error)
-
 type Opt struct {
 type Opt struct {
-	SessionManager           *session.Manager
-	WorkerController         *worker.Controller
-	Frontends                map[string]frontend.Frontend
-	CacheKeyStorage          solver.CacheKeyStorage
-	ResolveCacheExporterFunc remotecache.ResolveCacheExporterFunc
-	ResolveCacheImporterFunc remotecache.ResolveCacheImporterFunc
+	SessionManager            *session.Manager
+	WorkerController          *worker.Controller
+	Frontends                 map[string]frontend.Frontend
+	CacheKeyStorage           solver.CacheKeyStorage
+	ResolveCacheExporterFuncs map[string]remotecache.ResolveCacheExporterFunc
+	ResolveCacheImporterFuncs map[string]remotecache.ResolveCacheImporterFunc
 }
 }
 
 
 type Controller struct { // TODO: ControlService
 type Controller struct { // TODO: ControlService
@@ -51,7 +48,7 @@ func NewController(opt Opt) (*Controller, error) {
 
 
 	gatewayForwarder := controlgateway.NewGatewayForwarder()
 	gatewayForwarder := controlgateway.NewGatewayForwarder()
 
 
-	solver, err := llbsolver.New(opt.WorkerController, opt.Frontends, cache, opt.ResolveCacheImporterFunc, gatewayForwarder)
+	solver, err := llbsolver.New(opt.WorkerController, opt.Frontends, cache, opt.ResolveCacheImporterFuncs, gatewayForwarder, opt.SessionManager)
 	if err != nil {
 	if err != nil {
 		return nil, errors.Wrap(err, "failed to create solver")
 		return nil, errors.Wrap(err, "failed to create solver")
 	}
 	}
@@ -179,7 +176,39 @@ func (c *Controller) Prune(req *controlapi.PruneRequest, stream controlapi.Contr
 	return eg2.Wait()
 	return eg2.Wait()
 }
 }
 
 
+func translateLegacySolveRequest(req *controlapi.SolveRequest) error {
+	// translates ExportRef and ExportAttrs to new Exports (v0.4.0)
+	if legacyExportRef := req.Cache.ExportRefDeprecated; legacyExportRef != "" {
+		ex := &controlapi.CacheOptionsEntry{
+			Type:  "registry",
+			Attrs: req.Cache.ExportAttrsDeprecated,
+		}
+		if ex.Attrs == nil {
+			ex.Attrs = make(map[string]string)
+		}
+		ex.Attrs["ref"] = legacyExportRef
+		// FIXME(AkihiroSuda): skip append if already exists
+		req.Cache.Exports = append(req.Cache.Exports, ex)
+		req.Cache.ExportRefDeprecated = ""
+		req.Cache.ExportAttrsDeprecated = nil
+	}
+	// translates ImportRefs to new Imports (v0.4.0)
+	for _, legacyImportRef := range req.Cache.ImportRefsDeprecated {
+		im := &controlapi.CacheOptionsEntry{
+			Type:  "registry",
+			Attrs: map[string]string{"ref": legacyImportRef},
+		}
+		// FIXME(AkihiroSuda): skip append if already exists
+		req.Cache.Imports = append(req.Cache.Imports, im)
+	}
+	req.Cache.ImportRefsDeprecated = nil
+	return nil
+}
+
 func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*controlapi.SolveResponse, error) {
 func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*controlapi.SolveResponse, error) {
+	if err := translateLegacySolveRequest(req); err != nil {
+		return nil, err
+	}
 	ctx = session.NewContext(ctx, req.Session)
 	ctx = session.NewContext(ctx, req.Session)
 
 
 	defer func() {
 	defer func() {
@@ -194,7 +223,7 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*
 		return nil, err
 		return nil, err
 	}
 	}
 	if req.Exporter != "" {
 	if req.Exporter != "" {
-		exp, err := w.Exporter(req.Exporter)
+		exp, err := w.Exporter(req.Exporter, c.opt.SessionManager)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
@@ -204,38 +233,44 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*
 		}
 		}
 	}
 	}
 
 
-	var cacheExporter remotecache.Exporter
-	if ref := req.Cache.ExportRef; ref != "" && c.opt.ResolveCacheExporterFunc != nil {
-		parsed, err := reference.ParseNormalizedNamed(ref)
-		if err != nil {
-			return nil, err
-		}
-		exportCacheRef := reference.TagNameOnly(parsed).String()
-		typ := "" // unimplemented yet (typically registry)
-		cacheExporter, err = c.opt.ResolveCacheExporterFunc(ctx, typ, exportCacheRef)
-		if err != nil {
-			return nil, err
-		}
+	var (
+		cacheExporter   remotecache.Exporter
+		cacheExportMode solver.CacheExportMode
+		cacheImports    []frontend.CacheOptionsEntry
+	)
+	if len(req.Cache.Exports) > 1 {
+		// TODO(AkihiroSuda): this should be fairly easy
+		return nil, errors.New("specifying multiple cache exports is not supported currently")
 	}
 	}
 
 
-	var importCacheRefs []string
-	for _, ref := range req.Cache.ImportRefs {
-		parsed, err := reference.ParseNormalizedNamed(ref)
+	if len(req.Cache.Exports) == 1 {
+		e := req.Cache.Exports[0]
+		cacheExporterFunc, ok := c.opt.ResolveCacheExporterFuncs[e.Type]
+		if !ok {
+			return nil, errors.Errorf("unknown cache exporter: %q", e.Type)
+		}
+		cacheExporter, err = cacheExporterFunc(ctx, e.Attrs)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		importCacheRefs = append(importCacheRefs, reference.TagNameOnly(parsed).String())
+		cacheExportMode = parseCacheExportMode(e.Attrs["mode"])
+	}
+	for _, im := range req.Cache.Imports {
+		cacheImports = append(cacheImports, frontend.CacheOptionsEntry{
+			Type:  im.Type,
+			Attrs: im.Attrs,
+		})
 	}
 	}
 
 
 	resp, err := c.solver.Solve(ctx, req.Ref, frontend.SolveRequest{
 	resp, err := c.solver.Solve(ctx, req.Ref, frontend.SolveRequest{
-		Frontend:        req.Frontend,
-		Definition:      req.Definition,
-		FrontendOpt:     req.FrontendAttrs,
-		ImportCacheRefs: importCacheRefs,
+		Frontend:     req.Frontend,
+		Definition:   req.Definition,
+		FrontendOpt:  req.FrontendAttrs,
+		CacheImports: cacheImports,
 	}, llbsolver.ExporterRequest{
 	}, llbsolver.ExporterRequest{
 		Exporter:        expi,
 		Exporter:        expi,
 		CacheExporter:   cacheExporter,
 		CacheExporter:   cacheExporter,
-		CacheExportMode: parseCacheExporterOpt(req.Cache.ExportAttrs),
+		CacheExportMode: cacheExportMode,
 	}, req.Entitlements)
 	}, req.Entitlements)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
@@ -376,21 +411,15 @@ func (c *Controller) gc() {
 	}
 	}
 }
 }
 
 
-func parseCacheExporterOpt(opt map[string]string) solver.CacheExportMode {
-	for k, v := range opt {
-		switch k {
-		case "mode":
-			switch v {
-			case "min":
-				return solver.CacheExportModeMin
-			case "max":
-				return solver.CacheExportModeMax
-			default:
-				logrus.Debugf("skipping incalid cache export mode: %s", v)
-			}
-		default:
-			logrus.Warnf("skipping invalid cache export opt: %s", v)
-		}
+func parseCacheExportMode(mode string) solver.CacheExportMode {
+	switch mode {
+	case "min":
+		return solver.CacheExportModeMin
+	case "max":
+		return solver.CacheExportModeMax
+	case "":
+	default:
+		logrus.Debugf("skipping invalid cache export mode: %s", mode)
 	}
 	}
 	return solver.CacheExportModeMin
 	return solver.CacheExportModeMin
 }
 }

+ 56 - 7
vendor/github.com/moby/buildkit/executor/oci/mounts.go

@@ -2,16 +2,19 @@ package oci
 
 
 import (
 import (
 	"context"
 	"context"
+	"path/filepath"
+	"strings"
 
 
 	specs "github.com/opencontainers/runtime-spec/specs-go"
 	specs "github.com/opencontainers/runtime-spec/specs-go"
+	"github.com/pkg/errors"
 )
 )
 
 
 // MountOpts sets oci spec specific info for mount points
 // MountOpts sets oci spec specific info for mount points
-type MountOpts func([]specs.Mount) []specs.Mount
+type MountOpts func([]specs.Mount) ([]specs.Mount, error)
 
 
 //GetMounts returns default required for buildkit
 //GetMounts returns default required for buildkit
 // https://github.com/moby/buildkit/issues/429
 // https://github.com/moby/buildkit/issues/429
-func GetMounts(ctx context.Context, mountOpts ...MountOpts) []specs.Mount {
+func GetMounts(ctx context.Context, mountOpts ...MountOpts) ([]specs.Mount, error) {
 	mounts := []specs.Mount{
 	mounts := []specs.Mount{
 		{
 		{
 			Destination: "/proc",
 			Destination: "/proc",
@@ -49,20 +52,66 @@ func GetMounts(ctx context.Context, mountOpts ...MountOpts) []specs.Mount {
 			Options:     []string{"nosuid", "noexec", "nodev", "ro"},
 			Options:     []string{"nosuid", "noexec", "nodev", "ro"},
 		},
 		},
 	}
 	}
+	var err error
 	for _, o := range mountOpts {
 	for _, o := range mountOpts {
-		mounts = o(mounts)
+		mounts, err = o(mounts)
+		if err != nil {
+			return nil, err
+		}
 	}
 	}
-	return mounts
+	return mounts, nil
 }
 }
 
 
-func withROBind(src, dest string) func(m []specs.Mount) []specs.Mount {
-	return func(m []specs.Mount) []specs.Mount {
+func withROBind(src, dest string) func(m []specs.Mount) ([]specs.Mount, error) {
+	return func(m []specs.Mount) ([]specs.Mount, error) {
 		m = append(m, specs.Mount{
 		m = append(m, specs.Mount{
 			Destination: dest,
 			Destination: dest,
 			Type:        "bind",
 			Type:        "bind",
 			Source:      src,
 			Source:      src,
 			Options:     []string{"rbind", "ro"},
 			Options:     []string{"rbind", "ro"},
 		})
 		})
-		return m
+		return m, nil
+	}
+}
+
+func hasPrefix(p, prefixDir string) bool {
+	prefixDir = filepath.Clean(prefixDir)
+	if prefixDir == "/" {
+		return true
+	}
+	p = filepath.Clean(p)
+	return p == prefixDir || strings.HasPrefix(p, prefixDir+"/")
+}
+
+func removeMountsWithPrefix(mounts []specs.Mount, prefixDir string) []specs.Mount {
+	var ret []specs.Mount
+	for _, m := range mounts {
+		if !hasPrefix(m.Destination, prefixDir) {
+			ret = append(ret, m)
+		}
+	}
+	return ret
+}
+
+func withProcessMode(processMode ProcessMode) func([]specs.Mount) ([]specs.Mount, error) {
+	return func(m []specs.Mount) ([]specs.Mount, error) {
+		switch processMode {
+		case ProcessSandbox:
+			// keep the default
+		case NoProcessSandbox:
+			m = removeMountsWithPrefix(m, "/proc")
+			procMount := specs.Mount{
+				Destination: "/proc",
+				Type:        "bind",
+				Source:      "/proc",
+				// NOTE: "rbind"+"ro" does not make /proc read-only recursively.
+				// So we keep maskedPath and readonlyPaths (although not mandatory for rootless mode)
+				Options: []string{"rbind"},
+			}
+			m = append([]specs.Mount{procMount}, m...)
+		default:
+			return nil, errors.Errorf("unknown process mode: %v", processMode)
+		}
+		return m, nil
 	}
 	}
 }
 }

+ 27 - 2
vendor/github.com/moby/buildkit/executor/oci/spec_unix.go

@@ -22,8 +22,21 @@ import (
 
 
 // Ideally we don't have to import whole containerd just for the default spec
 // Ideally we don't have to import whole containerd just for the default spec
 
 
+// ProcMode configures PID namespaces
+type ProcessMode int
+
+const (
+	// ProcessSandbox unshares pidns and mount procfs.
+	ProcessSandbox ProcessMode = iota
+	// NoProcessSandbox uses host pidns and bind-mount procfs.
+	// Note that NoProcessSandbox allows build containers to kill (and potentially ptrace) an arbitrary process in the BuildKit host namespace.
+	// NoProcessSandbox should be enabled only when the BuildKit is running in a container as an unprivileged user.
+	NoProcessSandbox
+)
+
 // GenerateSpec generates spec using containerd functionality.
 // GenerateSpec generates spec using containerd functionality.
-func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mount, id, resolvConf, hostsFile string, namespace network.Namespace, opts ...oci.SpecOpts) (*specs.Spec, func(), error) {
+// opts are ignored for s.Process, s.Hostname, and s.Mounts .
+func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mount, id, resolvConf, hostsFile string, namespace network.Namespace, processMode ProcessMode, opts ...oci.SpecOpts) (*specs.Spec, func(), error) {
 	c := &containers.Container{
 	c := &containers.Container{
 		ID: id,
 		ID: id,
 	}
 	}
@@ -32,6 +45,14 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
 		ctx = namespaces.WithNamespace(ctx, "buildkit")
 		ctx = namespaces.WithNamespace(ctx, "buildkit")
 	}
 	}
 
 
+	switch processMode {
+	case NoProcessSandbox:
+		// Mount for /proc is replaced in GetMounts()
+		opts = append(opts,
+			oci.WithHostNamespace(specs.PIDNamespace))
+		// TODO(AkihiroSuda): Configure seccomp to disable ptrace (and prctl?) explicitly
+	}
+
 	// Note that containerd.GenerateSpec is namespaced so as to make
 	// Note that containerd.GenerateSpec is namespaced so as to make
 	// specs.Linux.CgroupsPath namespaced
 	// specs.Linux.CgroupsPath namespaced
 	s, err := oci.GenerateSpec(ctx, nil, c, opts...)
 	s, err := oci.GenerateSpec(ctx, nil, c, opts...)
@@ -48,10 +69,14 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
 	s.Process.NoNewPrivileges = false // reset nonewprivileges
 	s.Process.NoNewPrivileges = false // reset nonewprivileges
 	s.Hostname = "buildkitsandbox"
 	s.Hostname = "buildkitsandbox"
 
 
-	s.Mounts = GetMounts(ctx,
+	s.Mounts, err = GetMounts(ctx,
+		withProcessMode(processMode),
 		withROBind(resolvConf, "/etc/resolv.conf"),
 		withROBind(resolvConf, "/etc/resolv.conf"),
 		withROBind(hostsFile, "/etc/hosts"),
 		withROBind(hostsFile, "/etc/hosts"),
 	)
 	)
+	if err != nil {
+		return nil, nil, err
+	}
 
 
 	s.Mounts = append(s.Mounts, specs.Mount{
 	s.Mounts = append(s.Mounts, specs.Mount{
 		Destination: "/sys/fs/cgroup",
 		Destination: "/sys/fs/cgroup",

+ 5 - 1
vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go

@@ -39,6 +39,8 @@ type Opt struct {
 	Rootless bool
 	Rootless bool
 	// DefaultCgroupParent is the cgroup-parent name for executor
 	// DefaultCgroupParent is the cgroup-parent name for executor
 	DefaultCgroupParent string
 	DefaultCgroupParent string
+	// ProcessMode
+	ProcessMode oci.ProcessMode
 }
 }
 
 
 var defaultCommandCandidates = []string{"buildkit-runc", "runc"}
 var defaultCommandCandidates = []string{"buildkit-runc", "runc"}
@@ -50,6 +52,7 @@ type runcExecutor struct {
 	cgroupParent     string
 	cgroupParent     string
 	rootless         bool
 	rootless         bool
 	networkProviders map[pb.NetMode]network.Provider
 	networkProviders map[pb.NetMode]network.Provider
+	processMode      oci.ProcessMode
 }
 }
 
 
 func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Executor, error) {
 func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Executor, error) {
@@ -105,6 +108,7 @@ func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Ex
 		cgroupParent:     opt.DefaultCgroupParent,
 		cgroupParent:     opt.DefaultCgroupParent,
 		rootless:         opt.Rootless,
 		rootless:         opt.Rootless,
 		networkProviders: networkProviders,
 		networkProviders: networkProviders,
+		processMode:      opt.ProcessMode,
 	}
 	}
 	return w, nil
 	return w, nil
 }
 }
@@ -193,7 +197,7 @@ func (w *runcExecutor) Exec(ctx context.Context, meta executor.Meta, root cache.
 		}
 		}
 		opts = append(opts, containerdoci.WithCgroup(cgroupsPath))
 		opts = append(opts, containerdoci.WithCgroup(cgroupsPath))
 	}
 	}
-	spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, opts...)
+	spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, w.processMode, opts...)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}

+ 1 - 0
vendor/github.com/moby/buildkit/exporter/containerimage/exptypes/types.go

@@ -3,6 +3,7 @@ package exptypes
 import specs "github.com/opencontainers/image-spec/specs-go/v1"
 import specs "github.com/opencontainers/image-spec/specs-go/v1"
 
 
 const ExporterImageConfigKey = "containerimage.config"
 const ExporterImageConfigKey = "containerimage.config"
+const ExporterInlineCache = "containerimage.inlinecache"
 const ExporterPlatformsKey = "refs.platforms"
 const ExporterPlatformsKey = "refs.platforms"
 
 
 type Platforms struct {
 type Platforms struct {

+ 148 - 0
vendor/github.com/moby/buildkit/exporter/local/export.go

@@ -0,0 +1,148 @@
+package local
+
+import (
+	"context"
+	"io/ioutil"
+	"os"
+	"strings"
+	"time"
+
+	"github.com/moby/buildkit/cache"
+	"github.com/moby/buildkit/exporter"
+	"github.com/moby/buildkit/session"
+	"github.com/moby/buildkit/session/filesync"
+	"github.com/moby/buildkit/snapshot"
+	"github.com/moby/buildkit/util/progress"
+	"github.com/pkg/errors"
+	"github.com/tonistiigi/fsutil"
+	fstypes "github.com/tonistiigi/fsutil/types"
+	"golang.org/x/sync/errgroup"
+	"golang.org/x/time/rate"
+)
+
+type Opt struct {
+	SessionManager *session.Manager
+}
+
+type localExporter struct {
+	opt Opt
+	// session manager
+}
+
+func New(opt Opt) (exporter.Exporter, error) {
+	le := &localExporter{opt: opt}
+	return le, nil
+}
+
+func (e *localExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) {
+	id := session.FromContext(ctx)
+	if id == "" {
+		return nil, errors.New("could not access local files without session")
+	}
+
+	timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
+	defer cancel()
+
+	caller, err := e.opt.SessionManager.Get(timeoutCtx, id)
+	if err != nil {
+		return nil, err
+	}
+
+	li := &localExporterInstance{localExporter: e, caller: caller}
+	return li, nil
+}
+
+type localExporterInstance struct {
+	*localExporter
+	caller session.Caller
+}
+
+func (e *localExporterInstance) Name() string {
+	return "exporting to client"
+}
+
+func (e *localExporterInstance) Export(ctx context.Context, inp exporter.Source) (map[string]string, error) {
+	isMap := len(inp.Refs) > 0
+
+	export := func(ctx context.Context, k string, ref cache.ImmutableRef) func() error {
+		return func() error {
+			var src string
+			var err error
+			if ref == nil {
+				src, err = ioutil.TempDir("", "buildkit")
+				if err != nil {
+					return err
+				}
+				defer os.RemoveAll(src)
+			} else {
+				mount, err := ref.Mount(ctx, true)
+				if err != nil {
+					return err
+				}
+
+				lm := snapshot.LocalMounter(mount)
+
+				src, err = lm.Mount()
+				if err != nil {
+					return err
+				}
+				defer lm.Unmount()
+			}
+
+			fs := fsutil.NewFS(src, nil)
+			lbl := "copying files"
+			if isMap {
+				lbl += " " + k
+				fs = fsutil.SubDirFS(fs, fstypes.Stat{
+					Mode: uint32(os.ModeDir | 0755),
+					Path: strings.Replace(k, "/", "_", -1),
+				})
+			}
+
+			progress := newProgressHandler(ctx, lbl)
+			if err := filesync.CopyToCaller(ctx, fs, e.caller, progress); err != nil {
+				return err
+			}
+			return nil
+		}
+	}
+
+	eg, ctx := errgroup.WithContext(ctx)
+
+	if isMap {
+		for k, ref := range inp.Refs {
+			eg.Go(export(ctx, k, ref))
+		}
+	} else {
+		eg.Go(export(ctx, "", inp.Ref))
+	}
+
+	if err := eg.Wait(); err != nil {
+		return nil, err
+	}
+	return nil, nil
+}
+
+func newProgressHandler(ctx context.Context, id string) func(int, bool) {
+	limiter := rate.NewLimiter(rate.Every(100*time.Millisecond), 1)
+	pw, _, _ := progress.FromContext(ctx)
+	now := time.Now()
+	st := progress.Status{
+		Started: &now,
+		Action:  "transferring",
+	}
+	pw.Write(id, st)
+	return func(s int, last bool) {
+		if last || limiter.Allow() {
+			st.Current = s
+			if last {
+				now := time.Now()
+				st.Completed = &now
+			}
+			pw.Write(id, st)
+			if last {
+				pw.Close()
+			}
+		}
+	}
+}

+ 62 - 27
vendor/github.com/moby/buildkit/frontend/dockerfile/builder/build.go

@@ -14,6 +14,7 @@ import (
 
 
 	"github.com/containerd/containerd/platforms"
 	"github.com/containerd/containerd/platforms"
 	"github.com/docker/docker/builder/dockerignore"
 	"github.com/docker/docker/builder/dockerignore"
+	controlapi "github.com/moby/buildkit/api/services/control"
 	"github.com/moby/buildkit/client/llb"
 	"github.com/moby/buildkit/client/llb"
 	"github.com/moby/buildkit/exporter/containerimage/exptypes"
 	"github.com/moby/buildkit/exporter/containerimage/exptypes"
 	"github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb"
 	"github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb"
@@ -25,22 +26,25 @@ import (
 )
 )
 
 
 const (
 const (
-	LocalNameContext      = "context"
-	LocalNameDockerfile   = "dockerfile"
-	keyTarget             = "target"
-	keyFilename           = "filename"
-	keyCacheFrom          = "cache-from"
-	defaultDockerfileName = "Dockerfile"
-	dockerignoreFilename  = ".dockerignore"
-	buildArgPrefix        = "build-arg:"
-	labelPrefix           = "label:"
-	keyNoCache            = "no-cache"
-	keyTargetPlatform     = "platform"
-	keyMultiPlatform      = "multi-platform"
-	keyImageResolveMode   = "image-resolve-mode"
-	keyGlobalAddHosts     = "add-hosts"
-	keyForceNetwork       = "force-network-mode"
-	keyOverrideCopyImage  = "override-copy-image" // remove after CopyOp implemented
+	DefaultLocalNameContext    = "context"
+	DefaultLocalNameDockerfile = "dockerfile"
+	keyTarget                  = "target"
+	keyFilename                = "filename"
+	keyCacheFrom               = "cache-from"    // for registry only. deprecated in favor of keyCacheImports
+	keyCacheImports            = "cache-imports" // JSON representation of []CacheOptionsEntry
+	defaultDockerfileName      = "Dockerfile"
+	dockerignoreFilename       = ".dockerignore"
+	buildArgPrefix             = "build-arg:"
+	labelPrefix                = "label:"
+	keyNoCache                 = "no-cache"
+	keyTargetPlatform          = "platform"
+	keyMultiPlatform           = "multi-platform"
+	keyImageResolveMode        = "image-resolve-mode"
+	keyGlobalAddHosts          = "add-hosts"
+	keyForceNetwork            = "force-network-mode"
+	keyOverrideCopyImage       = "override-copy-image" // remove after CopyOp implemented
+	keyNameContext             = "contextkey"
+	keyNameDockerfile          = "dockerfilekey"
 )
 )
 
 
 var httpPrefix = regexp.MustCompile("^https?://")
 var httpPrefix = regexp.MustCompile("^https?://")
@@ -52,6 +56,16 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) {
 
 
 	marshalOpts := []llb.ConstraintsOpt{llb.WithCaps(caps)}
 	marshalOpts := []llb.ConstraintsOpt{llb.WithCaps(caps)}
 
 
+	localNameContext := DefaultLocalNameContext
+	if v, ok := opts[keyNameContext]; ok {
+		localNameContext = v
+	}
+
+	localNameDockerfile := DefaultLocalNameDockerfile
+	if v, ok := opts[keyNameDockerfile]; ok {
+		localNameDockerfile = v
+	}
+
 	defaultBuildPlatform := platforms.DefaultSpec()
 	defaultBuildPlatform := platforms.DefaultSpec()
 	if workers := c.BuildOpts().Workers; len(workers) > 0 && len(workers[0].Platforms) > 0 {
 	if workers := c.BuildOpts().Workers; len(workers) > 0 && len(workers[0].Platforms) > 0 {
 		defaultBuildPlatform = workers[0].Platforms[0]
 		defaultBuildPlatform = workers[0].Platforms[0]
@@ -98,19 +112,19 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) {
 
 
 	name := "load build definition from " + filename
 	name := "load build definition from " + filename
 
 
-	src := llb.Local(LocalNameDockerfile,
+	src := llb.Local(localNameDockerfile,
 		llb.FollowPaths([]string{filename}),
 		llb.FollowPaths([]string{filename}),
 		llb.SessionID(c.BuildOpts().SessionID),
 		llb.SessionID(c.BuildOpts().SessionID),
-		llb.SharedKeyHint(defaultDockerfileName),
+		llb.SharedKeyHint(localNameDockerfile),
 		dockerfile2llb.WithInternalName(name),
 		dockerfile2llb.WithInternalName(name),
 	)
 	)
 	var buildContext *llb.State
 	var buildContext *llb.State
 	isScratchContext := false
 	isScratchContext := false
-	if st, ok := detectGitContext(opts[LocalNameContext]); ok {
+	if st, ok := detectGitContext(opts[localNameContext]); ok {
 		src = *st
 		src = *st
 		buildContext = &src
 		buildContext = &src
-	} else if httpPrefix.MatchString(opts[LocalNameContext]) {
-		httpContext := llb.HTTP(opts[LocalNameContext], llb.Filename("context"), dockerfile2llb.WithInternalName("load remote build context"))
+	} else if httpPrefix.MatchString(opts[localNameContext]) {
+		httpContext := llb.HTTP(opts[localNameContext], llb.Filename("context"), dockerfile2llb.WithInternalName("load remote build context"))
 		def, err := httpContext.Marshal(marshalOpts...)
 		def, err := httpContext.Marshal(marshalOpts...)
 		if err != nil {
 		if err != nil {
 			return nil, errors.Wrapf(err, "failed to marshal httpcontext")
 			return nil, errors.Wrapf(err, "failed to marshal httpcontext")
@@ -187,10 +201,10 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) {
 		eg.Go(func() error {
 		eg.Go(func() error {
 			dockerignoreState := buildContext
 			dockerignoreState := buildContext
 			if dockerignoreState == nil {
 			if dockerignoreState == nil {
-				st := llb.Local(LocalNameContext,
+				st := llb.Local(localNameContext,
 					llb.SessionID(c.BuildOpts().SessionID),
 					llb.SessionID(c.BuildOpts().SessionID),
 					llb.FollowPaths([]string{dockerignoreFilename}),
 					llb.FollowPaths([]string{dockerignoreFilename}),
-					llb.SharedKeyHint(dockerignoreFilename),
+					llb.SharedKeyHint(localNameContext+"-"+dockerignoreFilename),
 					dockerfile2llb.WithInternalName("load "+dockerignoreFilename),
 					dockerfile2llb.WithInternalName("load "+dockerignoreFilename),
 				)
 				)
 				dockerignoreState = &st
 				dockerignoreState = &st
@@ -289,14 +303,35 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) {
 					return errors.Wrapf(err, "failed to marshal image config")
 					return errors.Wrapf(err, "failed to marshal image config")
 				}
 				}
 
 
-				var cacheFrom []string
+				var cacheImports []client.CacheOptionsEntry
+				// new API
+				if cacheImportsStr := opts[keyCacheImports]; cacheImportsStr != "" {
+					var cacheImportsUM []controlapi.CacheOptionsEntry
+					if err := json.Unmarshal([]byte(cacheImportsStr), &cacheImportsUM); err != nil {
+						return errors.Wrapf(err, "failed to unmarshal %s (%q)", keyCacheImports, cacheImportsStr)
+					}
+					for _, um := range cacheImportsUM {
+						cacheImports = append(cacheImports, client.CacheOptionsEntry{Type: um.Type, Attrs: um.Attrs})
+					}
+				}
+				// old API
 				if cacheFromStr := opts[keyCacheFrom]; cacheFromStr != "" {
 				if cacheFromStr := opts[keyCacheFrom]; cacheFromStr != "" {
-					cacheFrom = strings.Split(cacheFromStr, ",")
+					cacheFrom := strings.Split(cacheFromStr, ",")
+					for _, s := range cacheFrom {
+						im := client.CacheOptionsEntry{
+							Type: "registry",
+							Attrs: map[string]string{
+								"ref": s,
+							},
+						}
+						// FIXME(AkihiroSuda): skip append if already exists
+						cacheImports = append(cacheImports, im)
+					}
 				}
 				}
 
 
 				r, err := c.Solve(ctx, client.SolveRequest{
 				r, err := c.Solve(ctx, client.SolveRequest{
-					Definition:      def.ToPB(),
-					ImportCacheRefs: cacheFrom,
+					Definition:   def.ToPB(),
+					CacheImports: cacheImports,
 				})
 				})
 				if err != nil {
 				if err != nil {
 					return err
 					return err

+ 12 - 7
vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert.go

@@ -31,9 +31,9 @@ import (
 )
 )
 
 
 const (
 const (
-	emptyImageName   = "scratch"
-	localNameContext = "context"
-	historyComment   = "buildkit.dockerfile.v0"
+	emptyImageName          = "scratch"
+	defaultContextLocalName = "context"
+	historyComment          = "buildkit.dockerfile.v0"
 
 
 	DefaultCopyImage = "docker/dockerfile-copy:v0.1.9@sha256:e8f159d3f00786604b93c675ee2783f8dc194bb565e61ca5788f6a6e9d304061"
 	DefaultCopyImage = "docker/dockerfile-copy:v0.1.9@sha256:e8f159d3f00786604b93c675ee2783f8dc194bb565e61ca5788f6a6e9d304061"
 )
 )
@@ -59,6 +59,7 @@ type ConvertOpt struct {
 	ForceNetMode      pb.NetMode
 	ForceNetMode      pb.NetMode
 	OverrideCopyImage string
 	OverrideCopyImage string
 	LLBCaps           *apicaps.CapSet
 	LLBCaps           *apicaps.CapSet
+	ContextLocalName  string
 }
 }
 
 
 func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State, *Image, error) {
 func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State, *Image, error) {
@@ -66,6 +67,10 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
 		return nil, nil, errors.Errorf("the Dockerfile cannot be empty")
 		return nil, nil, errors.Errorf("the Dockerfile cannot be empty")
 	}
 	}
 
 
+	if opt.ContextLocalName == "" {
+		opt.ContextLocalName = defaultContextLocalName
+	}
+
 	platformOpt := buildPlatformOpt(&opt)
 	platformOpt := buildPlatformOpt(&opt)
 
 
 	optMetaArgs := getPlatformArgs(platformOpt)
 	optMetaArgs := getPlatformArgs(platformOpt)
@@ -357,14 +362,14 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
 	opts := []llb.LocalOption{
 	opts := []llb.LocalOption{
 		llb.SessionID(opt.SessionID),
 		llb.SessionID(opt.SessionID),
 		llb.ExcludePatterns(opt.Excludes),
 		llb.ExcludePatterns(opt.Excludes),
-		llb.SharedKeyHint(localNameContext),
+		llb.SharedKeyHint(opt.ContextLocalName),
 		WithInternalName("load build context"),
 		WithInternalName("load build context"),
 	}
 	}
 	if includePatterns := normalizeContextPaths(ctxPaths); includePatterns != nil {
 	if includePatterns := normalizeContextPaths(ctxPaths); includePatterns != nil {
 		opts = append(opts, llb.FollowPaths(includePatterns))
 		opts = append(opts, llb.FollowPaths(includePatterns))
 	}
 	}
 
 
-	bc := llb.Local(localNameContext, opts...)
+	bc := llb.Local(opt.ContextLocalName, opts...)
 	if opt.BuildContext != nil {
 	if opt.BuildContext != nil {
 		bc = *opt.BuildContext
 		bc = *opt.BuildContext
 	}
 	}
@@ -1138,8 +1143,8 @@ func autoDetectPlatform(img Image, target specs.Platform, supported []specs.Plat
 	return target
 	return target
 }
 }
 
 
-func WithInternalName(name string, a ...interface{}) llb.ConstraintsOpt {
-	return llb.WithCustomName("[internal] "+name, a...)
+func WithInternalName(name string) llb.ConstraintsOpt {
+	return llb.WithCustomName("[internal] " + name)
 }
 }
 
 
 func uppercaseCmd(str string) string {
 func uppercaseCmd(str string) string {

+ 2 - 0
vendor/github.com/moby/buildkit/frontend/frontend.go

@@ -23,6 +23,8 @@ type FrontendLLBBridge interface {
 
 
 type SolveRequest = gw.SolveRequest
 type SolveRequest = gw.SolveRequest
 
 
+type CacheOptionsEntry = gw.CacheOptionsEntry
+
 type WorkerInfos interface {
 type WorkerInfos interface {
 	WorkerInfos() []client.WorkerInfo
 	WorkerInfos() []client.WorkerInfo
 }
 }

+ 9 - 4
vendor/github.com/moby/buildkit/frontend/gateway/client/client.go

@@ -43,10 +43,15 @@ type StatRequest struct {
 
 
 // SolveRequest is same as frontend.SolveRequest but avoiding dependency
 // SolveRequest is same as frontend.SolveRequest but avoiding dependency
 type SolveRequest struct {
 type SolveRequest struct {
-	Definition      *pb.Definition
-	Frontend        string
-	FrontendOpt     map[string]string
-	ImportCacheRefs []string
+	Definition   *pb.Definition
+	Frontend     string
+	FrontendOpt  map[string]string
+	CacheImports []CacheOptionsEntry
+}
+
+type CacheOptionsEntry struct {
+	Type  string
+	Attrs map[string]string
 }
 }
 
 
 type WorkerInfo struct {
 type WorkerInfo struct {

+ 4 - 4
vendor/github.com/moby/buildkit/frontend/gateway/forwarder/forward.go

@@ -42,10 +42,10 @@ type bridgeClient struct {
 
 
 func (c *bridgeClient) Solve(ctx context.Context, req client.SolveRequest) (*client.Result, error) {
 func (c *bridgeClient) Solve(ctx context.Context, req client.SolveRequest) (*client.Result, error) {
 	res, err := c.FrontendLLBBridge.Solve(ctx, frontend.SolveRequest{
 	res, err := c.FrontendLLBBridge.Solve(ctx, frontend.SolveRequest{
-		Definition:      req.Definition,
-		Frontend:        req.Frontend,
-		FrontendOpt:     req.FrontendOpt,
-		ImportCacheRefs: req.ImportCacheRefs,
+		Definition:   req.Definition,
+		Frontend:     req.Frontend,
+		FrontendOpt:  req.FrontendOpt,
+		CacheImports: req.CacheImports,
 	})
 	})
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err

+ 39 - 6
vendor/github.com/moby/buildkit/frontend/gateway/gateway.go

@@ -7,6 +7,7 @@ import (
 	"io"
 	"io"
 	"net"
 	"net"
 	"os"
 	"os"
+	"strconv"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
 	"time"
 	"time"
@@ -193,12 +194,20 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten
 
 
 	env = append(env, "BUILDKIT_EXPORTEDPRODUCT="+apicaps.ExportedProduct)
 	env = append(env, "BUILDKIT_EXPORTEDPRODUCT="+apicaps.ExportedProduct)
 
 
-	err = llbBridge.Exec(ctx, executor.Meta{
+	meta := executor.Meta{
 		Env:            env,
 		Env:            env,
 		Args:           args,
 		Args:           args,
 		Cwd:            cwd,
 		Cwd:            cwd,
 		ReadonlyRootFS: readonly,
 		ReadonlyRootFS: readonly,
-	}, rootFS, lbf.Stdin, lbf.Stdout, os.Stderr)
+	}
+
+	if v, ok := img.Config.Labels["moby.buildkit.frontend.network.none"]; ok {
+		if ok, _ := strconv.ParseBool(v); ok {
+			meta.NetMode = opspb.NetMode_NONE
+		}
+	}
+
+	err = llbBridge.Exec(ctx, meta, rootFS, lbf.Stdin, lbf.Stdout, os.Stderr)
 
 
 	if err != nil {
 	if err != nil {
 		// An existing error (set via Return rpc) takes
 		// An existing error (set via Return rpc) takes
@@ -397,13 +406,37 @@ func (lbf *llbBridgeForwarder) ResolveImageConfig(ctx context.Context, req *pb.R
 	}, nil
 	}, nil
 }
 }
 
 
+func translateLegacySolveRequest(req *pb.SolveRequest) error {
+	// translates ImportCacheRefs to new CacheImports (v0.4.0)
+	for _, legacyImportRef := range req.ImportCacheRefsDeprecated {
+		im := &pb.CacheOptionsEntry{
+			Type:  "registry",
+			Attrs: map[string]string{"ref": legacyImportRef},
+		}
+		// FIXME(AkihiroSuda): skip append if already exists
+		req.CacheImports = append(req.CacheImports, im)
+	}
+	req.ImportCacheRefsDeprecated = nil
+	return nil
+}
+
 func (lbf *llbBridgeForwarder) Solve(ctx context.Context, req *pb.SolveRequest) (*pb.SolveResponse, error) {
 func (lbf *llbBridgeForwarder) Solve(ctx context.Context, req *pb.SolveRequest) (*pb.SolveResponse, error) {
+	if err := translateLegacySolveRequest(req); err != nil {
+		return nil, err
+	}
+	var cacheImports []frontend.CacheOptionsEntry
+	for _, e := range req.CacheImports {
+		cacheImports = append(cacheImports, frontend.CacheOptionsEntry{
+			Type:  e.Type,
+			Attrs: e.Attrs,
+		})
+	}
 	ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)
 	ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)
 	res, err := lbf.llbBridge.Solve(ctx, frontend.SolveRequest{
 	res, err := lbf.llbBridge.Solve(ctx, frontend.SolveRequest{
-		Definition:      req.Definition,
-		Frontend:        req.Frontend,
-		FrontendOpt:     req.FrontendOpt,
-		ImportCacheRefs: req.ImportCacheRefs,
+		Definition:   req.Definition,
+		Frontend:     req.Frontend,
+		FrontendOpt:  req.FrontendOpt,
+		CacheImports: cacheImports,
 	})
 	})
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err

+ 21 - 1
vendor/github.com/moby/buildkit/frontend/gateway/grpcclient/client.go

@@ -259,13 +259,33 @@ func (c *grpcClient) Solve(ctx context.Context, creq client.SolveRequest) (*clie
 			}
 			}
 		}
 		}
 	}
 	}
+	var (
+		// old API
+		legacyRegistryCacheImports []string
+		// new API (CapImportCaches)
+		cacheImports []*pb.CacheOptionsEntry
+	)
+	supportCapImportCaches := c.caps.Supports(pb.CapImportCaches) == nil
+	for _, im := range creq.CacheImports {
+		if !supportCapImportCaches && im.Type == "registry" {
+			legacyRegistryCacheImports = append(legacyRegistryCacheImports, im.Attrs["ref"])
+		} else {
+			cacheImports = append(cacheImports, &pb.CacheOptionsEntry{
+				Type:  im.Type,
+				Attrs: im.Attrs,
+			})
+		}
+	}
 
 
 	req := &pb.SolveRequest{
 	req := &pb.SolveRequest{
 		Definition:        creq.Definition,
 		Definition:        creq.Definition,
 		Frontend:          creq.Frontend,
 		Frontend:          creq.Frontend,
 		FrontendOpt:       creq.FrontendOpt,
 		FrontendOpt:       creq.FrontendOpt,
-		ImportCacheRefs:   creq.ImportCacheRefs,
 		AllowResultReturn: true,
 		AllowResultReturn: true,
+		// old API
+		ImportCacheRefsDeprecated: legacyRegistryCacheImports,
+		// new API
+		CacheImports: cacheImports,
 	}
 	}
 
 
 	// backwards compatibility with inline return
 	// backwards compatibility with inline return

+ 8 - 0
vendor/github.com/moby/buildkit/frontend/gateway/pb/caps.go

@@ -18,6 +18,7 @@ const (
 	CapReturnMap               apicaps.CapID = "returnmap"
 	CapReturnMap               apicaps.CapID = "returnmap"
 	CapReadDir                 apicaps.CapID = "readdir"
 	CapReadDir                 apicaps.CapID = "readdir"
 	CapStatFile                apicaps.CapID = "statfile"
 	CapStatFile                apicaps.CapID = "statfile"
+	CapImportCaches            apicaps.CapID = "importcaches"
 )
 )
 
 
 func init() {
 func init() {
@@ -84,4 +85,11 @@ func init() {
 		Enabled: true,
 		Enabled: true,
 		Status:  apicaps.CapStatusExperimental,
 		Status:  apicaps.CapStatusExperimental,
 	})
 	})
+
+	Caps.Init(apicaps.Cap{
+		ID:      CapImportCaches,
+		Name:    "import caches",
+		Enabled: true,
+		Status:  apicaps.CapStatusExperimental,
+	})
 }
 }

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 712 - 140
vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.pb.go


+ 15 - 2
vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.proto

@@ -64,12 +64,25 @@ message SolveRequest {
 	pb.Definition Definition = 1;
 	pb.Definition Definition = 1;
 	string Frontend = 2;
 	string Frontend = 2;
 	map<string, string> FrontendOpt = 3;
 	map<string, string> FrontendOpt = 3;
-	repeated string ImportCacheRefs = 4;
+	// ImportCacheRefsDeprecated is deprecated in favor or the new Imports since BuildKit v0.4.0.
+        // When ImportCacheRefsDeprecated is set, the solver appends
+        // {.Type = "registry", .Attrs = {"ref": importCacheRef}}
+        // for each of the ImportCacheRefs entry to CacheImports for compatibility. (planned to be removed)
+	repeated string ImportCacheRefsDeprecated = 4;
 	bool allowResultReturn = 5;
 	bool allowResultReturn = 5;
 	
 	
 	// apicaps.CapSolveInlineReturn deprecated
 	// apicaps.CapSolveInlineReturn deprecated
 	bool Final = 10;
 	bool Final = 10;
 	bytes ExporterAttr = 11;
 	bytes ExporterAttr = 11;
+	// CacheImports was added in BuildKit v0.4.0.
+	// apicaps:CapImportCaches
+	repeated CacheOptionsEntry CacheImports = 12;
+}
+
+// CacheOptionsEntry corresponds to the control.CacheOptionsEntry
+message CacheOptionsEntry {
+	string Type = 1;
+	map<string, string> Attrs = 2;
 }
 }
 
 
 message SolveResponse {
 message SolveResponse {
@@ -122,4 +135,4 @@ message PongResponse{
 	repeated moby.buildkit.v1.apicaps.APICap FrontendAPICaps = 1 [(gogoproto.nullable) = false];
 	repeated moby.buildkit.v1.apicaps.APICap FrontendAPICaps = 1 [(gogoproto.nullable) = false];
 	repeated moby.buildkit.v1.apicaps.APICap LLBCaps = 2 [(gogoproto.nullable) = false];
 	repeated moby.buildkit.v1.apicaps.APICap LLBCaps = 2 [(gogoproto.nullable) = false];
 	repeated moby.buildkit.v1.types.WorkerRecord Workers = 3;
 	repeated moby.buildkit.v1.types.WorkerRecord Workers = 3;
-}
+}

+ 84 - 29
vendor/github.com/moby/buildkit/session/auth/auth.pb.go

@@ -1,16 +1,6 @@
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // source: auth.proto
 // source: auth.proto
 
 
-/*
-	Package auth is a generated protocol buffer package.
-
-	It is generated from these files:
-		auth.proto
-
-	It has these top-level messages:
-		CredentialsRequest
-		CredentialsResponse
-*/
 package auth
 package auth
 
 
 import proto "github.com/gogo/protobuf/proto"
 import proto "github.com/gogo/protobuf/proto"
@@ -20,8 +10,10 @@ import math "math"
 import strings "strings"
 import strings "strings"
 import reflect "reflect"
 import reflect "reflect"
 
 
-import context "golang.org/x/net/context"
-import grpc "google.golang.org/grpc"
+import (
+	context "golang.org/x/net/context"
+	grpc "google.golang.org/grpc"
+)
 
 
 import io "io"
 import io "io"
 
 
@@ -40,9 +32,37 @@ type CredentialsRequest struct {
 	Host string `protobuf:"bytes,1,opt,name=Host,proto3" json:"Host,omitempty"`
 	Host string `protobuf:"bytes,1,opt,name=Host,proto3" json:"Host,omitempty"`
 }
 }
 
 
-func (m *CredentialsRequest) Reset()                    { *m = CredentialsRequest{} }
-func (*CredentialsRequest) ProtoMessage()               {}
-func (*CredentialsRequest) Descriptor() ([]byte, []int) { return fileDescriptorAuth, []int{0} }
+func (m *CredentialsRequest) Reset()      { *m = CredentialsRequest{} }
+func (*CredentialsRequest) ProtoMessage() {}
+func (*CredentialsRequest) Descriptor() ([]byte, []int) {
+	return fileDescriptor_auth_0215b2f0213c0d57, []int{0}
+}
+func (m *CredentialsRequest) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *CredentialsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_CredentialsRequest.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (dst *CredentialsRequest) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_CredentialsRequest.Merge(dst, src)
+}
+func (m *CredentialsRequest) XXX_Size() int {
+	return m.Size()
+}
+func (m *CredentialsRequest) XXX_DiscardUnknown() {
+	xxx_messageInfo_CredentialsRequest.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CredentialsRequest proto.InternalMessageInfo
 
 
 func (m *CredentialsRequest) GetHost() string {
 func (m *CredentialsRequest) GetHost() string {
 	if m != nil {
 	if m != nil {
@@ -56,9 +76,37 @@ type CredentialsResponse struct {
 	Secret   string `protobuf:"bytes,2,opt,name=Secret,proto3" json:"Secret,omitempty"`
 	Secret   string `protobuf:"bytes,2,opt,name=Secret,proto3" json:"Secret,omitempty"`
 }
 }
 
 
-func (m *CredentialsResponse) Reset()                    { *m = CredentialsResponse{} }
-func (*CredentialsResponse) ProtoMessage()               {}
-func (*CredentialsResponse) Descriptor() ([]byte, []int) { return fileDescriptorAuth, []int{1} }
+func (m *CredentialsResponse) Reset()      { *m = CredentialsResponse{} }
+func (*CredentialsResponse) ProtoMessage() {}
+func (*CredentialsResponse) Descriptor() ([]byte, []int) {
+	return fileDescriptor_auth_0215b2f0213c0d57, []int{1}
+}
+func (m *CredentialsResponse) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *CredentialsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_CredentialsResponse.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (dst *CredentialsResponse) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_CredentialsResponse.Merge(dst, src)
+}
+func (m *CredentialsResponse) XXX_Size() int {
+	return m.Size()
+}
+func (m *CredentialsResponse) XXX_DiscardUnknown() {
+	xxx_messageInfo_CredentialsResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CredentialsResponse proto.InternalMessageInfo
 
 
 func (m *CredentialsResponse) GetUsername() string {
 func (m *CredentialsResponse) GetUsername() string {
 	if m != nil {
 	if m != nil {
@@ -167,8 +215,9 @@ var _ grpc.ClientConn
 // is compatible with the grpc package it is being compiled against.
 // is compatible with the grpc package it is being compiled against.
 const _ = grpc.SupportPackageIsVersion4
 const _ = grpc.SupportPackageIsVersion4
 
 
-// Client API for Auth service
-
+// AuthClient is the client API for Auth service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
 type AuthClient interface {
 type AuthClient interface {
 	Credentials(ctx context.Context, in *CredentialsRequest, opts ...grpc.CallOption) (*CredentialsResponse, error)
 	Credentials(ctx context.Context, in *CredentialsRequest, opts ...grpc.CallOption) (*CredentialsResponse, error)
 }
 }
@@ -183,15 +232,14 @@ func NewAuthClient(cc *grpc.ClientConn) AuthClient {
 
 
 func (c *authClient) Credentials(ctx context.Context, in *CredentialsRequest, opts ...grpc.CallOption) (*CredentialsResponse, error) {
 func (c *authClient) Credentials(ctx context.Context, in *CredentialsRequest, opts ...grpc.CallOption) (*CredentialsResponse, error) {
 	out := new(CredentialsResponse)
 	out := new(CredentialsResponse)
-	err := grpc.Invoke(ctx, "/moby.filesync.v1.Auth/Credentials", in, out, c.cc, opts...)
+	err := c.cc.Invoke(ctx, "/moby.filesync.v1.Auth/Credentials", in, out, opts...)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 	return out, nil
 	return out, nil
 }
 }
 
 
-// Server API for Auth service
-
+// AuthServer is the server API for Auth service.
 type AuthServer interface {
 type AuthServer interface {
 	Credentials(context.Context, *CredentialsRequest) (*CredentialsResponse, error)
 	Credentials(context.Context, *CredentialsRequest) (*CredentialsResponse, error)
 }
 }
@@ -295,6 +343,9 @@ func encodeVarintAuth(dAtA []byte, offset int, v uint64) int {
 	return offset + 1
 	return offset + 1
 }
 }
 func (m *CredentialsRequest) Size() (n int) {
 func (m *CredentialsRequest) Size() (n int) {
+	if m == nil {
+		return 0
+	}
 	var l int
 	var l int
 	_ = l
 	_ = l
 	l = len(m.Host)
 	l = len(m.Host)
@@ -305,6 +356,9 @@ func (m *CredentialsRequest) Size() (n int) {
 }
 }
 
 
 func (m *CredentialsResponse) Size() (n int) {
 func (m *CredentialsResponse) Size() (n int) {
+	if m == nil {
+		return 0
+	}
 	var l int
 	var l int
 	_ = l
 	_ = l
 	l = len(m.Username)
 	l = len(m.Username)
@@ -652,10 +706,10 @@ var (
 	ErrIntOverflowAuth   = fmt.Errorf("proto: integer overflow")
 	ErrIntOverflowAuth   = fmt.Errorf("proto: integer overflow")
 )
 )
 
 
-func init() { proto.RegisterFile("auth.proto", fileDescriptorAuth) }
+func init() { proto.RegisterFile("auth.proto", fileDescriptor_auth_0215b2f0213c0d57) }
 
 
-var fileDescriptorAuth = []byte{
-	// 224 bytes of a gzipped FileDescriptorProto
+var fileDescriptor_auth_0215b2f0213c0d57 = []byte{
+	// 233 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4a, 0x2c, 0x2d, 0xc9,
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4a, 0x2c, 0x2d, 0xc9,
 	0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0xc8, 0xcd, 0x4f, 0xaa, 0xd4, 0x4b, 0xcb, 0xcc,
 	0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0xc8, 0xcd, 0x4f, 0xaa, 0xd4, 0x4b, 0xcb, 0xcc,
 	0x49, 0x2d, 0xae, 0xcc, 0x4b, 0xd6, 0x2b, 0x33, 0x54, 0xd2, 0xe0, 0x12, 0x72, 0x2e, 0x4a, 0x4d,
 	0x49, 0x2d, 0xae, 0xcc, 0x4b, 0xd6, 0x2b, 0x33, 0x54, 0xd2, 0xe0, 0x12, 0x72, 0x2e, 0x4a, 0x4d,
@@ -665,9 +719,10 @@ var fileDescriptorAuth = []byte{
 	0x16, 0xa7, 0x16, 0xe5, 0x25, 0xe6, 0xa6, 0x42, 0x95, 0xc3, 0xf9, 0x42, 0x62, 0x5c, 0x6c, 0xc1,
 	0x16, 0xa7, 0x16, 0xe5, 0x25, 0xe6, 0xa6, 0x42, 0x95, 0xc3, 0xf9, 0x42, 0x62, 0x5c, 0x6c, 0xc1,
 	0xa9, 0xc9, 0x45, 0xa9, 0x25, 0x12, 0x4c, 0x60, 0x19, 0x28, 0xcf, 0x28, 0x89, 0x8b, 0xc5, 0xb1,
 	0xa9, 0xc9, 0x45, 0xa9, 0x25, 0x12, 0x4c, 0x60, 0x19, 0x28, 0xcf, 0x28, 0x89, 0x8b, 0xc5, 0xb1,
 	0xb4, 0x24, 0x43, 0x28, 0x8a, 0x8b, 0x1b, 0xc9, 0x48, 0x21, 0x15, 0x3d, 0x74, 0xe7, 0xe9, 0x61,
 	0xb4, 0x24, 0x43, 0x28, 0x8a, 0x8b, 0x1b, 0xc9, 0x48, 0x21, 0x15, 0x3d, 0x74, 0xe7, 0xe9, 0x61,
-	0xba, 0x4d, 0x4a, 0x95, 0x80, 0x2a, 0x88, 0xbb, 0x9c, 0x8c, 0x2e, 0x3c, 0x94, 0x63, 0xb8, 0xf1,
+	0xba, 0x4d, 0x4a, 0x95, 0x80, 0x2a, 0x88, 0xbb, 0x9c, 0xac, 0x2e, 0x3c, 0x94, 0x63, 0xb8, 0xf1,
 	0x50, 0x8e, 0xe1, 0xc3, 0x43, 0x39, 0xc6, 0x86, 0x47, 0x72, 0x8c, 0x2b, 0x1e, 0xc9, 0x31, 0x9e,
 	0x50, 0x8e, 0xe1, 0xc3, 0x43, 0x39, 0xc6, 0x86, 0x47, 0x72, 0x8c, 0x2b, 0x1e, 0xc9, 0x31, 0x9e,
 	0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x2f, 0x1e, 0xc9, 0x31,
 	0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x2f, 0x1e, 0xc9, 0x31,
-	0x7c, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0x43, 0x14, 0x0b, 0x28, 0x90, 0x92, 0xd8, 0xc0,
-	0xa1, 0x64, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xaa, 0x73, 0xf3, 0xd5, 0x33, 0x01, 0x00, 0x00,
+	0x7c, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb,
+	0x31, 0x44, 0xb1, 0x80, 0x02, 0x2b, 0x89, 0x0d, 0x1c, 0x5a, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff,
+	0xff, 0x64, 0x61, 0x71, 0x59, 0x3b, 0x01, 0x00, 0x00,
 }
 }

+ 132 - 0
vendor/github.com/moby/buildkit/session/content/attachable.go

@@ -0,0 +1,132 @@
+package content
+
+import (
+	"context"
+
+	api "github.com/containerd/containerd/api/services/content/v1"
+	"github.com/containerd/containerd/content"
+	"github.com/containerd/containerd/errdefs"
+	contentservice "github.com/containerd/containerd/services/content"
+	"github.com/moby/buildkit/session"
+	digest "github.com/opencontainers/go-digest"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/pkg/errors"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/metadata"
+)
+
+// GRPCHeaderID is a gRPC header for store ID
+const GRPCHeaderID = "buildkit-attachable-store-id"
+
+type attachableContentStore struct {
+	stores map[string]content.Store
+}
+
+func (cs *attachableContentStore) choose(ctx context.Context) (content.Store, error) {
+	md, ok := metadata.FromIncomingContext(ctx)
+	if !ok {
+		return nil, errors.Wrap(errdefs.ErrInvalidArgument, "request lacks metadata")
+	}
+
+	values := md[GRPCHeaderID]
+	if len(values) == 0 {
+		return nil, errors.Wrapf(errdefs.ErrInvalidArgument, "request lacks metadata %q", GRPCHeaderID)
+	}
+	id := values[0]
+	store, ok := cs.stores[id]
+	if !ok {
+		return nil, errors.Wrapf(errdefs.ErrNotFound, "unknown store %s", id)
+	}
+	return store, nil
+}
+
+func (cs *attachableContentStore) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) {
+	store, err := cs.choose(ctx)
+	if err != nil {
+		return content.Info{}, err
+	}
+	return store.Info(ctx, dgst)
+}
+
+func (cs *attachableContentStore) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
+	store, err := cs.choose(ctx)
+	if err != nil {
+		return content.Info{}, err
+	}
+	return store.Update(ctx, info, fieldpaths...)
+}
+
+func (cs *attachableContentStore) Walk(ctx context.Context, fn content.WalkFunc, fs ...string) error {
+	store, err := cs.choose(ctx)
+	if err != nil {
+		return err
+	}
+	return store.Walk(ctx, fn, fs...)
+}
+
+func (cs *attachableContentStore) Delete(ctx context.Context, dgst digest.Digest) error {
+	store, err := cs.choose(ctx)
+	if err != nil {
+		return err
+	}
+	return store.Delete(ctx, dgst)
+}
+
+func (cs *attachableContentStore) ListStatuses(ctx context.Context, fs ...string) ([]content.Status, error) {
+	store, err := cs.choose(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return store.ListStatuses(ctx, fs...)
+}
+
+func (cs *attachableContentStore) Status(ctx context.Context, ref string) (content.Status, error) {
+	store, err := cs.choose(ctx)
+	if err != nil {
+		return content.Status{}, err
+	}
+	return store.Status(ctx, ref)
+}
+
+func (cs *attachableContentStore) Abort(ctx context.Context, ref string) error {
+	store, err := cs.choose(ctx)
+	if err != nil {
+		return err
+	}
+	return store.Abort(ctx, ref)
+}
+
+func (cs *attachableContentStore) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
+	store, err := cs.choose(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return store.Writer(ctx, opts...)
+}
+
+func (cs *attachableContentStore) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
+	store, err := cs.choose(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return store.ReaderAt(ctx, desc)
+}
+
+type attachable struct {
+	service api.ContentServer
+}
+
+// NewAttachable creates session.Attachable from aggregated stores.
+// A key of the store map is an ID string that is used for choosing underlying store.
+func NewAttachable(stores map[string]content.Store) session.Attachable {
+	store := &attachableContentStore{stores: stores}
+	service := contentservice.NewService(store)
+	a := attachable{
+		service: service,
+	}
+	return &a
+}
+
+func (a *attachable) Register(server *grpc.Server) {
+	api.RegisterContentServer(server, a.service)
+}

+ 84 - 0
vendor/github.com/moby/buildkit/session/content/caller.go

@@ -0,0 +1,84 @@
+package content
+
+import (
+	"context"
+
+	api "github.com/containerd/containerd/api/services/content/v1"
+	"github.com/containerd/containerd/content"
+	"github.com/containerd/containerd/content/proxy"
+	"github.com/moby/buildkit/session"
+	digest "github.com/opencontainers/go-digest"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"google.golang.org/grpc/metadata"
+)
+
+type callerContentStore struct {
+	store   content.Store
+	storeID string
+}
+
+func (cs *callerContentStore) choose(ctx context.Context) context.Context {
+	nsheader := metadata.Pairs(GRPCHeaderID, cs.storeID)
+	md, ok := metadata.FromOutgoingContext(ctx) // merge with outgoing context.
+	if !ok {
+		md = nsheader
+	} else {
+		// order ensures the latest is first in this list.
+		md = metadata.Join(nsheader, md)
+	}
+	return metadata.NewOutgoingContext(ctx, md)
+}
+
+func (cs *callerContentStore) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) {
+	ctx = cs.choose(ctx)
+	return cs.store.Info(ctx, dgst)
+}
+
+func (cs *callerContentStore) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
+	ctx = cs.choose(ctx)
+	return cs.store.Update(ctx, info, fieldpaths...)
+}
+
+func (cs *callerContentStore) Walk(ctx context.Context, fn content.WalkFunc, fs ...string) error {
+	ctx = cs.choose(ctx)
+	return cs.store.Walk(ctx, fn, fs...)
+}
+
+func (cs *callerContentStore) Delete(ctx context.Context, dgst digest.Digest) error {
+	ctx = cs.choose(ctx)
+	return cs.store.Delete(ctx, dgst)
+}
+
+func (cs *callerContentStore) ListStatuses(ctx context.Context, fs ...string) ([]content.Status, error) {
+	ctx = cs.choose(ctx)
+	return cs.store.ListStatuses(ctx, fs...)
+}
+
+func (cs *callerContentStore) Status(ctx context.Context, ref string) (content.Status, error) {
+	ctx = cs.choose(ctx)
+	return cs.store.Status(ctx, ref)
+}
+
+func (cs *callerContentStore) Abort(ctx context.Context, ref string) error {
+	ctx = cs.choose(ctx)
+	return cs.store.Abort(ctx, ref)
+}
+
+func (cs *callerContentStore) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
+	ctx = cs.choose(ctx)
+	return cs.store.Writer(ctx, opts...)
+}
+
+func (cs *callerContentStore) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
+	ctx = cs.choose(ctx)
+	return cs.store.ReaderAt(ctx, desc)
+}
+
+// NewCallerStore creates content.Store from session.Caller with specified storeID
+func NewCallerStore(c session.Caller, storeID string) content.Store {
+	client := api.NewContentClient(c.Conn())
+	return &callerContentStore{
+		store:   proxy.NewContentStore(client),
+		storeID: storeID,
+	}
+}

+ 56 - 31
vendor/github.com/moby/buildkit/session/filesync/filesync.pb.go

@@ -1,15 +1,6 @@
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // source: filesync.proto
 // source: filesync.proto
 
 
-/*
-Package filesync is a generated protocol buffer package.
-
-It is generated from these files:
-	filesync.proto
-
-It has these top-level messages:
-	BytesMessage
-*/
 package filesync
 package filesync
 
 
 import proto "github.com/gogo/protobuf/proto"
 import proto "github.com/gogo/protobuf/proto"
@@ -21,8 +12,10 @@ import bytes "bytes"
 import strings "strings"
 import strings "strings"
 import reflect "reflect"
 import reflect "reflect"
 
 
-import context "golang.org/x/net/context"
-import grpc "google.golang.org/grpc"
+import (
+	context "golang.org/x/net/context"
+	grpc "google.golang.org/grpc"
+)
 
 
 import io "io"
 import io "io"
 
 
@@ -42,9 +35,37 @@ type BytesMessage struct {
 	Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
 	Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
 }
 }
 
 
-func (m *BytesMessage) Reset()                    { *m = BytesMessage{} }
-func (*BytesMessage) ProtoMessage()               {}
-func (*BytesMessage) Descriptor() ([]byte, []int) { return fileDescriptorFilesync, []int{0} }
+func (m *BytesMessage) Reset()      { *m = BytesMessage{} }
+func (*BytesMessage) ProtoMessage() {}
+func (*BytesMessage) Descriptor() ([]byte, []int) {
+	return fileDescriptor_filesync_26f8b7bce2e5ac0e, []int{0}
+}
+func (m *BytesMessage) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *BytesMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_BytesMessage.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (dst *BytesMessage) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_BytesMessage.Merge(dst, src)
+}
+func (m *BytesMessage) XXX_Size() int {
+	return m.Size()
+}
+func (m *BytesMessage) XXX_DiscardUnknown() {
+	xxx_messageInfo_BytesMessage.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_BytesMessage proto.InternalMessageInfo
 
 
 func (m *BytesMessage) GetData() []byte {
 func (m *BytesMessage) GetData() []byte {
 	if m != nil {
 	if m != nil {
@@ -107,8 +128,9 @@ var _ grpc.ClientConn
 // is compatible with the grpc package it is being compiled against.
 // is compatible with the grpc package it is being compiled against.
 const _ = grpc.SupportPackageIsVersion4
 const _ = grpc.SupportPackageIsVersion4
 
 
-// Client API for FileSync service
-
+// FileSyncClient is the client API for FileSync service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
 type FileSyncClient interface {
 type FileSyncClient interface {
 	DiffCopy(ctx context.Context, opts ...grpc.CallOption) (FileSync_DiffCopyClient, error)
 	DiffCopy(ctx context.Context, opts ...grpc.CallOption) (FileSync_DiffCopyClient, error)
 	TarStream(ctx context.Context, opts ...grpc.CallOption) (FileSync_TarStreamClient, error)
 	TarStream(ctx context.Context, opts ...grpc.CallOption) (FileSync_TarStreamClient, error)
@@ -123,7 +145,7 @@ func NewFileSyncClient(cc *grpc.ClientConn) FileSyncClient {
 }
 }
 
 
 func (c *fileSyncClient) DiffCopy(ctx context.Context, opts ...grpc.CallOption) (FileSync_DiffCopyClient, error) {
 func (c *fileSyncClient) DiffCopy(ctx context.Context, opts ...grpc.CallOption) (FileSync_DiffCopyClient, error) {
-	stream, err := grpc.NewClientStream(ctx, &_FileSync_serviceDesc.Streams[0], c.cc, "/moby.filesync.v1.FileSync/DiffCopy", opts...)
+	stream, err := c.cc.NewStream(ctx, &_FileSync_serviceDesc.Streams[0], "/moby.filesync.v1.FileSync/DiffCopy", opts...)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -154,7 +176,7 @@ func (x *fileSyncDiffCopyClient) Recv() (*BytesMessage, error) {
 }
 }
 
 
 func (c *fileSyncClient) TarStream(ctx context.Context, opts ...grpc.CallOption) (FileSync_TarStreamClient, error) {
 func (c *fileSyncClient) TarStream(ctx context.Context, opts ...grpc.CallOption) (FileSync_TarStreamClient, error) {
-	stream, err := grpc.NewClientStream(ctx, &_FileSync_serviceDesc.Streams[1], c.cc, "/moby.filesync.v1.FileSync/TarStream", opts...)
+	stream, err := c.cc.NewStream(ctx, &_FileSync_serviceDesc.Streams[1], "/moby.filesync.v1.FileSync/TarStream", opts...)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -184,8 +206,7 @@ func (x *fileSyncTarStreamClient) Recv() (*BytesMessage, error) {
 	return m, nil
 	return m, nil
 }
 }
 
 
-// Server API for FileSync service
-
+// FileSyncServer is the server API for FileSync service.
 type FileSyncServer interface {
 type FileSyncServer interface {
 	DiffCopy(FileSync_DiffCopyServer) error
 	DiffCopy(FileSync_DiffCopyServer) error
 	TarStream(FileSync_TarStreamServer) error
 	TarStream(FileSync_TarStreamServer) error
@@ -268,8 +289,9 @@ var _FileSync_serviceDesc = grpc.ServiceDesc{
 	Metadata: "filesync.proto",
 	Metadata: "filesync.proto",
 }
 }
 
 
-// Client API for FileSend service
-
+// FileSendClient is the client API for FileSend service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
 type FileSendClient interface {
 type FileSendClient interface {
 	DiffCopy(ctx context.Context, opts ...grpc.CallOption) (FileSend_DiffCopyClient, error)
 	DiffCopy(ctx context.Context, opts ...grpc.CallOption) (FileSend_DiffCopyClient, error)
 }
 }
@@ -283,7 +305,7 @@ func NewFileSendClient(cc *grpc.ClientConn) FileSendClient {
 }
 }
 
 
 func (c *fileSendClient) DiffCopy(ctx context.Context, opts ...grpc.CallOption) (FileSend_DiffCopyClient, error) {
 func (c *fileSendClient) DiffCopy(ctx context.Context, opts ...grpc.CallOption) (FileSend_DiffCopyClient, error) {
-	stream, err := grpc.NewClientStream(ctx, &_FileSend_serviceDesc.Streams[0], c.cc, "/moby.filesync.v1.FileSend/DiffCopy", opts...)
+	stream, err := c.cc.NewStream(ctx, &_FileSend_serviceDesc.Streams[0], "/moby.filesync.v1.FileSend/DiffCopy", opts...)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -313,8 +335,7 @@ func (x *fileSendDiffCopyClient) Recv() (*BytesMessage, error) {
 	return m, nil
 	return m, nil
 }
 }
 
 
-// Server API for FileSend service
-
+// FileSendServer is the server API for FileSend service.
 type FileSendServer interface {
 type FileSendServer interface {
 	DiffCopy(FileSend_DiffCopyServer) error
 	DiffCopy(FileSend_DiffCopyServer) error
 }
 }
@@ -398,6 +419,9 @@ func encodeVarintFilesync(dAtA []byte, offset int, v uint64) int {
 	return offset + 1
 	return offset + 1
 }
 }
 func (m *BytesMessage) Size() (n int) {
 func (m *BytesMessage) Size() (n int) {
+	if m == nil {
+		return 0
+	}
 	var l int
 	var l int
 	_ = l
 	_ = l
 	l = len(m.Data)
 	l = len(m.Data)
@@ -624,10 +648,10 @@ var (
 	ErrIntOverflowFilesync   = fmt.Errorf("proto: integer overflow")
 	ErrIntOverflowFilesync   = fmt.Errorf("proto: integer overflow")
 )
 )
 
 
-func init() { proto.RegisterFile("filesync.proto", fileDescriptorFilesync) }
+func init() { proto.RegisterFile("filesync.proto", fileDescriptor_filesync_26f8b7bce2e5ac0e) }
 
 
-var fileDescriptorFilesync = []byte{
-	// 208 bytes of a gzipped FileDescriptorProto
+var fileDescriptor_filesync_26f8b7bce2e5ac0e = []byte{
+	// 217 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4b, 0xcb, 0xcc, 0x49,
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4b, 0xcb, 0xcc, 0x49,
 	0x2d, 0xae, 0xcc, 0x4b, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0xc8, 0xcd, 0x4f, 0xaa,
 	0x2d, 0xae, 0xcc, 0x4b, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0xc8, 0xcd, 0x4f, 0xaa,
 	0xd4, 0x83, 0x0b, 0x96, 0x19, 0x2a, 0x29, 0x71, 0xf1, 0x38, 0x55, 0x96, 0xa4, 0x16, 0xfb, 0xa6,
 	0xd4, 0x83, 0x0b, 0x96, 0x19, 0x2a, 0x29, 0x71, 0xf1, 0x38, 0x55, 0x96, 0xa4, 0x16, 0xfb, 0xa6,
@@ -636,9 +660,10 @@ var fileDescriptorFilesync = []byte{
 	0x2b, 0xf3, 0x92, 0x85, 0xfc, 0xb8, 0x38, 0x5c, 0x32, 0xd3, 0xd2, 0x9c, 0xf3, 0x0b, 0x2a, 0x85,
 	0x2b, 0xf3, 0x92, 0x85, 0xfc, 0xb8, 0x38, 0x5c, 0x32, 0xd3, 0xd2, 0x9c, 0xf3, 0x0b, 0x2a, 0x85,
 	0xe4, 0xf4, 0xd0, 0xcd, 0xd3, 0x43, 0x36, 0x4c, 0x8a, 0x80, 0xbc, 0x06, 0xa3, 0x01, 0xa3, 0x90,
 	0xe4, 0xf4, 0xd0, 0xcd, 0xd3, 0x43, 0x36, 0x4c, 0x8a, 0x80, 0xbc, 0x06, 0xa3, 0x01, 0xa3, 0x90,
 	0x3f, 0x17, 0x67, 0x48, 0x62, 0x51, 0x70, 0x49, 0x51, 0x6a, 0x62, 0x2e, 0x35, 0x0c, 0x34, 0x8a,
 	0x3f, 0x17, 0x67, 0x48, 0x62, 0x51, 0x70, 0x49, 0x51, 0x6a, 0x62, 0x2e, 0x35, 0x0c, 0x34, 0x8a,
-	0x82, 0x3a, 0x36, 0x35, 0x2f, 0x85, 0xda, 0x8e, 0x75, 0x32, 0xbb, 0xf0, 0x50, 0x8e, 0xe1, 0xc6,
+	0x82, 0x3a, 0x36, 0x35, 0x2f, 0x85, 0xda, 0x8e, 0x75, 0xb2, 0xbb, 0xf0, 0x50, 0x8e, 0xe1, 0xc6,
 	0x43, 0x39, 0x86, 0x0f, 0x0f, 0xe5, 0x18, 0x1b, 0x1e, 0xc9, 0x31, 0xae, 0x78, 0x24, 0xc7, 0x78,
 	0x43, 0x39, 0x86, 0x0f, 0x0f, 0xe5, 0x18, 0x1b, 0x1e, 0xc9, 0x31, 0xae, 0x78, 0x24, 0xc7, 0x78,
 	0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0xbe, 0x78, 0x24, 0xc7,
 	0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0xbe, 0x78, 0x24, 0xc7,
-	0xf0, 0xe1, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x51, 0x1c, 0x30, 0xb3, 0x92, 0xd8, 0xc0,
-	0xc1, 0x6f, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x72, 0x81, 0x1a, 0x91, 0x90, 0x01, 0x00, 0x00,
+	0xf0, 0xe1, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c,
+	0xc7, 0x10, 0xc5, 0x01, 0x33, 0x33, 0x89, 0x0d, 0x1c, 0x0d, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff,
+	0xff, 0x5e, 0xce, 0x52, 0xb3, 0x98, 0x01, 0x00, 0x00,
 }
 }

+ 88 - 33
vendor/github.com/moby/buildkit/session/secrets/secrets.pb.go

@@ -1,16 +1,6 @@
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // source: secrets.proto
 // source: secrets.proto
 
 
-/*
-	Package secrets is a generated protocol buffer package.
-
-	It is generated from these files:
-		secrets.proto
-
-	It has these top-level messages:
-		GetSecretRequest
-		GetSecretResponse
-*/
 package secrets
 package secrets
 
 
 import proto "github.com/gogo/protobuf/proto"
 import proto "github.com/gogo/protobuf/proto"
@@ -21,10 +11,12 @@ import bytes "bytes"
 
 
 import strings "strings"
 import strings "strings"
 import reflect "reflect"
 import reflect "reflect"
-import sortkeys "github.com/gogo/protobuf/sortkeys"
+import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
 
 
-import context "golang.org/x/net/context"
-import grpc "google.golang.org/grpc"
+import (
+	context "golang.org/x/net/context"
+	grpc "google.golang.org/grpc"
+)
 
 
 import io "io"
 import io "io"
 
 
@@ -41,12 +33,40 @@ const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
 
 
 type GetSecretRequest struct {
 type GetSecretRequest struct {
 	ID          string            `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
 	ID          string            `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
-	Annotations map[string]string `protobuf:"bytes,2,rep,name=annotations" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	Annotations map[string]string `protobuf:"bytes,2,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
 }
 }
 
 
-func (m *GetSecretRequest) Reset()                    { *m = GetSecretRequest{} }
-func (*GetSecretRequest) ProtoMessage()               {}
-func (*GetSecretRequest) Descriptor() ([]byte, []int) { return fileDescriptorSecrets, []int{0} }
+func (m *GetSecretRequest) Reset()      { *m = GetSecretRequest{} }
+func (*GetSecretRequest) ProtoMessage() {}
+func (*GetSecretRequest) Descriptor() ([]byte, []int) {
+	return fileDescriptor_secrets_21bd4adec74a381e, []int{0}
+}
+func (m *GetSecretRequest) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *GetSecretRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_GetSecretRequest.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (dst *GetSecretRequest) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_GetSecretRequest.Merge(dst, src)
+}
+func (m *GetSecretRequest) XXX_Size() int {
+	return m.Size()
+}
+func (m *GetSecretRequest) XXX_DiscardUnknown() {
+	xxx_messageInfo_GetSecretRequest.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_GetSecretRequest proto.InternalMessageInfo
 
 
 func (m *GetSecretRequest) GetID() string {
 func (m *GetSecretRequest) GetID() string {
 	if m != nil {
 	if m != nil {
@@ -66,9 +86,37 @@ type GetSecretResponse struct {
 	Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
 	Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
 }
 }
 
 
-func (m *GetSecretResponse) Reset()                    { *m = GetSecretResponse{} }
-func (*GetSecretResponse) ProtoMessage()               {}
-func (*GetSecretResponse) Descriptor() ([]byte, []int) { return fileDescriptorSecrets, []int{1} }
+func (m *GetSecretResponse) Reset()      { *m = GetSecretResponse{} }
+func (*GetSecretResponse) ProtoMessage() {}
+func (*GetSecretResponse) Descriptor() ([]byte, []int) {
+	return fileDescriptor_secrets_21bd4adec74a381e, []int{1}
+}
+func (m *GetSecretResponse) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *GetSecretResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_GetSecretResponse.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (dst *GetSecretResponse) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_GetSecretResponse.Merge(dst, src)
+}
+func (m *GetSecretResponse) XXX_Size() int {
+	return m.Size()
+}
+func (m *GetSecretResponse) XXX_DiscardUnknown() {
+	xxx_messageInfo_GetSecretResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_GetSecretResponse proto.InternalMessageInfo
 
 
 func (m *GetSecretResponse) GetData() []byte {
 func (m *GetSecretResponse) GetData() []byte {
 	if m != nil {
 	if m != nil {
@@ -79,6 +127,7 @@ func (m *GetSecretResponse) GetData() []byte {
 
 
 func init() {
 func init() {
 	proto.RegisterType((*GetSecretRequest)(nil), "moby.buildkit.secrets.v1.GetSecretRequest")
 	proto.RegisterType((*GetSecretRequest)(nil), "moby.buildkit.secrets.v1.GetSecretRequest")
+	proto.RegisterMapType((map[string]string)(nil), "moby.buildkit.secrets.v1.GetSecretRequest.AnnotationsEntry")
 	proto.RegisterType((*GetSecretResponse)(nil), "moby.buildkit.secrets.v1.GetSecretResponse")
 	proto.RegisterType((*GetSecretResponse)(nil), "moby.buildkit.secrets.v1.GetSecretResponse")
 }
 }
 func (this *GetSecretRequest) Equal(that interface{}) bool {
 func (this *GetSecretRequest) Equal(that interface{}) bool {
@@ -148,7 +197,7 @@ func (this *GetSecretRequest) GoString() string {
 	for k, _ := range this.Annotations {
 	for k, _ := range this.Annotations {
 		keysForAnnotations = append(keysForAnnotations, k)
 		keysForAnnotations = append(keysForAnnotations, k)
 	}
 	}
-	sortkeys.Strings(keysForAnnotations)
+	github_com_gogo_protobuf_sortkeys.Strings(keysForAnnotations)
 	mapStringForAnnotations := "map[string]string{"
 	mapStringForAnnotations := "map[string]string{"
 	for _, k := range keysForAnnotations {
 	for _, k := range keysForAnnotations {
 		mapStringForAnnotations += fmt.Sprintf("%#v: %#v,", k, this.Annotations[k])
 		mapStringForAnnotations += fmt.Sprintf("%#v: %#v,", k, this.Annotations[k])
@@ -187,8 +236,9 @@ var _ grpc.ClientConn
 // is compatible with the grpc package it is being compiled against.
 // is compatible with the grpc package it is being compiled against.
 const _ = grpc.SupportPackageIsVersion4
 const _ = grpc.SupportPackageIsVersion4
 
 
-// Client API for Secrets service
-
+// SecretsClient is the client API for Secrets service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
 type SecretsClient interface {
 type SecretsClient interface {
 	GetSecret(ctx context.Context, in *GetSecretRequest, opts ...grpc.CallOption) (*GetSecretResponse, error)
 	GetSecret(ctx context.Context, in *GetSecretRequest, opts ...grpc.CallOption) (*GetSecretResponse, error)
 }
 }
@@ -203,15 +253,14 @@ func NewSecretsClient(cc *grpc.ClientConn) SecretsClient {
 
 
 func (c *secretsClient) GetSecret(ctx context.Context, in *GetSecretRequest, opts ...grpc.CallOption) (*GetSecretResponse, error) {
 func (c *secretsClient) GetSecret(ctx context.Context, in *GetSecretRequest, opts ...grpc.CallOption) (*GetSecretResponse, error) {
 	out := new(GetSecretResponse)
 	out := new(GetSecretResponse)
-	err := grpc.Invoke(ctx, "/moby.buildkit.secrets.v1.Secrets/GetSecret", in, out, c.cc, opts...)
+	err := c.cc.Invoke(ctx, "/moby.buildkit.secrets.v1.Secrets/GetSecret", in, out, opts...)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 	return out, nil
 	return out, nil
 }
 }
 
 
-// Server API for Secrets service
-
+// SecretsServer is the server API for Secrets service.
 type SecretsServer interface {
 type SecretsServer interface {
 	GetSecret(context.Context, *GetSecretRequest) (*GetSecretResponse, error)
 	GetSecret(context.Context, *GetSecretRequest) (*GetSecretResponse, error)
 }
 }
@@ -326,6 +375,9 @@ func encodeVarintSecrets(dAtA []byte, offset int, v uint64) int {
 	return offset + 1
 	return offset + 1
 }
 }
 func (m *GetSecretRequest) Size() (n int) {
 func (m *GetSecretRequest) Size() (n int) {
+	if m == nil {
+		return 0
+	}
 	var l int
 	var l int
 	_ = l
 	_ = l
 	l = len(m.ID)
 	l = len(m.ID)
@@ -344,6 +396,9 @@ func (m *GetSecretRequest) Size() (n int) {
 }
 }
 
 
 func (m *GetSecretResponse) Size() (n int) {
 func (m *GetSecretResponse) Size() (n int) {
+	if m == nil {
+		return 0
+	}
 	var l int
 	var l int
 	_ = l
 	_ = l
 	l = len(m.Data)
 	l = len(m.Data)
@@ -374,7 +429,7 @@ func (this *GetSecretRequest) String() string {
 	for k, _ := range this.Annotations {
 	for k, _ := range this.Annotations {
 		keysForAnnotations = append(keysForAnnotations, k)
 		keysForAnnotations = append(keysForAnnotations, k)
 	}
 	}
-	sortkeys.Strings(keysForAnnotations)
+	github_com_gogo_protobuf_sortkeys.Strings(keysForAnnotations)
 	mapStringForAnnotations := "map[string]string{"
 	mapStringForAnnotations := "map[string]string{"
 	for _, k := range keysForAnnotations {
 	for _, k := range keysForAnnotations {
 		mapStringForAnnotations += fmt.Sprintf("%v: %v,", k, this.Annotations[k])
 		mapStringForAnnotations += fmt.Sprintf("%v: %v,", k, this.Annotations[k])
@@ -788,10 +843,10 @@ var (
 	ErrIntOverflowSecrets   = fmt.Errorf("proto: integer overflow")
 	ErrIntOverflowSecrets   = fmt.Errorf("proto: integer overflow")
 )
 )
 
 
-func init() { proto.RegisterFile("secrets.proto", fileDescriptorSecrets) }
+func init() { proto.RegisterFile("secrets.proto", fileDescriptor_secrets_21bd4adec74a381e) }
 
 
-var fileDescriptorSecrets = []byte{
-	// 279 bytes of a gzipped FileDescriptorProto
+var fileDescriptor_secrets_21bd4adec74a381e = []byte{
+	// 288 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2d, 0x4e, 0x4d, 0x2e,
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2d, 0x4e, 0x4d, 0x2e,
 	0x4a, 0x2d, 0x29, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0xc8, 0xcd, 0x4f, 0xaa, 0xd4,
 	0x4a, 0x2d, 0x29, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0xc8, 0xcd, 0x4f, 0xaa, 0xd4,
 	0x4b, 0x2a, 0xcd, 0xcc, 0x49, 0xc9, 0xce, 0x2c, 0xd1, 0x83, 0x49, 0x96, 0x19, 0x2a, 0x1d, 0x64,
 	0x4b, 0x2a, 0xcd, 0xcc, 0x49, 0xc9, 0xce, 0x2c, 0xd1, 0x83, 0x49, 0x96, 0x19, 0x2a, 0x1d, 0x64,
@@ -805,9 +860,9 @@ var fileDescriptorSecrets = []byte{
 	0x41, 0x24, 0x1b, 0x8b, 0x0b, 0xf2, 0xf3, 0x8a, 0x53, 0x85, 0x84, 0xb8, 0x58, 0x52, 0x12, 0x4b,
 	0x41, 0x24, 0x1b, 0x8b, 0x0b, 0xf2, 0xf3, 0x8a, 0x53, 0x85, 0x84, 0xb8, 0x58, 0x52, 0x12, 0x4b,
 	0x12, 0xc1, 0x26, 0xf0, 0x04, 0x81, 0xd9, 0x46, 0xf9, 0x5c, 0xec, 0x10, 0x55, 0xc5, 0x42, 0x29,
 	0x12, 0xc1, 0x26, 0xf0, 0x04, 0x81, 0xd9, 0x46, 0xf9, 0x5c, 0xec, 0x10, 0x55, 0xc5, 0x42, 0x29,
 	0x5c, 0x9c, 0x70, 0x3d, 0x42, 0x5a, 0xc4, 0x7b, 0x45, 0x4a, 0x9b, 0x28, 0xb5, 0x10, 0x47, 0x38,
 	0x5c, 0x9c, 0x70, 0x3d, 0x42, 0x5a, 0xc4, 0x7b, 0x45, 0x4a, 0x9b, 0x28, 0xb5, 0x10, 0x47, 0x38,
-	0x99, 0x5e, 0x78, 0x28, 0xc7, 0x70, 0xe3, 0xa1, 0x1c, 0xc3, 0x87, 0x87, 0x72, 0x8c, 0x0d, 0x8f,
+	0xd9, 0x5e, 0x78, 0x28, 0xc7, 0x70, 0xe3, 0xa1, 0x1c, 0xc3, 0x87, 0x87, 0x72, 0x8c, 0x0d, 0x8f,
 	0xe4, 0x18, 0x57, 0x3c, 0x92, 0x63, 0x3c, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07,
 	0xe4, 0x18, 0x57, 0x3c, 0x92, 0x63, 0x3c, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07,
 	0x8f, 0xe4, 0x18, 0x5f, 0x3c, 0x92, 0x63, 0xf8, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86,
 	0x8f, 0xe4, 0x18, 0x5f, 0x3c, 0x92, 0x63, 0xf8, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86,
-	0x28, 0x76, 0xa8, 0x59, 0x49, 0x6c, 0xe0, 0x58, 0x33, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x05,
-	0x4e, 0x56, 0xde, 0xc6, 0x01, 0x00, 0x00,
+	0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0x62, 0x87, 0x9a, 0x99, 0xc4, 0x06, 0x8e,
+	0x3d, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2c, 0x38, 0xec, 0x1f, 0xce, 0x01, 0x00, 0x00,
 }
 }

+ 119 - 35
vendor/github.com/moby/buildkit/session/sshforward/ssh.pb.go

@@ -1,17 +1,6 @@
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // source: ssh.proto
 // source: ssh.proto
 
 
-/*
-Package sshforward is a generated protocol buffer package.
-
-It is generated from these files:
-	ssh.proto
-
-It has these top-level messages:
-	BytesMessage
-	CheckAgentRequest
-	CheckAgentResponse
-*/
 package sshforward
 package sshforward
 
 
 import proto "github.com/gogo/protobuf/proto"
 import proto "github.com/gogo/protobuf/proto"
@@ -23,8 +12,10 @@ import bytes "bytes"
 import strings "strings"
 import strings "strings"
 import reflect "reflect"
 import reflect "reflect"
 
 
-import context "golang.org/x/net/context"
-import grpc "google.golang.org/grpc"
+import (
+	context "golang.org/x/net/context"
+	grpc "google.golang.org/grpc"
+)
 
 
 import io "io"
 import io "io"
 
 
@@ -44,9 +35,37 @@ type BytesMessage struct {
 	Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
 	Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
 }
 }
 
 
-func (m *BytesMessage) Reset()                    { *m = BytesMessage{} }
-func (*BytesMessage) ProtoMessage()               {}
-func (*BytesMessage) Descriptor() ([]byte, []int) { return fileDescriptorSsh, []int{0} }
+func (m *BytesMessage) Reset()      { *m = BytesMessage{} }
+func (*BytesMessage) ProtoMessage() {}
+func (*BytesMessage) Descriptor() ([]byte, []int) {
+	return fileDescriptor_ssh_13bd2c34c031d472, []int{0}
+}
+func (m *BytesMessage) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *BytesMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_BytesMessage.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (dst *BytesMessage) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_BytesMessage.Merge(dst, src)
+}
+func (m *BytesMessage) XXX_Size() int {
+	return m.Size()
+}
+func (m *BytesMessage) XXX_DiscardUnknown() {
+	xxx_messageInfo_BytesMessage.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_BytesMessage proto.InternalMessageInfo
 
 
 func (m *BytesMessage) GetData() []byte {
 func (m *BytesMessage) GetData() []byte {
 	if m != nil {
 	if m != nil {
@@ -59,9 +78,37 @@ type CheckAgentRequest struct {
 	ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
 	ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
 }
 }
 
 
-func (m *CheckAgentRequest) Reset()                    { *m = CheckAgentRequest{} }
-func (*CheckAgentRequest) ProtoMessage()               {}
-func (*CheckAgentRequest) Descriptor() ([]byte, []int) { return fileDescriptorSsh, []int{1} }
+func (m *CheckAgentRequest) Reset()      { *m = CheckAgentRequest{} }
+func (*CheckAgentRequest) ProtoMessage() {}
+func (*CheckAgentRequest) Descriptor() ([]byte, []int) {
+	return fileDescriptor_ssh_13bd2c34c031d472, []int{1}
+}
+func (m *CheckAgentRequest) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *CheckAgentRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_CheckAgentRequest.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (dst *CheckAgentRequest) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_CheckAgentRequest.Merge(dst, src)
+}
+func (m *CheckAgentRequest) XXX_Size() int {
+	return m.Size()
+}
+func (m *CheckAgentRequest) XXX_DiscardUnknown() {
+	xxx_messageInfo_CheckAgentRequest.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CheckAgentRequest proto.InternalMessageInfo
 
 
 func (m *CheckAgentRequest) GetID() string {
 func (m *CheckAgentRequest) GetID() string {
 	if m != nil {
 	if m != nil {
@@ -73,9 +120,37 @@ func (m *CheckAgentRequest) GetID() string {
 type CheckAgentResponse struct {
 type CheckAgentResponse struct {
 }
 }
 
 
-func (m *CheckAgentResponse) Reset()                    { *m = CheckAgentResponse{} }
-func (*CheckAgentResponse) ProtoMessage()               {}
-func (*CheckAgentResponse) Descriptor() ([]byte, []int) { return fileDescriptorSsh, []int{2} }
+func (m *CheckAgentResponse) Reset()      { *m = CheckAgentResponse{} }
+func (*CheckAgentResponse) ProtoMessage() {}
+func (*CheckAgentResponse) Descriptor() ([]byte, []int) {
+	return fileDescriptor_ssh_13bd2c34c031d472, []int{2}
+}
+func (m *CheckAgentResponse) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *CheckAgentResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_CheckAgentResponse.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (dst *CheckAgentResponse) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_CheckAgentResponse.Merge(dst, src)
+}
+func (m *CheckAgentResponse) XXX_Size() int {
+	return m.Size()
+}
+func (m *CheckAgentResponse) XXX_DiscardUnknown() {
+	xxx_messageInfo_CheckAgentResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CheckAgentResponse proto.InternalMessageInfo
 
 
 func init() {
 func init() {
 	proto.RegisterType((*BytesMessage)(nil), "moby.sshforward.v1.BytesMessage")
 	proto.RegisterType((*BytesMessage)(nil), "moby.sshforward.v1.BytesMessage")
@@ -197,8 +272,9 @@ var _ grpc.ClientConn
 // is compatible with the grpc package it is being compiled against.
 // is compatible with the grpc package it is being compiled against.
 const _ = grpc.SupportPackageIsVersion4
 const _ = grpc.SupportPackageIsVersion4
 
 
-// Client API for SSH service
-
+// SSHClient is the client API for SSH service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
 type SSHClient interface {
 type SSHClient interface {
 	CheckAgent(ctx context.Context, in *CheckAgentRequest, opts ...grpc.CallOption) (*CheckAgentResponse, error)
 	CheckAgent(ctx context.Context, in *CheckAgentRequest, opts ...grpc.CallOption) (*CheckAgentResponse, error)
 	ForwardAgent(ctx context.Context, opts ...grpc.CallOption) (SSH_ForwardAgentClient, error)
 	ForwardAgent(ctx context.Context, opts ...grpc.CallOption) (SSH_ForwardAgentClient, error)
@@ -214,7 +290,7 @@ func NewSSHClient(cc *grpc.ClientConn) SSHClient {
 
 
 func (c *sSHClient) CheckAgent(ctx context.Context, in *CheckAgentRequest, opts ...grpc.CallOption) (*CheckAgentResponse, error) {
 func (c *sSHClient) CheckAgent(ctx context.Context, in *CheckAgentRequest, opts ...grpc.CallOption) (*CheckAgentResponse, error) {
 	out := new(CheckAgentResponse)
 	out := new(CheckAgentResponse)
-	err := grpc.Invoke(ctx, "/moby.sshforward.v1.SSH/CheckAgent", in, out, c.cc, opts...)
+	err := c.cc.Invoke(ctx, "/moby.sshforward.v1.SSH/CheckAgent", in, out, opts...)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -222,7 +298,7 @@ func (c *sSHClient) CheckAgent(ctx context.Context, in *CheckAgentRequest, opts
 }
 }
 
 
 func (c *sSHClient) ForwardAgent(ctx context.Context, opts ...grpc.CallOption) (SSH_ForwardAgentClient, error) {
 func (c *sSHClient) ForwardAgent(ctx context.Context, opts ...grpc.CallOption) (SSH_ForwardAgentClient, error) {
-	stream, err := grpc.NewClientStream(ctx, &_SSH_serviceDesc.Streams[0], c.cc, "/moby.sshforward.v1.SSH/ForwardAgent", opts...)
+	stream, err := c.cc.NewStream(ctx, &_SSH_serviceDesc.Streams[0], "/moby.sshforward.v1.SSH/ForwardAgent", opts...)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -252,8 +328,7 @@ func (x *sSHForwardAgentClient) Recv() (*BytesMessage, error) {
 	return m, nil
 	return m, nil
 }
 }
 
 
-// Server API for SSH service
-
+// SSHServer is the server API for SSH service.
 type SSHServer interface {
 type SSHServer interface {
 	CheckAgent(context.Context, *CheckAgentRequest) (*CheckAgentResponse, error)
 	CheckAgent(context.Context, *CheckAgentRequest) (*CheckAgentResponse, error)
 	ForwardAgent(SSH_ForwardAgentServer) error
 	ForwardAgent(SSH_ForwardAgentServer) error
@@ -403,6 +478,9 @@ func encodeVarintSsh(dAtA []byte, offset int, v uint64) int {
 	return offset + 1
 	return offset + 1
 }
 }
 func (m *BytesMessage) Size() (n int) {
 func (m *BytesMessage) Size() (n int) {
+	if m == nil {
+		return 0
+	}
 	var l int
 	var l int
 	_ = l
 	_ = l
 	l = len(m.Data)
 	l = len(m.Data)
@@ -413,6 +491,9 @@ func (m *BytesMessage) Size() (n int) {
 }
 }
 
 
 func (m *CheckAgentRequest) Size() (n int) {
 func (m *CheckAgentRequest) Size() (n int) {
+	if m == nil {
+		return 0
+	}
 	var l int
 	var l int
 	_ = l
 	_ = l
 	l = len(m.ID)
 	l = len(m.ID)
@@ -423,6 +504,9 @@ func (m *CheckAgentRequest) Size() (n int) {
 }
 }
 
 
 func (m *CheckAgentResponse) Size() (n int) {
 func (m *CheckAgentResponse) Size() (n int) {
+	if m == nil {
+		return 0
+	}
 	var l int
 	var l int
 	_ = l
 	_ = l
 	return n
 	return n
@@ -793,10 +877,10 @@ var (
 	ErrIntOverflowSsh   = fmt.Errorf("proto: integer overflow")
 	ErrIntOverflowSsh   = fmt.Errorf("proto: integer overflow")
 )
 )
 
 
-func init() { proto.RegisterFile("ssh.proto", fileDescriptorSsh) }
+func init() { proto.RegisterFile("ssh.proto", fileDescriptor_ssh_13bd2c34c031d472) }
 
 
-var fileDescriptorSsh = []byte{
-	// 243 bytes of a gzipped FileDescriptorProto
+var fileDescriptor_ssh_13bd2c34c031d472 = []byte{
+	// 252 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2c, 0x2e, 0xce, 0xd0,
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2c, 0x2e, 0xce, 0xd0,
 	0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0xca, 0xcd, 0x4f, 0xaa, 0xd4, 0x2b, 0x2e, 0xce, 0x48,
 	0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0xca, 0xcd, 0x4f, 0xaa, 0xd4, 0x2b, 0x2e, 0xce, 0x48,
 	0xcb, 0x2f, 0x2a, 0x4f, 0x2c, 0x4a, 0xd1, 0x2b, 0x33, 0x54, 0x52, 0xe2, 0xe2, 0x71, 0xaa, 0x2c,
 	0xcb, 0x2f, 0x2a, 0x4f, 0x2c, 0x4a, 0xd1, 0x2b, 0x33, 0x54, 0x52, 0xe2, 0xe2, 0x71, 0xaa, 0x2c,
@@ -807,10 +891,10 @@ var fileDescriptorSsh = []byte{
 	0x90, 0x15, 0x15, 0x17, 0xe4, 0xe7, 0x15, 0xa7, 0x1a, 0xed, 0x62, 0xe4, 0x62, 0x0e, 0x0e, 0xf6,
 	0x90, 0x15, 0x15, 0x17, 0xe4, 0xe7, 0x15, 0xa7, 0x1a, 0xed, 0x62, 0xe4, 0x62, 0x0e, 0x0e, 0xf6,
 	0x10, 0x8a, 0xe6, 0xe2, 0x42, 0xc8, 0x0a, 0xa9, 0xea, 0x61, 0xba, 0x44, 0x0f, 0xc3, 0x0a, 0x29,
 	0x10, 0x8a, 0xe6, 0xe2, 0x42, 0xc8, 0x0a, 0xa9, 0xea, 0x61, 0xba, 0x44, 0x0f, 0xc3, 0x0a, 0x29,
 	0x35, 0x42, 0xca, 0x20, 0x96, 0x08, 0x85, 0x71, 0xf1, 0xb8, 0x41, 0x14, 0x40, 0x8c, 0x57, 0xc0,
 	0x35, 0x42, 0xca, 0x20, 0x96, 0x08, 0x85, 0x71, 0xf1, 0xb8, 0x41, 0x14, 0x40, 0x8c, 0x57, 0xc0,
-	0xa6, 0x0f, 0xd9, 0x97, 0x52, 0x04, 0x55, 0x68, 0x30, 0x1a, 0x30, 0x3a, 0x59, 0x5c, 0x78, 0x28,
+	0xa6, 0x0f, 0xd9, 0x97, 0x52, 0x04, 0x55, 0x68, 0x30, 0x1a, 0x30, 0x3a, 0x39, 0x5c, 0x78, 0x28,
 	0xc7, 0x70, 0xe3, 0xa1, 0x1c, 0xc3, 0x87, 0x87, 0x72, 0x8c, 0x0d, 0x8f, 0xe4, 0x18, 0x57, 0x3c,
 	0xc7, 0x70, 0xe3, 0xa1, 0x1c, 0xc3, 0x87, 0x87, 0x72, 0x8c, 0x0d, 0x8f, 0xe4, 0x18, 0x57, 0x3c,
 	0x92, 0x63, 0x3c, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x5f,
 	0x92, 0x63, 0x3c, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x5f,
-	0x3c, 0x92, 0x63, 0xf8, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x28, 0x2e, 0x84, 0x69,
-	0x49, 0x6c, 0xe0, 0x00, 0x37, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x31, 0x3e, 0x40, 0xab, 0x7d,
-	0x01, 0x00, 0x00,
+	0x3c, 0x92, 0x63, 0xf8, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18,
+	0x6e, 0x3c, 0x96, 0x63, 0x88, 0xe2, 0x42, 0x98, 0x9a, 0xc4, 0x06, 0x0e, 0x78, 0x63, 0x40, 0x00,
+	0x00, 0x00, 0xff, 0xff, 0x6c, 0xe6, 0x6d, 0xb7, 0x85, 0x01, 0x00, 0x00,
 }
 }

+ 80 - 3
vendor/github.com/moby/buildkit/solver/cachemanager.go

@@ -3,7 +3,9 @@ package solver
 import (
 import (
 	"context"
 	"context"
 	"fmt"
 	"fmt"
+	"strings"
 	"sync"
 	"sync"
+	"time"
 
 
 	"github.com/moby/buildkit/identity"
 	"github.com/moby/buildkit/identity"
 	digest "github.com/opencontainers/go-digest"
 	digest "github.com/opencontainers/go-digest"
@@ -142,15 +144,87 @@ func (c *cacheManager) Load(ctx context.Context, rec *CacheRecord) (Result, erro
 	return c.results.Load(ctx, res)
 	return c.results.Load(ctx, res)
 }
 }
 
 
-func (c *cacheManager) Save(k *CacheKey, r Result) (*ExportableCacheKey, error) {
+type LoadedResult struct {
+	Result      Result
+	CacheResult CacheResult
+	CacheKey    *CacheKey
+}
+
+func (c *cacheManager) filterResults(m map[string]Result, ck *CacheKey) (results []LoadedResult, err error) {
+	id := c.getID(ck)
+	if err := c.backend.WalkResults(id, func(cr CacheResult) error {
+		res, ok := m[id]
+		if ok {
+			results = append(results, LoadedResult{
+				Result:      res,
+				CacheKey:    ck,
+				CacheResult: cr,
+			})
+			delete(m, id)
+		}
+		return nil
+	}); err != nil {
+		for _, r := range results {
+			r.Result.Release(context.TODO())
+		}
+	}
+	for _, keys := range ck.Deps() {
+		for _, key := range keys {
+			res, err := c.filterResults(m, key.CacheKey.CacheKey)
+			if err != nil {
+				for _, r := range results {
+					r.Result.Release(context.TODO())
+				}
+				return nil, err
+			}
+			results = append(results, res...)
+		}
+	}
+	return
+}
+
+func (c *cacheManager) LoadWithParents(ctx context.Context, rec *CacheRecord) ([]LoadedResult, error) {
+	lwp, ok := c.results.(interface {
+		LoadWithParents(context.Context, CacheResult) (map[string]Result, error)
+	})
+	if !ok {
+		res, err := c.Load(ctx, rec)
+		if err != nil {
+			return nil, err
+		}
+		return []LoadedResult{{Result: res, CacheKey: rec.key, CacheResult: CacheResult{ID: c.getID(rec.key), CreatedAt: rec.CreatedAt}}}, nil
+	}
+	c.mu.RLock()
+	defer c.mu.RUnlock()
+
+	cr, err := c.backend.Load(c.getID(rec.key), rec.ID)
+	if err != nil {
+		return nil, err
+	}
+
+	m, err := lwp.LoadWithParents(ctx, cr)
+	if err != nil {
+		return nil, err
+	}
+
+	results, err := c.filterResults(m, rec.key)
+	if err != nil {
+		for _, r := range m {
+			r.Release(context.TODO())
+		}
+	}
+
+	return results, nil
+}
+
+func (c *cacheManager) Save(k *CacheKey, r Result, createdAt time.Time) (*ExportableCacheKey, error) {
 	c.mu.Lock()
 	c.mu.Lock()
 	defer c.mu.Unlock()
 	defer c.mu.Unlock()
 
 
-	res, err := c.results.Save(r)
+	res, err := c.results.Save(r, createdAt)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-
 	if err := c.backend.AddResult(c.getID(k), res); err != nil {
 	if err := c.backend.AddResult(c.getID(k), res); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -273,5 +347,8 @@ func (c *cacheManager) getIDFromDeps(k *CacheKey) string {
 }
 }
 
 
 func rootKey(dgst digest.Digest, output Index) digest.Digest {
 func rootKey(dgst digest.Digest, output Index) digest.Digest {
+	if strings.HasPrefix(dgst.String(), "random:") {
+		return digest.Digest("random:" + strings.TrimPrefix(digest.FromBytes([]byte(fmt.Sprintf("%s@%d", dgst, output))).String(), digest.Canonical.String()+":"))
+	}
 	return digest.FromBytes([]byte(fmt.Sprintf("%s@%d", dgst, output)))
 	return digest.FromBytes([]byte(fmt.Sprintf("%s@%d", dgst, output)))
 }
 }

+ 1 - 1
vendor/github.com/moby/buildkit/solver/cachestorage.go

@@ -44,7 +44,7 @@ type CacheInfoLink struct {
 // CacheResultStorage is interface for converting cache metadata result to
 // CacheResultStorage is interface for converting cache metadata result to
 // actual solve result
 // actual solve result
 type CacheResultStorage interface {
 type CacheResultStorage interface {
-	Save(Result) (CacheResult, error)
+	Save(Result, time.Time) (CacheResult, error)
 	Load(ctx context.Context, res CacheResult) (Result, error)
 	Load(ctx context.Context, res CacheResult) (Result, error)
 	LoadRemote(ctx context.Context, res CacheResult) (*Remote, error)
 	LoadRemote(ctx context.Context, res CacheResult) (*Remote, error)
 	Exists(id string) bool
 	Exists(id string) bool

+ 20 - 7
vendor/github.com/moby/buildkit/solver/combinedcache.go

@@ -4,6 +4,7 @@ import (
 	"context"
 	"context"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
+	"time"
 
 
 	digest "github.com/opencontainers/go-digest"
 	digest "github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
@@ -66,19 +67,31 @@ func (cm *combinedCacheManager) Query(inp []CacheKeyWithSelector, inputIndex Ind
 	return out, nil
 	return out, nil
 }
 }
 
 
-func (cm *combinedCacheManager) Load(ctx context.Context, rec *CacheRecord) (Result, error) {
-	res, err := rec.cacheManager.Load(ctx, rec)
+func (cm *combinedCacheManager) Load(ctx context.Context, rec *CacheRecord) (res Result, err error) {
+	results, err := rec.cacheManager.LoadWithParents(ctx, rec)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	if _, err := cm.main.Save(rec.key, res); err != nil {
-		return nil, err
+	defer func() {
+		for i, res := range results {
+			if err == nil && i == 0 {
+				continue
+			}
+			res.Result.Release(context.TODO())
+		}
+	}()
+	if rec.cacheManager != cm.main {
+		for _, res := range results {
+			if _, err := cm.main.Save(res.CacheKey, res.Result, res.CacheResult.CreatedAt); err != nil {
+				return nil, err
+			}
+		}
 	}
 	}
-	return res, nil
+	return results[0].Result, nil
 }
 }
 
 
-func (cm *combinedCacheManager) Save(key *CacheKey, s Result) (*ExportableCacheKey, error) {
-	return cm.main.Save(key, s)
+func (cm *combinedCacheManager) Save(key *CacheKey, s Result, createdAt time.Time) (*ExportableCacheKey, error) {
+	return cm.main.Save(key, s, createdAt)
 }
 }
 
 
 func (cm *combinedCacheManager) Records(ck *CacheKey) ([]*CacheRecord, error) {
 func (cm *combinedCacheManager) Records(ck *CacheKey) ([]*CacheRecord, error) {

+ 38 - 3
vendor/github.com/moby/buildkit/solver/edge.go

@@ -3,6 +3,7 @@ package solver
 import (
 import (
 	"context"
 	"context"
 	"sync"
 	"sync"
+	"time"
 
 
 	"github.com/moby/buildkit/solver/internal/pipe"
 	"github.com/moby/buildkit/solver/internal/pipe"
 	digest "github.com/opencontainers/go-digest"
 	digest "github.com/opencontainers/go-digest"
@@ -28,7 +29,7 @@ func newEdge(ed Edge, op activeOp, index *edgeIndex) *edge {
 		edge:         ed,
 		edge:         ed,
 		op:           op,
 		op:           op,
 		depRequests:  map[pipe.Receiver]*dep{},
 		depRequests:  map[pipe.Receiver]*dep{},
-		keyMap:       map[string]*CacheKey{},
+		keyMap:       map[string]struct{}{},
 		cacheRecords: map[string]*CacheRecord{},
 		cacheRecords: map[string]*CacheRecord{},
 		index:        index,
 		index:        index,
 	}
 	}
@@ -50,7 +51,7 @@ type edge struct {
 	execReq         pipe.Receiver
 	execReq         pipe.Receiver
 	err             error
 	err             error
 	cacheRecords    map[string]*CacheRecord
 	cacheRecords    map[string]*CacheRecord
-	keyMap          map[string]*CacheKey
+	keyMap          map[string]struct{}
 
 
 	noCacheMatchPossible      bool
 	noCacheMatchPossible      bool
 	allDepsCompletedCacheFast bool
 	allDepsCompletedCacheFast bool
@@ -526,6 +527,10 @@ func (e *edge) recalcCurrentState() {
 		}
 		}
 	}
 	}
 
 
+	for key := range newKeys {
+		e.keyMap[key] = struct{}{}
+	}
+
 	for _, r := range newKeys {
 	for _, r := range newKeys {
 		// TODO: add all deps automatically
 		// TODO: add all deps automatically
 		mergedKey := r.clone()
 		mergedKey := r.clone()
@@ -612,6 +617,36 @@ func (e *edge) recalcCurrentState() {
 		e.allDepsCompletedCacheSlow = e.cacheMapDone && allDepsCompletedCacheSlow
 		e.allDepsCompletedCacheSlow = e.cacheMapDone && allDepsCompletedCacheSlow
 		e.allDepsStateCacheSlow = e.cacheMapDone && allDepsStateCacheSlow
 		e.allDepsStateCacheSlow = e.cacheMapDone && allDepsStateCacheSlow
 		e.allDepsCompleted = e.cacheMapDone && allDepsCompleted
 		e.allDepsCompleted = e.cacheMapDone && allDepsCompleted
+
+		if e.allDepsStateCacheSlow && len(e.cacheRecords) > 0 && e.state == edgeStatusCacheFast {
+			openKeys := map[string]struct{}{}
+			for _, dep := range e.deps {
+				isSlowIncomplete := e.slowCacheFunc(dep) != nil && (dep.state == edgeStatusCacheSlow || (dep.state == edgeStatusComplete && !dep.slowCacheComplete))
+				if !isSlowIncomplete {
+					openDepKeys := map[string]struct{}{}
+					for key := range dep.keyMap {
+						if _, ok := e.keyMap[key]; !ok {
+							openDepKeys[key] = struct{}{}
+						}
+					}
+					if len(openKeys) != 0 {
+						for k := range openKeys {
+							if _, ok := openDepKeys[k]; !ok {
+								delete(openKeys, k)
+							}
+						}
+					} else {
+						openKeys = openDepKeys
+					}
+					if len(openKeys) == 0 {
+						e.state = edgeStatusCacheSlow
+						if debugScheduler {
+							logrus.Debugf("upgrade to cache-slow because no open keys")
+						}
+					}
+				}
+			}
+		}
 	}
 	}
 }
 }
 
 
@@ -845,7 +880,7 @@ func (e *edge) execOp(ctx context.Context) (interface{}, error) {
 	var exporters []CacheExporter
 	var exporters []CacheExporter
 
 
 	for _, cacheKey := range cacheKeys {
 	for _, cacheKey := range cacheKeys {
-		ck, err := e.op.Cache().Save(cacheKey, res)
+		ck, err := e.op.Cache().Save(cacheKey, res, time.Now())
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}

+ 1 - 1
vendor/github.com/moby/buildkit/solver/jobs.go

@@ -177,7 +177,7 @@ func (sb *subBuilder) Context(ctx context.Context) context.Context {
 
 
 func (sb *subBuilder) EachValue(ctx context.Context, key string, fn func(interface{}) error) error {
 func (sb *subBuilder) EachValue(ctx context.Context, key string, fn func(interface{}) error) error {
 	sb.mu.Lock()
 	sb.mu.Lock()
-	defer sb.mu.Lock()
+	defer sb.mu.Unlock()
 	for j := range sb.jobs {
 	for j := range sb.jobs {
 		if err := j.EachValue(ctx, key, fn); err != nil {
 		if err := j.EachValue(ctx, key, fn); err != nil {
 			return err
 			return err

+ 34 - 27
vendor/github.com/moby/buildkit/solver/llbsolver/bridge.go

@@ -6,30 +6,34 @@ import (
 	"io"
 	"io"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
+	"time"
 
 
 	"github.com/containerd/containerd/platforms"
 	"github.com/containerd/containerd/platforms"
-	"github.com/docker/distribution/reference"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/cache/remotecache"
 	"github.com/moby/buildkit/cache/remotecache"
 	"github.com/moby/buildkit/executor"
 	"github.com/moby/buildkit/executor"
 	"github.com/moby/buildkit/frontend"
 	"github.com/moby/buildkit/frontend"
 	gw "github.com/moby/buildkit/frontend/gateway/client"
 	gw "github.com/moby/buildkit/frontend/gateway/client"
+	"github.com/moby/buildkit/identity"
+	"github.com/moby/buildkit/session"
 	"github.com/moby/buildkit/solver"
 	"github.com/moby/buildkit/solver"
 	"github.com/moby/buildkit/util/tracing"
 	"github.com/moby/buildkit/util/tracing"
 	"github.com/moby/buildkit/worker"
 	"github.com/moby/buildkit/worker"
 	digest "github.com/opencontainers/go-digest"
 	digest "github.com/opencontainers/go-digest"
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
+	"github.com/sirupsen/logrus"
 )
 )
 
 
 type llbBridge struct {
 type llbBridge struct {
-	builder              solver.Builder
-	frontends            map[string]frontend.Frontend
-	resolveWorker        func() (worker.Worker, error)
-	resolveCacheImporter remotecache.ResolveCacheImporterFunc
-	cms                  map[string]solver.CacheManager
-	cmsMu                sync.Mutex
-	platforms            []specs.Platform
+	builder                   solver.Builder
+	frontends                 map[string]frontend.Frontend
+	resolveWorker             func() (worker.Worker, error)
+	resolveCacheImporterFuncs map[string]remotecache.ResolveCacheImporterFunc
+	cms                       map[string]solver.CacheManager
+	cmsMu                     sync.Mutex
+	platforms                 []specs.Platform
+	sm                        *session.Manager
 }
 }
 
 
 func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (res *frontend.Result, err error) {
 func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (res *frontend.Result, err error) {
@@ -38,36 +42,39 @@ func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (res *
 		return nil, err
 		return nil, err
 	}
 	}
 	var cms []solver.CacheManager
 	var cms []solver.CacheManager
-	for _, ref := range req.ImportCacheRefs {
+	for _, im := range req.CacheImports {
 		b.cmsMu.Lock()
 		b.cmsMu.Lock()
 		var cm solver.CacheManager
 		var cm solver.CacheManager
-		if prevCm, ok := b.cms[ref]; !ok {
-			r, err := reference.ParseNormalizedNamed(ref)
-			if err != nil {
-				return nil, err
+		cmId := identity.NewID()
+		if im.Type == "registry" {
+			// For compatibility with < v0.4.0
+			if ref := im.Attrs["ref"]; ref != "" {
+				cmId = ref
 			}
 			}
-			ref = reference.TagNameOnly(r).String()
-			func(ref string) {
-				cm = newLazyCacheManager(ref, func() (solver.CacheManager, error) {
+		}
+		if prevCm, ok := b.cms[cmId]; !ok {
+			func(cmId string) {
+				cm = newLazyCacheManager(cmId, func() (solver.CacheManager, error) {
 					var cmNew solver.CacheManager
 					var cmNew solver.CacheManager
-					if err := inVertexContext(b.builder.Context(ctx), "importing cache manifest from "+ref, "", func(ctx context.Context) error {
-						if b.resolveCacheImporter == nil {
-							return errors.New("no cache importer is available")
+					if err := inVertexContext(b.builder.Context(ctx), "importing cache manifest from "+cmId, "", func(ctx context.Context) error {
+						resolveCI, ok := b.resolveCacheImporterFuncs[im.Type]
+						if !ok {
+							return errors.Errorf("unknown cache importer: %s", im.Type)
 						}
 						}
-						typ := "" // TODO: support non-registry type
-						ci, desc, err := b.resolveCacheImporter(ctx, typ, ref)
+						ci, desc, err := resolveCI(ctx, im.Attrs)
 						if err != nil {
 						if err != nil {
 							return err
 							return err
 						}
 						}
-						cmNew, err = ci.Resolve(ctx, desc, ref, w)
+						cmNew, err = ci.Resolve(ctx, desc, cmId, w)
 						return err
 						return err
 					}); err != nil {
 					}); err != nil {
+						logrus.Debugf("error while importing cache manifest from cmId=%s: %v", cmId, err)
 						return nil, err
 						return nil, err
 					}
 					}
 					return cmNew, nil
 					return cmNew, nil
 				})
 				})
-			}(ref)
-			b.cms[ref] = cm
+			}(cmId)
+			b.cms[cmId] = cm
 		} else {
 		} else {
 			cm = prevCm
 			cm = prevCm
 		}
 		}
@@ -151,7 +158,7 @@ func (s *llbBridge) ResolveImageConfig(ctx context.Context, ref string, opt gw.R
 		id += platforms.Format(*platform)
 		id += platforms.Format(*platform)
 	}
 	}
 	err = inVertexContext(s.builder.Context(ctx), opt.LogName, id, func(ctx context.Context) error {
 	err = inVertexContext(s.builder.Context(ctx), opt.LogName, id, func(ctx context.Context) error {
-		dgst, config, err = w.ResolveImageConfig(ctx, ref, opt)
+		dgst, config, err = w.ResolveImageConfig(ctx, ref, opt, s.sm)
 		return err
 		return err
 	})
 	})
 	return dgst, config, err
 	return dgst, config, err
@@ -186,11 +193,11 @@ func (lcm *lazyCacheManager) Load(ctx context.Context, rec *solver.CacheRecord)
 	}
 	}
 	return lcm.main.Load(ctx, rec)
 	return lcm.main.Load(ctx, rec)
 }
 }
-func (lcm *lazyCacheManager) Save(key *solver.CacheKey, s solver.Result) (*solver.ExportableCacheKey, error) {
+func (lcm *lazyCacheManager) Save(key *solver.CacheKey, s solver.Result, createdAt time.Time) (*solver.ExportableCacheKey, error) {
 	if err := lcm.wait(); err != nil {
 	if err := lcm.wait(); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	return lcm.main.Save(key, s)
+	return lcm.main.Save(key, s, createdAt)
 }
 }
 
 
 func (lcm *lazyCacheManager) wait() error {
 func (lcm *lazyCacheManager) wait() error {

+ 25 - 11
vendor/github.com/moby/buildkit/solver/llbsolver/ops/exec.go

@@ -10,13 +10,13 @@ import (
 	"os"
 	"os"
 	"path"
 	"path"
 	"path/filepath"
 	"path/filepath"
-	"runtime"
 	"sort"
 	"sort"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
 	"time"
 	"time"
 
 
 	"github.com/containerd/containerd/mount"
 	"github.com/containerd/containerd/mount"
+	"github.com/containerd/containerd/platforms"
 	"github.com/docker/docker/pkg/locker"
 	"github.com/docker/docker/pkg/locker"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/cache/metadata"
 	"github.com/moby/buildkit/cache/metadata"
@@ -34,6 +34,7 @@ import (
 	utilsystem "github.com/moby/buildkit/util/system"
 	utilsystem "github.com/moby/buildkit/util/system"
 	"github.com/moby/buildkit/worker"
 	"github.com/moby/buildkit/worker"
 	digest "github.com/opencontainers/go-digest"
 	digest "github.com/opencontainers/go-digest"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/opencontainers/runc/libcontainer/system"
 	"github.com/opencontainers/runc/libcontainer/system"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
@@ -51,12 +52,13 @@ type execOp struct {
 	md        *metadata.Store
 	md        *metadata.Store
 	exec      executor.Executor
 	exec      executor.Executor
 	w         worker.Worker
 	w         worker.Worker
+	platform  *pb.Platform
 	numInputs int
 	numInputs int
 
 
 	cacheMounts map[string]*cacheRefShare
 	cacheMounts map[string]*cacheRefShare
 }
 }
 
 
-func NewExecOp(v solver.Vertex, op *pb.Op_Exec, cm cache.Manager, sm *session.Manager, md *metadata.Store, exec executor.Executor, w worker.Worker) (solver.Op, error) {
+func NewExecOp(v solver.Vertex, op *pb.Op_Exec, platform *pb.Platform, cm cache.Manager, sm *session.Manager, md *metadata.Store, exec executor.Executor, w worker.Worker) (solver.Op, error) {
 	return &execOp{
 	return &execOp{
 		op:          op.Exec,
 		op:          op.Exec,
 		cm:          cm,
 		cm:          cm,
@@ -65,6 +67,7 @@ func NewExecOp(v solver.Vertex, op *pb.Op_Exec, cm cache.Manager, sm *session.Ma
 		exec:        exec,
 		exec:        exec,
 		numInputs:   len(v.Inputs()),
 		numInputs:   len(v.Inputs()),
 		w:           w,
 		w:           w,
+		platform:    platform,
 		cacheMounts: map[string]*cacheRefShare{},
 		cacheMounts: map[string]*cacheRefShare{},
 	}, nil
 	}, nil
 }
 }
@@ -98,16 +101,27 @@ func (e *execOp) CacheMap(ctx context.Context, index int) (*solver.CacheMap, boo
 	}
 	}
 	op.Meta.ProxyEnv = nil
 	op.Meta.ProxyEnv = nil
 
 
+	p := platforms.DefaultSpec()
+	if e.platform != nil {
+		p = specs.Platform{
+			OS:           e.platform.OS,
+			Architecture: e.platform.Architecture,
+			Variant:      e.platform.Variant,
+		}
+	}
+
 	dt, err := json.Marshal(struct {
 	dt, err := json.Marshal(struct {
-		Type string
-		Exec *pb.ExecOp
-		OS   string
-		Arch string
+		Type    string
+		Exec    *pb.ExecOp
+		OS      string
+		Arch    string
+		Variant string `json:",omitempty"`
 	}{
 	}{
-		Type: execCacheType,
-		Exec: &op,
-		OS:   runtime.GOOS,
-		Arch: runtime.GOARCH,
+		Type:    execCacheType,
+		Exec:    &op,
+		OS:      p.OS,
+		Arch:    p.Architecture,
+		Variant: p.Variant,
 	})
 	})
 	if err != nil {
 	if err != nil {
 		return nil, false, err
 		return nil, false, err
@@ -151,7 +165,7 @@ func dedupePaths(inp []string) []string {
 	for p1 := range old {
 	for p1 := range old {
 		var skip bool
 		var skip bool
 		for p2 := range old {
 		for p2 := range old {
-			if p1 != p2 && strings.HasPrefix(p1, p2) {
+			if p1 != p2 && strings.HasPrefix(p1, p2+"/") {
 				skip = true
 				skip = true
 				break
 				break
 			}
 			}

+ 13 - 3
vendor/github.com/moby/buildkit/solver/llbsolver/ops/source.go

@@ -2,8 +2,10 @@ package ops
 
 
 import (
 import (
 	"context"
 	"context"
+	"strings"
 	"sync"
 	"sync"
 
 
+	"github.com/moby/buildkit/session"
 	"github.com/moby/buildkit/solver"
 	"github.com/moby/buildkit/solver"
 	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/source"
 	"github.com/moby/buildkit/source"
@@ -19,14 +21,16 @@ type sourceOp struct {
 	platform *pb.Platform
 	platform *pb.Platform
 	sm       *source.Manager
 	sm       *source.Manager
 	src      source.SourceInstance
 	src      source.SourceInstance
+	sessM    *session.Manager
 	w        worker.Worker
 	w        worker.Worker
 }
 }
 
 
-func NewSourceOp(_ solver.Vertex, op *pb.Op_Source, platform *pb.Platform, sm *source.Manager, w worker.Worker) (solver.Op, error) {
+func NewSourceOp(_ solver.Vertex, op *pb.Op_Source, platform *pb.Platform, sm *source.Manager, sessM *session.Manager, w worker.Worker) (solver.Op, error) {
 	return &sourceOp{
 	return &sourceOp{
 		op:       op,
 		op:       op,
 		sm:       sm,
 		sm:       sm,
 		w:        w,
 		w:        w,
+		sessM:    sessM,
 		platform: platform,
 		platform: platform,
 	}, nil
 	}, nil
 }
 }
@@ -41,7 +45,7 @@ func (s *sourceOp) instance(ctx context.Context) (source.SourceInstance, error)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	src, err := s.sm.Resolve(ctx, id)
+	src, err := s.sm.Resolve(ctx, id, s.sessM)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -59,9 +63,15 @@ func (s *sourceOp) CacheMap(ctx context.Context, index int) (*solver.CacheMap, b
 		return nil, false, err
 		return nil, false, err
 	}
 	}
 
 
+	dgst := digest.FromBytes([]byte(sourceCacheType + ":" + k))
+
+	if strings.HasPrefix(k, "session:") {
+		dgst = digest.Digest("random:" + strings.TrimPrefix(dgst.String(), dgst.Algorithm().String()+":"))
+	}
+
 	return &solver.CacheMap{
 	return &solver.CacheMap{
 		// TODO: add os/arch
 		// TODO: add os/arch
-		Digest: digest.FromBytes([]byte(sourceCacheType + ":" + k)),
+		Digest: dgst,
 	}, done, nil
 	}, done, nil
 }
 }
 
 

+ 1 - 1
vendor/github.com/moby/buildkit/solver/llbsolver/result.go

@@ -32,7 +32,7 @@ func NewContentHashFunc(selectors []string) solver.ResultBasedCacheFunc {
 			// FIXME(tonistiigi): enabling this parallelization seems to create wrong results for some big inputs(like gobuild)
 			// FIXME(tonistiigi): enabling this parallelization seems to create wrong results for some big inputs(like gobuild)
 			// func(i int) {
 			// func(i int) {
 			// 	eg.Go(func() error {
 			// 	eg.Go(func() error {
-			dgst, err := contenthash.Checksum(ctx, ref.ImmutableRef, path.Join("/", sel))
+			dgst, err := contenthash.Checksum(ctx, ref.ImmutableRef, path.Join("/", sel), true)
 			if err != nil {
 			if err != nil {
 				return "", err
 				return "", err
 			}
 			}

+ 83 - 24
vendor/github.com/moby/buildkit/solver/llbsolver/solver.go

@@ -2,6 +2,7 @@ package llbsolver
 
 
 import (
 import (
 	"context"
 	"context"
+	"fmt"
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
@@ -10,6 +11,7 @@ import (
 	"github.com/moby/buildkit/client"
 	"github.com/moby/buildkit/client"
 	controlgateway "github.com/moby/buildkit/control/gateway"
 	controlgateway "github.com/moby/buildkit/control/gateway"
 	"github.com/moby/buildkit/exporter"
 	"github.com/moby/buildkit/exporter"
+	"github.com/moby/buildkit/exporter/containerimage/exptypes"
 	"github.com/moby/buildkit/frontend"
 	"github.com/moby/buildkit/frontend"
 	"github.com/moby/buildkit/frontend/gateway"
 	"github.com/moby/buildkit/frontend/gateway"
 	"github.com/moby/buildkit/identity"
 	"github.com/moby/buildkit/identity"
@@ -35,22 +37,24 @@ type ExporterRequest struct {
 type ResolveWorkerFunc func() (worker.Worker, error)
 type ResolveWorkerFunc func() (worker.Worker, error)
 
 
 type Solver struct {
 type Solver struct {
-	workerController     *worker.Controller
-	solver               *solver.Solver
-	resolveWorker        ResolveWorkerFunc
-	frontends            map[string]frontend.Frontend
-	resolveCacheImporter remotecache.ResolveCacheImporterFunc
-	platforms            []specs.Platform
-	gatewayForwarder     *controlgateway.GatewayForwarder
+	workerController          *worker.Controller
+	solver                    *solver.Solver
+	resolveWorker             ResolveWorkerFunc
+	frontends                 map[string]frontend.Frontend
+	resolveCacheImporterFuncs map[string]remotecache.ResolveCacheImporterFunc
+	platforms                 []specs.Platform
+	gatewayForwarder          *controlgateway.GatewayForwarder
+	sm                        *session.Manager
 }
 }
 
 
-func New(wc *worker.Controller, f map[string]frontend.Frontend, cache solver.CacheManager, resolveCI remotecache.ResolveCacheImporterFunc, gatewayForwarder *controlgateway.GatewayForwarder) (*Solver, error) {
+func New(wc *worker.Controller, f map[string]frontend.Frontend, cache solver.CacheManager, resolveCI map[string]remotecache.ResolveCacheImporterFunc, gatewayForwarder *controlgateway.GatewayForwarder, sm *session.Manager) (*Solver, error) {
 	s := &Solver{
 	s := &Solver{
-		workerController:     wc,
-		resolveWorker:        defaultResolver(wc),
-		frontends:            f,
-		resolveCacheImporter: resolveCI,
-		gatewayForwarder:     gatewayForwarder,
+		workerController:          wc,
+		resolveWorker:             defaultResolver(wc),
+		frontends:                 f,
+		resolveCacheImporterFuncs: resolveCI,
+		gatewayForwarder:          gatewayForwarder,
+		sm:                        sm,
 	}
 	}
 
 
 	// executing is currently only allowed on default worker
 	// executing is currently only allowed on default worker
@@ -73,18 +77,19 @@ func (s *Solver) resolver() solver.ResolveOpFunc {
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		return w.ResolveOp(v, s.Bridge(b))
+		return w.ResolveOp(v, s.Bridge(b), s.sm)
 	}
 	}
 }
 }
 
 
 func (s *Solver) Bridge(b solver.Builder) frontend.FrontendLLBBridge {
 func (s *Solver) Bridge(b solver.Builder) frontend.FrontendLLBBridge {
 	return &llbBridge{
 	return &llbBridge{
-		builder:              b,
-		frontends:            s.frontends,
-		resolveWorker:        s.resolveWorker,
-		resolveCacheImporter: s.resolveCacheImporter,
-		cms:                  map[string]solver.CacheManager{},
-		platforms:            s.platforms,
+		builder:                   b,
+		frontends:                 s.frontends,
+		resolveWorker:             s.resolveWorker,
+		resolveCacheImporterFuncs: s.resolveCacheImporterFuncs,
+		cms:                       map[string]solver.CacheManager{},
+		platforms:                 s.platforms,
+		sm:                        s.sm,
 	}
 	}
 }
 }
 
 
@@ -138,7 +143,7 @@ func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest
 	}()
 	}()
 
 
 	var exporterResponse map[string]string
 	var exporterResponse map[string]string
-	if exp := exp.Exporter; exp != nil {
+	if e := exp.Exporter; e != nil {
 		inp := exporter.Source{
 		inp := exporter.Source{
 			Metadata: res.Metadata,
 			Metadata: res.Metadata,
 		}
 		}
@@ -151,6 +156,14 @@ func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest
 				return nil, errors.Errorf("invalid reference: %T", res.Sys())
 				return nil, errors.Errorf("invalid reference: %T", res.Sys())
 			}
 			}
 			inp.Ref = workerRef.ImmutableRef
 			inp.Ref = workerRef.ImmutableRef
+
+			dt, err := inlineCache(ctx, exp.CacheExporter, res)
+			if err != nil {
+				return nil, err
+			}
+			if dt != nil {
+				inp.Metadata[exptypes.ExporterInlineCache] = dt
+			}
 		}
 		}
 		if res.Refs != nil {
 		if res.Refs != nil {
 			m := make(map[string]cache.ImmutableRef, len(res.Refs))
 			m := make(map[string]cache.ImmutableRef, len(res.Refs))
@@ -163,19 +176,28 @@ func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest
 						return nil, errors.Errorf("invalid reference: %T", res.Sys())
 						return nil, errors.Errorf("invalid reference: %T", res.Sys())
 					}
 					}
 					m[k] = workerRef.ImmutableRef
 					m[k] = workerRef.ImmutableRef
+
+					dt, err := inlineCache(ctx, exp.CacheExporter, res)
+					if err != nil {
+						return nil, err
+					}
+					if dt != nil {
+						inp.Metadata[fmt.Sprintf("%s/%s", exptypes.ExporterInlineCache, k)] = dt
+					}
 				}
 				}
 			}
 			}
 			inp.Refs = m
 			inp.Refs = m
 		}
 		}
 
 
-		if err := inVertexContext(j.Context(ctx), exp.Name(), "", func(ctx context.Context) error {
-			exporterResponse, err = exp.Export(ctx, inp)
+		if err := inVertexContext(j.Context(ctx), e.Name(), "", func(ctx context.Context) error {
+			exporterResponse, err = e.Export(ctx, inp)
 			return err
 			return err
 		}); err != nil {
 		}); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
 	}
 	}
 
 
+	var cacheExporterResponse map[string]string
 	if e := exp.CacheExporter; e != nil {
 	if e := exp.CacheExporter; e != nil {
 		if err := inVertexContext(j.Context(ctx), "exporting cache", "", func(ctx context.Context) error {
 		if err := inVertexContext(j.Context(ctx), "exporting cache", "", func(ctx context.Context) error {
 			prepareDone := oneOffProgress(ctx, "preparing build cache for export")
 			prepareDone := oneOffProgress(ctx, "preparing build cache for export")
@@ -190,7 +212,8 @@ func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest
 				return prepareDone(err)
 				return prepareDone(err)
 			}
 			}
 			prepareDone(nil)
 			prepareDone(nil)
-			return e.Finalize(ctx)
+			cacheExporterResponse, err = e.Finalize(ctx)
+			return err
 		}); err != nil {
 		}); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
@@ -205,12 +228,48 @@ func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest
 			exporterResponse[k] = string(v)
 			exporterResponse[k] = string(v)
 		}
 		}
 	}
 	}
+	for k, v := range cacheExporterResponse {
+		if strings.HasPrefix(k, "cache.") {
+			exporterResponse[k] = v
+		}
+	}
 
 
 	return &client.SolveResponse{
 	return &client.SolveResponse{
 		ExporterResponse: exporterResponse,
 		ExporterResponse: exporterResponse,
 	}, nil
 	}, nil
 }
 }
 
 
+func inlineCache(ctx context.Context, e remotecache.Exporter, res solver.CachedResult) ([]byte, error) {
+	if efl, ok := e.(interface {
+		ExportForLayers([]digest.Digest) ([]byte, error)
+	}); ok {
+		workerRef, ok := res.Sys().(*worker.WorkerRef)
+		if !ok {
+			return nil, errors.Errorf("invalid reference: %T", res.Sys())
+		}
+
+		remote, err := workerRef.Worker.GetRemote(ctx, workerRef.ImmutableRef, true)
+		if err != nil || remote == nil {
+			return nil, nil
+		}
+
+		digests := make([]digest.Digest, 0, len(remote.Descriptors))
+		for _, desc := range remote.Descriptors {
+			digests = append(digests, desc.Digest)
+		}
+
+		if _, err := res.CacheKeys()[0].Exporter.ExportTo(ctx, e, solver.CacheExportOpt{
+			Convert: workerRefConverter,
+			Mode:    solver.CacheExportModeMin,
+		}); err != nil {
+			return nil, err
+		}
+
+		return efl.ExportForLayers(digests)
+	}
+	return nil, nil
+}
+
 func (s *Solver) Status(ctx context.Context, id string, statusChan chan *client.SolveStatus) error {
 func (s *Solver) Status(ctx context.Context, id string, statusChan chan *client.SolveStatus) error {
 	j, err := s.solver.Get(id)
 	j, err := s.solver.Get(id)
 	if err != nil {
 	if err != nil {

+ 15 - 1
vendor/github.com/moby/buildkit/solver/llbsolver/vertex.go

@@ -80,10 +80,20 @@ func RuntimePlatforms(p []specs.Platform) LoadOpt {
 				defaultPlatform = &pb.Platform{
 				defaultPlatform = &pb.Platform{
 					OS:           p.OS,
 					OS:           p.OS,
 					Architecture: p.Architecture,
 					Architecture: p.Architecture,
+					Variant:      p.Variant,
 				}
 				}
 			}
 			}
 			op.Platform = defaultPlatform
 			op.Platform = defaultPlatform
 		}
 		}
+		platform := specs.Platform{OS: op.Platform.OS, Architecture: op.Platform.Architecture, Variant: op.Platform.Variant}
+		normalizedPlatform := platforms.Normalize(platform)
+
+		op.Platform = &pb.Platform{
+			OS:           normalizedPlatform.OS,
+			Architecture: normalizedPlatform.Architecture,
+			Variant:      normalizedPlatform.Variant,
+		}
+
 		if _, ok := op.Op.(*pb.Op_Exec); ok {
 		if _, ok := op.Op.(*pb.Op_Exec); ok {
 			var found bool
 			var found bool
 			for _, pp := range pp {
 			for _, pp := range pp {
@@ -186,7 +196,11 @@ func loadLLB(def *pb.Definition, fn func(digest.Digest, *pb.Op, func(digest.Dige
 		if v, ok := cache[dgst]; ok {
 		if v, ok := cache[dgst]; ok {
 			return v, nil
 			return v, nil
 		}
 		}
-		v, err := fn(dgst, allOps[dgst], rec)
+		op, ok := allOps[dgst]
+		if !ok {
+			return nil, errors.Errorf("invalid missing input digest %s", dgst)
+		}
+		v, err := fn(dgst, op, rec)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}

+ 2 - 2
vendor/github.com/moby/buildkit/solver/memorycachestorage.go

@@ -284,9 +284,9 @@ type inMemoryResultStore struct {
 	m *sync.Map
 	m *sync.Map
 }
 }
 
 
-func (s *inMemoryResultStore) Save(r Result) (CacheResult, error) {
+func (s *inMemoryResultStore) Save(r Result, createdAt time.Time) (CacheResult, error) {
 	s.m.Store(r.ID(), r)
 	s.m.Store(r.ID(), r)
-	return CacheResult{ID: r.ID(), CreatedAt: time.Now()}, nil
+	return CacheResult{ID: r.ID(), CreatedAt: createdAt}, nil
 }
 }
 
 
 func (s *inMemoryResultStore) Load(ctx context.Context, res CacheResult) (Result, error) {
 func (s *inMemoryResultStore) Load(ctx context.Context, res CacheResult) (Result, error) {

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 610 - 144
vendor/github.com/moby/buildkit/solver/pb/ops.pb.go


+ 1 - 1
vendor/github.com/moby/buildkit/solver/types.go

@@ -164,5 +164,5 @@ type CacheManager interface {
 	// Load pulls and returns the cached result
 	// Load pulls and returns the cached result
 	Load(ctx context.Context, rec *CacheRecord) (Result, error)
 	Load(ctx context.Context, rec *CacheRecord) (Result, error)
 	// Save saves a result based on a cache key
 	// Save saves a result based on a cache key
-	Save(key *CacheKey, s Result) (*ExportableCacheKey, error)
+	Save(key *CacheKey, s Result, createdAt time.Time) (*ExportableCacheKey, error)
 }
 }

+ 5 - 1
vendor/github.com/moby/buildkit/source/git/gitsource.go

@@ -16,6 +16,7 @@ import (
 	"github.com/moby/buildkit/cache/metadata"
 	"github.com/moby/buildkit/cache/metadata"
 	"github.com/moby/buildkit/client"
 	"github.com/moby/buildkit/client"
 	"github.com/moby/buildkit/identity"
 	"github.com/moby/buildkit/identity"
+	"github.com/moby/buildkit/session"
 	"github.com/moby/buildkit/snapshot"
 	"github.com/moby/buildkit/snapshot"
 	"github.com/moby/buildkit/source"
 	"github.com/moby/buildkit/source"
 	"github.com/moby/buildkit/util/progress/logs"
 	"github.com/moby/buildkit/util/progress/logs"
@@ -152,7 +153,7 @@ type gitSourceHandler struct {
 	cacheKey string
 	cacheKey string
 }
 }
 
 
-func (gs *gitSource) Resolve(ctx context.Context, id source.Identifier) (source.SourceInstance, error) {
+func (gs *gitSource) Resolve(ctx context.Context, id source.Identifier, _ *session.Manager) (source.SourceInstance, error) {
 	gitIdentifier, ok := id.(*source.GitIdentifier)
 	gitIdentifier, ok := id.(*source.GitIdentifier)
 	if !ok {
 	if !ok {
 		return nil, errors.Errorf("invalid git identifier %v", id)
 		return nil, errors.Errorf("invalid git identifier %v", id)
@@ -248,6 +249,9 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context) (out cache.ImmutableRe
 	}
 	}
 
 
 	if doFetch {
 	if doFetch {
+		// make sure no old lock files have leaked
+		os.RemoveAll(filepath.Join(gitDir, "shallow.lock"))
+
 		args := []string{"fetch"}
 		args := []string{"fetch"}
 		if !isCommitSHA(ref) { // TODO: find a branch from ls-remote?
 		if !isCommitSHA(ref) { // TODO: find a branch from ls-remote?
 			args = append(args, "--depth=1", "--no-tags")
 			args = append(args, "--depth=1", "--no-tags")

+ 9 - 1
vendor/github.com/moby/buildkit/source/git/gitsource_unix.go

@@ -6,6 +6,7 @@ import (
 	"context"
 	"context"
 	"os/exec"
 	"os/exec"
 	"syscall"
 	"syscall"
+	"time"
 )
 )
 
 
 func runProcessGroup(ctx context.Context, cmd *exec.Cmd) error {
 func runProcessGroup(ctx context.Context, cmd *exec.Cmd) error {
@@ -17,7 +18,14 @@ func runProcessGroup(ctx context.Context, cmd *exec.Cmd) error {
 	go func() {
 	go func() {
 		select {
 		select {
 		case <-ctx.Done():
 		case <-ctx.Done():
-			syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
+			syscall.Kill(-cmd.Process.Pid, syscall.SIGTERM)
+			go func() {
+				select {
+				case <-waitDone:
+				case <-time.After(10 * time.Second):
+					syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
+				}
+			}()
 		case <-waitDone:
 		case <-waitDone:
 		}
 		}
 	}()
 	}()

+ 34 - 2
vendor/github.com/moby/buildkit/source/http/httpsource.go

@@ -18,6 +18,7 @@ import (
 	"github.com/docker/docker/pkg/locker"
 	"github.com/docker/docker/pkg/locker"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/cache/metadata"
 	"github.com/moby/buildkit/cache/metadata"
+	"github.com/moby/buildkit/session"
 	"github.com/moby/buildkit/snapshot"
 	"github.com/moby/buildkit/snapshot"
 	"github.com/moby/buildkit/source"
 	"github.com/moby/buildkit/source"
 	"github.com/moby/buildkit/util/tracing"
 	"github.com/moby/buildkit/util/tracing"
@@ -66,7 +67,7 @@ type httpSourceHandler struct {
 	cacheKey digest.Digest
 	cacheKey digest.Digest
 }
 }
 
 
-func (hs *httpSource) Resolve(ctx context.Context, id source.Identifier) (source.SourceInstance, error) {
+func (hs *httpSource) Resolve(ctx context.Context, id source.Identifier, _ *session.Manager) (source.SourceInstance, error) {
 	httpIdentifier, ok := id.(*source.HttpIdentifier)
 	httpIdentifier, ok := id.(*source.HttpIdentifier)
 	if !ok {
 	if !ok {
 		return nil, errors.Errorf("invalid http identifier %v", id)
 		return nil, errors.Errorf("invalid http identifier %v", id)
@@ -146,11 +147,42 @@ func (hs *httpSourceHandler) CacheKey(ctx context.Context, index int) (string, b
 			if etag := getETag(si); etag != "" {
 			if etag := getETag(si); etag != "" {
 				if dgst := getChecksum(si); dgst != "" {
 				if dgst := getChecksum(si); dgst != "" {
 					m[etag] = si
 					m[etag] = si
-					req.Header.Add("If-None-Match", etag)
 				}
 				}
 			}
 			}
 			// }
 			// }
 		}
 		}
+		if len(m) > 0 {
+			etags := make([]string, 0, len(m))
+			for t := range m {
+				etags = append(etags, t)
+			}
+			req.Header.Add("If-None-Match", strings.Join(etags, ", "))
+		}
+	}
+
+	// Some servers seem to have trouble supporting If-None-Match properly even
+	// though they return ETag-s. So first, optionally try a HEAD request with
+	// manual ETag value comparison.
+	if len(m) > 0 {
+		req.Method = "HEAD"
+		resp, err := hs.client.Do(req)
+		if err == nil {
+			if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNotModified {
+				respETag := resp.Header.Get("ETag")
+				si, ok := m[respETag]
+				if ok {
+					hs.refID = si.ID()
+					dgst := getChecksum(si)
+					if dgst != "" {
+						modTime := getModTime(si)
+						resp.Body.Close()
+						return hs.formatCacheKey(getFileName(hs.src.URL, hs.src.Filename, resp), dgst, modTime).String(), true, nil
+					}
+				}
+			}
+			resp.Body.Close()
+		}
+		req.Method = "GET"
 	}
 	}
 
 
 	resp, err := hs.client.Do(req)
 	resp, err := hs.client.Do(req)

+ 5 - 6
vendor/github.com/moby/buildkit/source/local/local.go

@@ -28,14 +28,12 @@ import (
 const keySharedKey = "local.sharedKey"
 const keySharedKey = "local.sharedKey"
 
 
 type Opt struct {
 type Opt struct {
-	SessionManager *session.Manager
-	CacheAccessor  cache.Accessor
-	MetadataStore  *metadata.Store
+	CacheAccessor cache.Accessor
+	MetadataStore *metadata.Store
 }
 }
 
 
 func NewSource(opt Opt) (source.Source, error) {
 func NewSource(opt Opt) (source.Source, error) {
 	ls := &localSource{
 	ls := &localSource{
-		sm: opt.SessionManager,
 		cm: opt.CacheAccessor,
 		cm: opt.CacheAccessor,
 		md: opt.MetadataStore,
 		md: opt.MetadataStore,
 	}
 	}
@@ -43,7 +41,6 @@ func NewSource(opt Opt) (source.Source, error) {
 }
 }
 
 
 type localSource struct {
 type localSource struct {
-	sm *session.Manager
 	cm cache.Accessor
 	cm cache.Accessor
 	md *metadata.Store
 	md *metadata.Store
 }
 }
@@ -52,7 +49,7 @@ func (ls *localSource) ID() string {
 	return source.LocalScheme
 	return source.LocalScheme
 }
 }
 
 
-func (ls *localSource) Resolve(ctx context.Context, id source.Identifier) (source.SourceInstance, error) {
+func (ls *localSource) Resolve(ctx context.Context, id source.Identifier, sm *session.Manager) (source.SourceInstance, error) {
 	localIdentifier, ok := id.(*source.LocalIdentifier)
 	localIdentifier, ok := id.(*source.LocalIdentifier)
 	if !ok {
 	if !ok {
 		return nil, errors.Errorf("invalid local identifier %v", id)
 		return nil, errors.Errorf("invalid local identifier %v", id)
@@ -60,12 +57,14 @@ func (ls *localSource) Resolve(ctx context.Context, id source.Identifier) (sourc
 
 
 	return &localSourceHandler{
 	return &localSourceHandler{
 		src:         *localIdentifier,
 		src:         *localIdentifier,
+		sm:          sm,
 		localSource: ls,
 		localSource: ls,
 	}, nil
 	}, nil
 }
 }
 
 
 type localSourceHandler struct {
 type localSourceHandler struct {
 	src source.LocalIdentifier
 	src source.LocalIdentifier
+	sm  *session.Manager
 	*localSource
 	*localSource
 }
 }
 
 

+ 4 - 3
vendor/github.com/moby/buildkit/source/manager.go

@@ -5,12 +5,13 @@ import (
 	"sync"
 	"sync"
 
 
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/cache"
+	"github.com/moby/buildkit/session"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 )
 )
 
 
 type Source interface {
 type Source interface {
 	ID() string
 	ID() string
-	Resolve(ctx context.Context, id Identifier) (SourceInstance, error)
+	Resolve(ctx context.Context, id Identifier, sm *session.Manager) (SourceInstance, error)
 }
 }
 
 
 type SourceInstance interface {
 type SourceInstance interface {
@@ -35,7 +36,7 @@ func (sm *Manager) Register(src Source) {
 	sm.mu.Unlock()
 	sm.mu.Unlock()
 }
 }
 
 
-func (sm *Manager) Resolve(ctx context.Context, id Identifier) (SourceInstance, error) {
+func (sm *Manager) Resolve(ctx context.Context, id Identifier, sessM *session.Manager) (SourceInstance, error) {
 	sm.mu.Lock()
 	sm.mu.Lock()
 	src, ok := sm.sources[id.ID()]
 	src, ok := sm.sources[id.ID()]
 	sm.mu.Unlock()
 	sm.mu.Unlock()
@@ -44,5 +45,5 @@ func (sm *Manager) Resolve(ctx context.Context, id Identifier) (SourceInstance,
 		return nil, errors.Errorf("no handler for %s", id.ID())
 		return nil, errors.Errorf("no handler for %s", id.ID())
 	}
 	}
 
 
-	return src.Resolve(ctx, id)
+	return src.Resolve(ctx, id, sessM)
 }
 }

+ 53 - 21
vendor/github.com/moby/buildkit/util/apicaps/pb/caps.pb.go

@@ -1,15 +1,6 @@
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // source: caps.proto
 // source: caps.proto
 
 
-/*
-	Package moby_buildkit_v1_apicaps is a generated protocol buffer package.
-
-	It is generated from these files:
-		caps.proto
-
-	It has these top-level messages:
-		APICap
-*/
 package moby_buildkit_v1_apicaps
 package moby_buildkit_v1_apicaps
 
 
 import proto "github.com/gogo/protobuf/proto"
 import proto "github.com/gogo/protobuf/proto"
@@ -32,18 +23,49 @@ const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
 
 
 // APICap defines a capability supported by the service
 // APICap defines a capability supported by the service
 type APICap struct {
 type APICap struct {
-	ID                  string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
-	Enabled             bool   `protobuf:"varint,2,opt,name=Enabled,proto3" json:"Enabled,omitempty"`
-	Deprecated          bool   `protobuf:"varint,3,opt,name=Deprecated,proto3" json:"Deprecated,omitempty"`
-	DisabledReason      string `protobuf:"bytes,4,opt,name=DisabledReason,proto3" json:"DisabledReason,omitempty"`
-	DisabledReasonMsg   string `protobuf:"bytes,5,opt,name=DisabledReasonMsg,proto3" json:"DisabledReasonMsg,omitempty"`
-	DisabledAlternative string `protobuf:"bytes,6,opt,name=DisabledAlternative,proto3" json:"DisabledAlternative,omitempty"`
+	ID                   string   `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
+	Enabled              bool     `protobuf:"varint,2,opt,name=Enabled,proto3" json:"Enabled,omitempty"`
+	Deprecated           bool     `protobuf:"varint,3,opt,name=Deprecated,proto3" json:"Deprecated,omitempty"`
+	DisabledReason       string   `protobuf:"bytes,4,opt,name=DisabledReason,proto3" json:"DisabledReason,omitempty"`
+	DisabledReasonMsg    string   `protobuf:"bytes,5,opt,name=DisabledReasonMsg,proto3" json:"DisabledReasonMsg,omitempty"`
+	DisabledAlternative  string   `protobuf:"bytes,6,opt,name=DisabledAlternative,proto3" json:"DisabledAlternative,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *APICap) Reset()         { *m = APICap{} }
+func (m *APICap) String() string { return proto.CompactTextString(m) }
+func (*APICap) ProtoMessage()    {}
+func (*APICap) Descriptor() ([]byte, []int) {
+	return fileDescriptor_caps_04e1bcd232e9a565, []int{0}
+}
+func (m *APICap) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *APICap) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_APICap.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (dst *APICap) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_APICap.Merge(dst, src)
+}
+func (m *APICap) XXX_Size() int {
+	return m.Size()
+}
+func (m *APICap) XXX_DiscardUnknown() {
+	xxx_messageInfo_APICap.DiscardUnknown(m)
 }
 }
 
 
-func (m *APICap) Reset()                    { *m = APICap{} }
-func (m *APICap) String() string            { return proto.CompactTextString(m) }
-func (*APICap) ProtoMessage()               {}
-func (*APICap) Descriptor() ([]byte, []int) { return fileDescriptorCaps, []int{0} }
+var xxx_messageInfo_APICap proto.InternalMessageInfo
 
 
 func (m *APICap) GetID() string {
 func (m *APICap) GetID() string {
 	if m != nil {
 	if m != nil {
@@ -149,6 +171,9 @@ func (m *APICap) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintCaps(dAtA, i, uint64(len(m.DisabledAlternative)))
 		i = encodeVarintCaps(dAtA, i, uint64(len(m.DisabledAlternative)))
 		i += copy(dAtA[i:], m.DisabledAlternative)
 		i += copy(dAtA[i:], m.DisabledAlternative)
 	}
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 	return i, nil
 }
 }
 
 
@@ -162,6 +187,9 @@ func encodeVarintCaps(dAtA []byte, offset int, v uint64) int {
 	return offset + 1
 	return offset + 1
 }
 }
 func (m *APICap) Size() (n int) {
 func (m *APICap) Size() (n int) {
+	if m == nil {
+		return 0
+	}
 	var l int
 	var l int
 	_ = l
 	_ = l
 	l = len(m.ID)
 	l = len(m.ID)
@@ -186,6 +214,9 @@ func (m *APICap) Size() (n int) {
 	if l > 0 {
 	if l > 0 {
 		n += 1 + l + sovCaps(uint64(l))
 		n += 1 + l + sovCaps(uint64(l))
 	}
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 	return n
 }
 }
 
 
@@ -399,6 +430,7 @@ func (m *APICap) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 				return io.ErrUnexpectedEOF
 			}
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 			iNdEx += skippy
 		}
 		}
 	}
 	}
@@ -513,9 +545,9 @@ var (
 	ErrIntOverflowCaps   = fmt.Errorf("proto: integer overflow")
 	ErrIntOverflowCaps   = fmt.Errorf("proto: integer overflow")
 )
 )
 
 
-func init() { proto.RegisterFile("caps.proto", fileDescriptorCaps) }
+func init() { proto.RegisterFile("caps.proto", fileDescriptor_caps_04e1bcd232e9a565) }
 
 
-var fileDescriptorCaps = []byte{
+var fileDescriptor_caps_04e1bcd232e9a565 = []byte{
 	// 236 bytes of a gzipped FileDescriptorProto
 	// 236 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4a, 0x4e, 0x2c, 0x28,
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4a, 0x4e, 0x2c, 0x28,
 	0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0xc8, 0xcd, 0x4f, 0xaa, 0xd4, 0x4b, 0x2a, 0xcd,
 	0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0xc8, 0xcd, 0x4f, 0xaa, 0xd4, 0x4b, 0x2a, 0xcd,

+ 1 - 1
vendor/github.com/moby/buildkit/util/contentutil/copy.go

@@ -67,7 +67,7 @@ func CopyChain(ctx context.Context, ingester content.Ingester, provider content.
 		remotes.FetchHandler(ingester, &localFetcher{provider}),
 		remotes.FetchHandler(ingester, &localFetcher{provider}),
 	}
 	}
 
 
-	if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil {
+	if err := images.Dispatch(ctx, images.Handlers(handlers...), nil, desc); err != nil {
 		return errors.WithStack(err)
 		return errors.WithStack(err)
 	}
 	}
 
 

+ 8 - 4
vendor/github.com/moby/buildkit/util/imageutil/config.go

@@ -66,7 +66,7 @@ func Config(ctx context.Context, str string, resolver remotes.Resolver, cache Co
 		remotes.FetchHandler(cache, fetcher),
 		remotes.FetchHandler(cache, fetcher),
 		childrenConfigHandler(cache, platform),
 		childrenConfigHandler(cache, platform),
 	}
 	}
-	if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil {
+	if err := images.Dispatch(ctx, images.Handlers(handlers...), nil, desc); err != nil {
 		return "", nil, err
 		return "", nil, err
 	}
 	}
 	config, err := images.Config(ctx, cache, desc, platform)
 	config, err := images.Config(ctx, cache, desc, platform)
@@ -135,17 +135,21 @@ func childrenConfigHandler(provider content.Provider, platform platforms.MatchCo
 func DetectManifestMediaType(ra content.ReaderAt) (string, error) {
 func DetectManifestMediaType(ra content.ReaderAt) (string, error) {
 	// TODO: schema1
 	// TODO: schema1
 
 
-	p := make([]byte, ra.Size())
-	if _, err := ra.ReadAt(p, 0); err != nil {
+	dt := make([]byte, ra.Size())
+	if _, err := ra.ReadAt(dt, 0); err != nil {
 		return "", err
 		return "", err
 	}
 	}
 
 
+	return DetectManifestBlobMediaType(dt)
+}
+
+func DetectManifestBlobMediaType(dt []byte) (string, error) {
 	var mfst struct {
 	var mfst struct {
 		MediaType string          `json:"mediaType"`
 		MediaType string          `json:"mediaType"`
 		Config    json.RawMessage `json:"config"`
 		Config    json.RawMessage `json:"config"`
 	}
 	}
 
 
-	if err := json.Unmarshal(p, &mfst); err != nil {
+	if err := json.Unmarshal(dt, &mfst); err != nil {
 		return "", err
 		return "", err
 	}
 	}
 
 

+ 0 - 69
vendor/github.com/moby/buildkit/vendor.conf

@@ -1,69 +0,0 @@
-github.com/pkg/errors v0.8.0
-go.etcd.io/bbolt v1.3.1-etcd.8
-
-github.com/stretchr/testify v1.1.4
-github.com/davecgh/go-spew v1.1.0
-github.com/pmezard/go-difflib v1.0.0
-golang.org/x/sys 1b2967e3c290b7c545b3db0deeda16e9be4f98a2
-
-github.com/containerd/containerd 47b328aab79146a9e81e37704db60e7e04a09256
-github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
-golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
-github.com/sirupsen/logrus v1.0.3
-google.golang.org/grpc v1.12.0
-github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7
-golang.org/x/net 0ed95abb35c445290478a5348a7b38bb154135fd
-github.com/gogo/protobuf v1.0.0
-github.com/gogo/googleapis b23578765ee54ff6bceff57f397d833bf4ca6869
-github.com/golang/protobuf v1.1.0
-github.com/containerd/continuity bd77b46c8352f74eb12c85bdc01f4b90f69d66b4
-github.com/opencontainers/image-spec v1.0.1
-github.com/opencontainers/runc 96ec2177ae841256168fcf76954f7177af9446eb
-github.com/Microsoft/go-winio v0.4.11
-github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
-github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353 # v1.0.1-45-geba862d
-github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
-github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
-google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
-golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
-github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
-github.com/syndtr/gocapability db04d3cc01c8b54962a58ec7e491717d06cfcc16
-github.com/Microsoft/hcsshim v0.7.9
-golang.org/x/crypto 0709b304e793a5edb4a2c0145f281ecdc20838a4
-github.com/containerd/cri f913714917d2456d7e65a0be84962b1ce8acb487 # release/1.2 branch
-
-github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
-github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b
-github.com/docker/go-units v0.3.1
-github.com/google/shlex 6f45313302b9c56850fc17f99e40caebce98c716
-golang.org/x/time f51c12702a4d776e4c1fa9b0fabab841babae631
-
-github.com/docker/docker 71cd53e4a197b303c6ba086bd584ffd67a884281
-github.com/pkg/profile 5b67d428864e92711fcbd2f8629456121a56d91f
-
-github.com/tonistiigi/fsutil 2862f6bc5ac9b97124e552a5c108230b38a1b0ca
-github.com/hashicorp/go-immutable-radix 826af9ccf0feeee615d546d69b11f8e98da8c8f1 https://github.com/tonistiigi/go-immutable-radix
-github.com/hashicorp/golang-lru a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
-github.com/mitchellh/hashstructure 2bca23e0e452137f789efbc8610126fd8b94f73b
-github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d
-github.com/docker/distribution 30578ca32960a4d368bf6db67b0a33c2a1f3dc6f
-
-github.com/tonistiigi/units 6950e57a87eaf136bbe44ef2ec8e75b9e3569de2
-github.com/docker/cli 99576756eb3303b7af8102c502f21a912e3c1af6 https://github.com/tonistiigi/docker-cli.git
-github.com/docker/docker-credential-helpers d68f9aeca33f5fd3f08eeae5e9d175edf4e731d1
-github.com/docker/libnetwork 36d3bed0e9f4b3c8c66df9bd45278bb90b33e911
-github.com/BurntSushi/toml 3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005
-github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb
-
-github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
-github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
-github.com/uber/jaeger-client-go e02c85f9069ea625a96fc4e1afb5e9ac6c569a6d
-github.com/apache/thrift b2a4d4ae21c789b689dd162deb819665567f481c
-github.com/uber/jaeger-lib c48167d9cae5887393dd5e61efd06a4a48b7fbb3
-github.com/codahale/hdrhistogram f8ad88b59a584afeee9d334eff879b104439117b
-
-github.com/opentracing-contrib/go-stdlib b1a47cfbdd7543e70e9ef3e73d0802ad306cc1cc
-
-# used by dockerfile tests
-gotest.tools v2.1.0
-github.com/google/go-cmp v0.2.0

+ 2 - 2
vendor/github.com/moby/buildkit/worker/cacheresult.go

@@ -20,7 +20,7 @@ type cacheResultStorage struct {
 	wc *Controller
 	wc *Controller
 }
 }
 
 
-func (s *cacheResultStorage) Save(res solver.Result) (solver.CacheResult, error) {
+func (s *cacheResultStorage) Save(res solver.Result, createdAt time.Time) (solver.CacheResult, error) {
 	ref, ok := res.Sys().(*WorkerRef)
 	ref, ok := res.Sys().(*WorkerRef)
 	if !ok {
 	if !ok {
 		return solver.CacheResult{}, errors.Errorf("invalid result: %T", res.Sys())
 		return solver.CacheResult{}, errors.Errorf("invalid result: %T", res.Sys())
@@ -33,7 +33,7 @@ func (s *cacheResultStorage) Save(res solver.Result) (solver.CacheResult, error)
 			ref.ImmutableRef.Metadata().Commit()
 			ref.ImmutableRef.Metadata().Commit()
 		}
 		}
 	}
 	}
-	return solver.CacheResult{ID: ref.ID(), CreatedAt: time.Now()}, nil
+	return solver.CacheResult{ID: ref.ID(), CreatedAt: createdAt}, nil
 }
 }
 func (s *cacheResultStorage) Load(ctx context.Context, res solver.CacheResult) (solver.Result, error) {
 func (s *cacheResultStorage) Load(ctx context.Context, res solver.CacheResult) (solver.Result, error) {
 	return s.load(res.ID, false)
 	return s.load(res.ID, false)

+ 4 - 3
vendor/github.com/moby/buildkit/worker/worker.go

@@ -10,6 +10,7 @@ import (
 	"github.com/moby/buildkit/exporter"
 	"github.com/moby/buildkit/exporter"
 	"github.com/moby/buildkit/frontend"
 	"github.com/moby/buildkit/frontend"
 	gw "github.com/moby/buildkit/frontend/gateway/client"
 	gw "github.com/moby/buildkit/frontend/gateway/client"
+	"github.com/moby/buildkit/session"
 	"github.com/moby/buildkit/solver"
 	"github.com/moby/buildkit/solver"
 	digest "github.com/opencontainers/go-digest"
 	digest "github.com/opencontainers/go-digest"
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
@@ -23,12 +24,12 @@ type Worker interface {
 	GCPolicy() []client.PruneInfo
 	GCPolicy() []client.PruneInfo
 	LoadRef(id string, hidden bool) (cache.ImmutableRef, error)
 	LoadRef(id string, hidden bool) (cache.ImmutableRef, error)
 	// ResolveOp resolves Vertex.Sys() to Op implementation.
 	// ResolveOp resolves Vertex.Sys() to Op implementation.
-	ResolveOp(v solver.Vertex, s frontend.FrontendLLBBridge) (solver.Op, error)
-	ResolveImageConfig(ctx context.Context, ref string, opt gw.ResolveImageConfigOpt) (digest.Digest, []byte, error)
+	ResolveOp(v solver.Vertex, s frontend.FrontendLLBBridge, sm *session.Manager) (solver.Op, error)
+	ResolveImageConfig(ctx context.Context, ref string, opt gw.ResolveImageConfigOpt, sm *session.Manager) (digest.Digest, []byte, error)
 	// Exec is similar to executor.Exec but without []mount.Mount
 	// Exec is similar to executor.Exec but without []mount.Mount
 	Exec(ctx context.Context, meta executor.Meta, rootFS cache.ImmutableRef, stdin io.ReadCloser, stdout, stderr io.WriteCloser) error
 	Exec(ctx context.Context, meta executor.Meta, rootFS cache.ImmutableRef, stdin io.ReadCloser, stdout, stderr io.WriteCloser) error
 	DiskUsage(ctx context.Context, opt client.DiskUsageInfo) ([]*client.UsageInfo, error)
 	DiskUsage(ctx context.Context, opt client.DiskUsageInfo) ([]*client.UsageInfo, error)
-	Exporter(name string) (exporter.Exporter, error)
+	Exporter(name string, sm *session.Manager) (exporter.Exporter, error)
 	Prune(ctx context.Context, ch chan client.UsageInfo, opt ...client.PruneInfo) error
 	Prune(ctx context.Context, ch chan client.UsageInfo, opt ...client.PruneInfo) error
 	GetRemote(ctx context.Context, ref cache.ImmutableRef, createIfNeeded bool) (*solver.Remote, error)
 	GetRemote(ctx context.Context, ref cache.ImmutableRef, createIfNeeded bool) (*solver.Remote, error)
 	FromRemote(ctx context.Context, remote *solver.Remote) (cache.ImmutableRef, error)
 	FromRemote(ctx context.Context, remote *solver.Remote) (cache.ImmutableRef, error)

+ 7 - 1
vendor/github.com/tonistiigi/fsutil/receive.go

@@ -92,7 +92,13 @@ func (w *dynamicWalker) fill(ctx context.Context, pathC chan<- *currentPath) err
 			if !ok {
 			if !ok {
 				return nil
 				return nil
 			}
 			}
-			pathC <- p
+			select {
+			case pathC <- p:
+			case <-ctx.Done():
+				w.err = ctx.Err()
+				close(w.closeCh)
+				return ctx.Err()
+			}
 		case <-ctx.Done():
 		case <-ctx.Done():
 			w.err = ctx.Err()
 			w.err = ctx.Err()
 			close(w.closeCh)
 			close(w.closeCh)

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác