Browse code

vendor: update buildkit to v0.14.0

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>

Tonis Tiigi authored on 2024/06/12 03:58:35
Showing 25 changed files
... ...
@@ -50,12 +50,13 @@ func New(opt Opt) (exporter.Exporter, error) {
50 50
 	return im, nil
51 51
 }
52 52
 
53
-func (e *imageExporter) Resolve(ctx context.Context, id int, opt map[string]string) (exporter.ExporterInstance, error) {
53
+func (e *imageExporter) Resolve(ctx context.Context, id int, attrs map[string]string) (exporter.ExporterInstance, error) {
54 54
 	i := &imageExporterInstance{
55 55
 		imageExporter: e,
56 56
 		id:            id,
57
+		attrs:         attrs,
57 58
 	}
58
-	for k, v := range opt {
59
+	for k, v := range attrs {
59 60
 		switch exptypes.ImageExporterOptKey(k) {
60 61
 		case exptypes.OptKeyName:
61 62
 			for _, v := range strings.Split(v, ",") {
... ...
@@ -80,12 +81,17 @@ type imageExporterInstance struct {
80 80
 	id          int
81 81
 	targetNames []distref.Named
82 82
 	meta        map[string][]byte
83
+	attrs       map[string]string
83 84
 }
84 85
 
85 86
 func (e *imageExporterInstance) ID() int {
86 87
 	return e.id
87 88
 }
88 89
 
90
+func (e *imageExporterInstance) Type() string {
91
+	return "image"
92
+}
93
+
89 94
 func (e *imageExporterInstance) Name() string {
90 95
 	return "exporting to image"
91 96
 }
... ...
@@ -94,6 +100,10 @@ func (e *imageExporterInstance) Config() *exporter.Config {
94 94
 	return exporter.NewConfig()
95 95
 }
96 96
 
97
+func (e *imageExporterInstance) Attrs() map[string]string {
98
+	return e.attrs
99
+}
100
+
97 101
 func (e *imageExporterInstance) Export(ctx context.Context, inp *exporter.Source, inlineCache exptypes.InlineCache, sessionID string) (map[string]string, exporter.DescriptorReference, error) {
98 102
 	if len(inp.Refs) > 1 {
99 103
 		return nil, nil, fmt.Errorf("exporting multiple references to image store is currently unsupported")
... ...
@@ -35,7 +35,7 @@ require (
35 35
 	github.com/cpuguy83/tar2go v0.3.1
36 36
 	github.com/creack/pty v1.1.18
37 37
 	github.com/deckarep/golang-set/v2 v2.3.0
38
-	github.com/distribution/reference v0.5.0
38
+	github.com/distribution/reference v0.6.0
39 39
 	github.com/docker/distribution v2.8.3+incompatible
40 40
 	github.com/docker/go-connections v0.5.0
41 41
 	github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c
... ...
@@ -61,7 +61,7 @@ require (
61 61
 	github.com/miekg/dns v1.1.57
62 62
 	github.com/mistifyio/go-zfs/v3 v3.0.1
63 63
 	github.com/mitchellh/copystructure v1.2.0
64
-	github.com/moby/buildkit v0.14.0-rc2
64
+	github.com/moby/buildkit v0.14.0
65 65
 	github.com/moby/docker-image-spec v1.3.1
66 66
 	github.com/moby/ipvs v1.1.0
67 67
 	github.com/moby/locker v1.0.1
... ...
@@ -93,7 +93,7 @@ require (
93 93
 	github.com/vbatts/tar-split v0.11.5
94 94
 	github.com/vishvananda/netlink v1.2.1-beta.2
95 95
 	github.com/vishvananda/netns v0.0.4
96
-	go.etcd.io/bbolt v1.3.9
96
+	go.etcd.io/bbolt v1.3.10
97 97
 	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1
98 98
 	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1
99 99
 	go.opentelemetry.io/otel v1.21.0
... ...
@@ -210,8 +210,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
210 210
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
211 211
 github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
212 212
 github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
213
-github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
214
-github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
213
+github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
214
+github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
215 215
 github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
216 216
 github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
217 217
 github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
... ...
@@ -480,8 +480,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
480 480
 github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
481 481
 github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
482 482
 github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs=
483
-github.com/moby/buildkit v0.14.0-rc2 h1:qvl0hOKeyAWReOkksNtstQjPNaAD4jN3Dvq4r7slqYM=
484
-github.com/moby/buildkit v0.14.0-rc2/go.mod h1:/ZJNHNVso1nf063XlDhEkNEcRNW19utVpUKixCUo9Ks=
483
+github.com/moby/buildkit v0.14.0 h1:mHv2lFS8znLDRc4SMyM2B9tPjxWh2blMvr0H7ARquNM=
484
+github.com/moby/buildkit v0.14.0/go.mod h1:1XssG7cAqv5Bz1xcGMxJL123iCv5TYN4Z/qf647gfuk=
485 485
 github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
486 486
 github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
487 487
 github.com/moby/ipvs v1.1.0 h1:ONN4pGaZQgAx+1Scz5RvWV4Q7Gb+mvfRh3NsPS+1XQQ=
... ...
@@ -718,8 +718,8 @@ github.com/zmap/zlint/v3 v3.1.0 h1:WjVytZo79m/L1+/Mlphl09WBob6YTGljN5IGWZFpAv0=
718 718
 github.com/zmap/zlint/v3 v3.1.0/go.mod h1:L7t8s3sEKkb0A2BxGy1IWrxt1ZATa1R4QfJZaQOD3zU=
719 719
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
720 720
 go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
721
-go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
722
-go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
721
+go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
722
+go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
723 723
 go.etcd.io/etcd/api/v3 v3.5.6/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8=
724 724
 go.etcd.io/etcd/client/pkg/v3 v3.5.6 h1:TXQWYceBKqLp4sa87rcPs11SXxUA/mHwH975v+BDvLU=
725 725
 go.etcd.io/etcd/client/pkg/v3 v3.5.6/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ=
... ...
@@ -10,7 +10,7 @@ Go library to handle references to container images.
10 10
 [![codecov](https://codecov.io/gh/distribution/reference/branch/main/graph/badge.svg)](https://codecov.io/gh/distribution/reference)
11 11
 [![FOSSA Status](https://app.fossa.com/api/projects/custom%2B162%2Fgithub.com%2Fdistribution%2Freference.svg?type=shield)](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Fdistribution%2Freference?ref=badge_shield)
12 12
 
13
-This repository contains a library for handling refrences to container images held in container registries. Please see [godoc](https://pkg.go.dev/github.com/distribution/reference) for details.
13
+This repository contains a library for handling references to container images held in container registries. Please see [godoc](https://pkg.go.dev/github.com/distribution/reference) for details.
14 14
 
15 15
 ## Contribution
16 16
 
... ...
@@ -123,20 +123,51 @@ func ParseDockerRef(ref string) (Named, error) {
123 123
 // splitDockerDomain splits a repository name to domain and remote-name.
124 124
 // If no valid domain is found, the default domain is used. Repository name
125 125
 // needs to be already validated before.
126
-func splitDockerDomain(name string) (domain, remainder string) {
127
-	i := strings.IndexRune(name, '/')
128
-	if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != localhost && strings.ToLower(name[:i]) == name[:i]) {
129
-		domain, remainder = defaultDomain, name
130
-	} else {
131
-		domain, remainder = name[:i], name[i+1:]
132
-	}
133
-	if domain == legacyDefaultDomain {
134
-		domain = defaultDomain
135
-	}
136
-	if domain == defaultDomain && !strings.ContainsRune(remainder, '/') {
137
-		remainder = officialRepoPrefix + remainder
138
-	}
139
-	return
126
+func splitDockerDomain(name string) (domain, remoteName string) {
127
+	maybeDomain, maybeRemoteName, ok := strings.Cut(name, "/")
128
+	if !ok {
129
+		// Fast-path for single element ("familiar" names), such as "ubuntu"
130
+		// or "ubuntu:latest". Familiar names must be handled separately, to
131
+		// prevent them from being handled as "hostname:port".
132
+		//
133
+		// Canonicalize them as "docker.io/library/name[:tag]"
134
+
135
+		// FIXME(thaJeztah): account for bare "localhost" or "example.com" names, which SHOULD be considered a domain.
136
+		return defaultDomain, officialRepoPrefix + name
137
+	}
138
+
139
+	switch {
140
+	case maybeDomain == localhost:
141
+		// localhost is a reserved namespace and always considered a domain.
142
+		domain, remoteName = maybeDomain, maybeRemoteName
143
+	case maybeDomain == legacyDefaultDomain:
144
+		// canonicalize the Docker Hub and legacy "Docker Index" domains.
145
+		domain, remoteName = defaultDomain, maybeRemoteName
146
+	case strings.ContainsAny(maybeDomain, ".:"):
147
+		// Likely a domain or IP-address:
148
+		//
149
+		// - contains a "." (e.g., "example.com" or "127.0.0.1")
150
+		// - contains a ":" (e.g., "example:5000", "::1", or "[::1]:5000")
151
+		domain, remoteName = maybeDomain, maybeRemoteName
152
+	case strings.ToLower(maybeDomain) != maybeDomain:
153
+		// Uppercase namespaces are not allowed, so if the first element
154
+		// is not lowercase, we assume it to be a domain-name.
155
+		domain, remoteName = maybeDomain, maybeRemoteName
156
+	default:
157
+		// None of the above: it's not a domain, so use the default, and
158
+		// use the name input the remote-name.
159
+		domain, remoteName = defaultDomain, name
160
+	}
161
+
162
+	if domain == defaultDomain && !strings.ContainsRune(remoteName, '/') {
163
+		// Canonicalize "familiar" names, but only on Docker Hub, not
164
+		// on other domains:
165
+		//
166
+		// "docker.io/ubuntu[:tag]" => "docker.io/library/ubuntu[:tag]"
167
+		remoteName = officialRepoPrefix + remoteName
168
+	}
169
+
170
+	return domain, remoteName
140 171
 }
141 172
 
142 173
 // familiarizeName returns a shortened version of the name familiar
... ...
@@ -35,8 +35,13 @@ import (
35 35
 )
36 36
 
37 37
 const (
38
+	// RepositoryNameTotalLengthMax is the maximum total number of characters in a repository name.
39
+	RepositoryNameTotalLengthMax = 255
40
+
38 41
 	// NameTotalLengthMax is the maximum total number of characters in a repository name.
39
-	NameTotalLengthMax = 255
42
+	//
43
+	// Deprecated: use [RepositoryNameTotalLengthMax] instead.
44
+	NameTotalLengthMax = RepositoryNameTotalLengthMax
40 45
 )
41 46
 
42 47
 var (
... ...
@@ -55,8 +60,8 @@ var (
55 55
 	// ErrNameEmpty is returned for empty, invalid repository names.
56 56
 	ErrNameEmpty = errors.New("repository name must have at least one component")
57 57
 
58
-	// ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax.
59
-	ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax)
58
+	// ErrNameTooLong is returned when a repository name is longer than RepositoryNameTotalLengthMax.
59
+	ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", RepositoryNameTotalLengthMax)
60 60
 
61 61
 	// ErrNameNotCanonical is returned when a name is not canonical.
62 62
 	ErrNameNotCanonical = errors.New("repository name must be canonical")
... ...
@@ -165,6 +170,9 @@ func Path(named Named) (name string) {
165 165
 	return path
166 166
 }
167 167
 
168
+// splitDomain splits a named reference into a hostname and path string.
169
+// If no valid hostname is found, the hostname is empty and the full value
170
+// is returned as name
168 171
 func splitDomain(name string) (string, string) {
169 172
 	match := anchoredNameRegexp.FindStringSubmatch(name)
170 173
 	if len(match) != 3 {
... ...
@@ -173,19 +181,6 @@ func splitDomain(name string) (string, string) {
173 173
 	return match[1], match[2]
174 174
 }
175 175
 
176
-// SplitHostname splits a named reference into a
177
-// hostname and name string. If no valid hostname is
178
-// found, the hostname is empty and the full value
179
-// is returned as name
180
-//
181
-// Deprecated: Use [Domain] or [Path].
182
-func SplitHostname(named Named) (string, string) {
183
-	if r, ok := named.(namedRepository); ok {
184
-		return r.Domain(), r.Path()
185
-	}
186
-	return splitDomain(named.Name())
187
-}
188
-
189 176
 // Parse parses s and returns a syntactically valid Reference.
190 177
 // If an error was encountered it is returned, along with a nil Reference.
191 178
 func Parse(s string) (Reference, error) {
... ...
@@ -200,10 +195,6 @@ func Parse(s string) (Reference, error) {
200 200
 		return nil, ErrReferenceInvalidFormat
201 201
 	}
202 202
 
203
-	if len(matches[1]) > NameTotalLengthMax {
204
-		return nil, ErrNameTooLong
205
-	}
206
-
207 203
 	var repo repository
208 204
 
209 205
 	nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1])
... ...
@@ -215,6 +206,10 @@ func Parse(s string) (Reference, error) {
215 215
 		repo.path = matches[1]
216 216
 	}
217 217
 
218
+	if len(repo.path) > RepositoryNameTotalLengthMax {
219
+		return nil, ErrNameTooLong
220
+	}
221
+
218 222
 	ref := reference{
219 223
 		namedRepository: repo,
220 224
 		tag:             matches[2],
... ...
@@ -253,14 +248,15 @@ func ParseNamed(s string) (Named, error) {
253 253
 // WithName returns a named object representing the given string. If the input
254 254
 // is invalid ErrReferenceInvalidFormat will be returned.
255 255
 func WithName(name string) (Named, error) {
256
-	if len(name) > NameTotalLengthMax {
257
-		return nil, ErrNameTooLong
258
-	}
259
-
260 256
 	match := anchoredNameRegexp.FindStringSubmatch(name)
261 257
 	if match == nil || len(match) != 3 {
262 258
 		return nil, ErrReferenceInvalidFormat
263 259
 	}
260
+
261
+	if len(match[2]) > RepositoryNameTotalLengthMax {
262
+		return nil, ErrNameTooLong
263
+	}
264
+
264 265
 	return repository{
265 266
 		domain: match[1],
266 267
 		path:   match[2],
... ...
@@ -372,6 +372,7 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*
372 372
 		if err != nil {
373 373
 			return nil, err
374 374
 		}
375
+		bklog.G(ctx).Debugf("resolve exporter %s with %v", ex.Type, ex.Attrs)
375 376
 		expi, err := exp.Resolve(ctx, i, ex.Attrs)
376 377
 		if err != nil {
377 378
 			return nil, err
... ...
@@ -20,6 +20,7 @@ import (
20 20
 	cerrdefs "github.com/containerd/errdefs"
21 21
 	"github.com/moby/buildkit/cache"
22 22
 	cacheconfig "github.com/moby/buildkit/cache/config"
23
+	"github.com/moby/buildkit/client"
23 24
 	"github.com/moby/buildkit/exporter"
24 25
 	"github.com/moby/buildkit/exporter/containerimage/exptypes"
25 26
 	"github.com/moby/buildkit/session"
... ...
@@ -68,6 +69,7 @@ func (e *imageExporter) Resolve(ctx context.Context, id int, opt map[string]stri
68 68
 	i := &imageExporterInstance{
69 69
 		imageExporter: e,
70 70
 		id:            id,
71
+		attrs:         opt,
71 72
 		opts: ImageCommitOpts{
72 73
 			RefCfg: cacheconfig.RefConfig{
73 74
 				Compression: compression.New(compression.Default),
... ...
@@ -168,7 +170,8 @@ func (e *imageExporter) Resolve(ctx context.Context, id int, opt map[string]stri
168 168
 
169 169
 type imageExporterInstance struct {
170 170
 	*imageExporter
171
-	id int
171
+	id    int
172
+	attrs map[string]string
172 173
 
173 174
 	opts                 ImageCommitOpts
174 175
 	push                 bool
... ...
@@ -194,6 +197,14 @@ func (e *imageExporterInstance) Config() *exporter.Config {
194 194
 	return exporter.NewConfigWithCompression(e.opts.RefCfg.Compression)
195 195
 }
196 196
 
197
+func (e *imageExporterInstance) Type() string {
198
+	return client.ExporterImage
199
+}
200
+
201
+func (e *imageExporterInstance) Attrs() map[string]string {
202
+	return e.attrs
203
+}
204
+
197 205
 func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source, inlineCache exptypes.InlineCache, sessionID string) (_ map[string]string, descref exporter.DescriptorReference, err error) {
198 206
 	src = src.Clone()
199 207
 	if src.Metadata == nil {
... ...
@@ -22,6 +22,8 @@ type ExporterInstance interface {
22 22
 	ID() int
23 23
 	Name() string
24 24
 	Config() *Config
25
+	Type() string
26
+	Attrs() map[string]string
25 27
 	Export(ctx context.Context, src *Source, inlineCache exptypes.InlineCache, sessionID string) (map[string]string, DescriptorReference, error)
26 28
 }
27 29
 
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"time"
9 9
 
10 10
 	"github.com/moby/buildkit/cache"
11
+	"github.com/moby/buildkit/client"
11 12
 	"github.com/moby/buildkit/exporter"
12 13
 	"github.com/moby/buildkit/exporter/containerimage/exptypes"
13 14
 	"github.com/moby/buildkit/exporter/util/epoch"
... ...
@@ -38,6 +39,7 @@ func New(opt Opt) (exporter.Exporter, error) {
38 38
 func (e *localExporter) Resolve(ctx context.Context, id int, opt map[string]string) (exporter.ExporterInstance, error) {
39 39
 	i := &localExporterInstance{
40 40
 		id:            id,
41
+		attrs:         opt,
41 42
 		localExporter: e,
42 43
 	}
43 44
 	_, err := i.opts.Load(opt)
... ...
@@ -50,7 +52,8 @@ func (e *localExporter) Resolve(ctx context.Context, id int, opt map[string]stri
50 50
 
51 51
 type localExporterInstance struct {
52 52
 	*localExporter
53
-	id int
53
+	id    int
54
+	attrs map[string]string
54 55
 
55 56
 	opts CreateFSOpts
56 57
 }
... ...
@@ -63,6 +66,14 @@ func (e *localExporterInstance) Name() string {
63 63
 	return "exporting to client directory"
64 64
 }
65 65
 
66
+func (e *localExporterInstance) Type() string {
67
+	return client.ExporterLocal
68
+}
69
+
70
+func (e *localExporterInstance) Attrs() map[string]string {
71
+	return e.attrs
72
+}
73
+
66 74
 func (e *localExporter) Config() *exporter.Config {
67 75
 	return exporter.NewConfig()
68 76
 }
... ...
@@ -14,6 +14,7 @@ import (
14 14
 	"github.com/distribution/reference"
15 15
 	"github.com/moby/buildkit/cache"
16 16
 	cacheconfig "github.com/moby/buildkit/cache/config"
17
+	"github.com/moby/buildkit/client"
17 18
 	"github.com/moby/buildkit/exporter"
18 19
 	"github.com/moby/buildkit/exporter/containerimage"
19 20
 	"github.com/moby/buildkit/exporter/containerimage/exptypes"
... ...
@@ -34,8 +35,8 @@ import (
34 34
 type ExporterVariant string
35 35
 
36 36
 const (
37
-	VariantOCI    = "oci"
38
-	VariantDocker = "docker"
37
+	VariantOCI    = client.ExporterOCI
38
+	VariantDocker = client.ExporterDocker
39 39
 )
40 40
 
41 41
 const (
... ...
@@ -62,6 +63,7 @@ func (e *imageExporter) Resolve(ctx context.Context, id int, opt map[string]stri
62 62
 	i := &imageExporterInstance{
63 63
 		imageExporter: e,
64 64
 		id:            id,
65
+		attrs:         opt,
65 66
 		tar:           true,
66 67
 		opts: containerimage.ImageCommitOpts{
67 68
 			RefCfg: cacheconfig.RefConfig{
... ...
@@ -100,7 +102,8 @@ func (e *imageExporter) Resolve(ctx context.Context, id int, opt map[string]stri
100 100
 
101 101
 type imageExporterInstance struct {
102 102
 	*imageExporter
103
-	id int
103
+	id    int
104
+	attrs map[string]string
104 105
 
105 106
 	opts containerimage.ImageCommitOpts
106 107
 	tar  bool
... ...
@@ -115,6 +118,14 @@ func (e *imageExporterInstance) Name() string {
115 115
 	return fmt.Sprintf("exporting to %s image format", e.opt.Variant)
116 116
 }
117 117
 
118
+func (e *imageExporterInstance) Type() string {
119
+	return string(e.opt.Variant)
120
+}
121
+
122
+func (e *imageExporterInstance) Attrs() map[string]string {
123
+	return e.attrs
124
+}
125
+
118 126
 func (e *imageExporterInstance) Config() *exporter.Config {
119 127
 	return exporter.NewConfigWithCompression(e.opts.RefCfg.Compression)
120 128
 }
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"time"
8 8
 
9 9
 	"github.com/moby/buildkit/cache"
10
+	"github.com/moby/buildkit/client"
10 11
 	"github.com/moby/buildkit/exporter"
11 12
 	"github.com/moby/buildkit/exporter/containerimage/exptypes"
12 13
 	"github.com/moby/buildkit/exporter/local"
... ...
@@ -37,6 +38,7 @@ func (e *localExporter) Resolve(ctx context.Context, id int, opt map[string]stri
37 37
 	li := &localExporterInstance{
38 38
 		localExporter: e,
39 39
 		id:            id,
40
+		attrs:         opt,
40 41
 	}
41 42
 	_, err := li.opts.Load(opt)
42 43
 	if err != nil {
... ...
@@ -49,7 +51,8 @@ func (e *localExporter) Resolve(ctx context.Context, id int, opt map[string]stri
49 49
 
50 50
 type localExporterInstance struct {
51 51
 	*localExporter
52
-	id int
52
+	id    int
53
+	attrs map[string]string
53 54
 
54 55
 	opts local.CreateFSOpts
55 56
 }
... ...
@@ -62,6 +65,14 @@ func (e *localExporterInstance) Name() string {
62 62
 	return "exporting to client tarball"
63 63
 }
64 64
 
65
+func (e *localExporterInstance) Type() string {
66
+	return client.ExporterTar
67
+}
68
+
69
+func (e *localExporterInstance) Attrs() map[string]string {
70
+	return e.attrs
71
+}
72
+
65 73
 func (e *localExporterInstance) Config() *exporter.Config {
66 74
 	return exporter.NewConfig()
67 75
 }
... ...
@@ -276,10 +276,10 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS
276 276
 		// The `dockerfile.Warnings` *should* only contain warnings about empty continuation
277 277
 		// lines, but we'll check the warning message to be sure, so that we don't accidentally
278 278
 		// process warnings that are not related to empty continuation lines twice.
279
-		if warning.URL == linter.RuleNoEmptyContinuations.URL {
279
+		if warning.URL == linter.RuleNoEmptyContinuation.URL {
280 280
 			location := []parser.Range{*warning.Location}
281
-			msg := linter.RuleNoEmptyContinuations.Format()
282
-			lint.Run(&linter.RuleNoEmptyContinuations, location, msg)
281
+			msg := linter.RuleNoEmptyContinuation.Format()
282
+			lint.Run(&linter.RuleNoEmptyContinuation, location, msg)
283 283
 		}
284 284
 	}
285 285
 
... ...
@@ -92,7 +92,7 @@ func (rule *LinterRule[F]) Run(warn LintWarnFunc, location []parser.Range, txt .
92 92
 }
93 93
 
94 94
 func LintFormatShort(rulename, msg string, startLine int) string {
95
-	return fmt.Sprintf("Lint Rule '%s': %s (line %d)", rulename, msg, startLine)
95
+	return fmt.Sprintf("%s: %s (line %d)", rulename, msg, startLine)
96 96
 }
97 97
 
98 98
 type LintWarnFunc func(rulename, description, url, fmtmsg string, location []parser.Range)
... ...
@@ -21,10 +21,10 @@ var (
21 21
 			return fmt.Sprintf("'%s' and '%s' keywords' casing do not match", as, from)
22 22
 		},
23 23
 	}
24
-	RuleNoEmptyContinuations = LinterRule[func() string]{
25
-		Name:        "NoEmptyContinuations",
24
+	RuleNoEmptyContinuation = LinterRule[func() string]{
25
+		Name:        "NoEmptyContinuation",
26 26
 		Description: "Empty continuation lines will become errors in a future release",
27
-		URL:         "https://docs.docker.com/go/dockerfile/rule/no-empty-continuations/",
27
+		URL:         "https://docs.docker.com/go/dockerfile/rule/no-empty-continuation/",
28 28
 		Format: func() string {
29 29
 			return "Empty continuation line"
30 30
 		},
... ...
@@ -338,7 +338,7 @@ func Parse(rwc io.Reader) (*Result, error) {
338 338
 			warnings = append(warnings, Warning{
339 339
 				Short:    "Empty continuation line found in: " + line,
340 340
 				Detail:   [][]byte{[]byte("Empty continuation lines will become errors in a future release")},
341
-				URL:      "https://docs.docker.com/go/dockerfile/rule/no-empty-continuations/",
341
+				URL:      "https://docs.docker.com/go/dockerfile/rule/no-empty-continuation/",
342 342
 				Location: &Range{Start: Position{Line: currentLine}, End: Position{Line: currentLine}},
343 343
 			})
344 344
 		}
... ...
@@ -53,8 +53,6 @@ const (
53 53
 )
54 54
 
55 55
 type ExporterRequest struct {
56
-	Type           string
57
-	Attrs          map[string]string
58 56
 	Exporters      []exporter.ExporterInstance
59 57
 	CacheExporters []RemoteCacheExporter
60 58
 }
... ...
@@ -173,11 +171,11 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend
173 173
 		CreatedAt:     &st,
174 174
 	}
175 175
 
176
-	if exp.Type != "" {
177
-		rec.Exporters = []*controlapi.Exporter{{
178
-			Type:  exp.Type,
179
-			Attrs: exp.Attrs,
180
-		}}
176
+	for _, e := range exp.Exporters {
177
+		rec.Exporters = append(rec.Exporters, &controlapi.Exporter{
178
+			Type:  e.Type(),
179
+			Attrs: e.Attrs(),
180
+		})
181 181
 	}
182 182
 
183 183
 	if err := s.history.Update(ctx, &controlapi.BuildHistoryEvent{
... ...
@@ -3,7 +3,7 @@ package flightcontrol
3 3
 import (
4 4
 	"context"
5 5
 	"io"
6
-	"runtime"
6
+	"math/rand"
7 7
 	"sort"
8 8
 	"sync"
9 9
 	"time"
... ...
@@ -43,13 +43,14 @@ func (g *Group[T]) Do(ctx context.Context, key string, fn func(ctx context.Conte
43 43
 			err = errors.Wrapf(errRetryTimeout, "flightcontrol")
44 44
 			return v, err
45 45
 		}
46
-		runtime.Gosched()
47 46
 		if backoff > 0 {
48
-			time.Sleep(backoff)
49
-			backoff *= 2
47
+			backoff = time.Duration(float64(backoff) * 1.2)
50 48
 		} else {
51
-			backoff = time.Millisecond
49
+			// randomize initial backoff to avoid all goroutines retrying at once
50
+			//nolint:gosec // using math/rand pseudo-randomness is acceptable here
51
+			backoff = time.Millisecond + time.Duration(rand.Intn(1e7))*time.Nanosecond
52 52
 		}
53
+		time.Sleep(backoff)
53 54
 	}
54 55
 }
55 56
 
56 57
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+1.21.9
... ...
@@ -421,10 +421,19 @@ Prev()   Move to the previous key.
421 421
 ```
422 422
 
423 423
 Each of those functions has a return signature of `(key []byte, value []byte)`.
424
-When you have iterated to the end of the cursor then `Next()` will return a
425
-`nil` key.  You must seek to a position using `First()`, `Last()`, or `Seek()`
426
-before calling `Next()` or `Prev()`. If you do not seek to a position then
427
-these functions will return a `nil` key.
424
+You must seek to a position using `First()`, `Last()`, or `Seek()` before calling
425
+`Next()` or `Prev()`. If you do not seek to a position then these functions will
426
+return a `nil` key.
427
+
428
+When you have iterated to the end of the cursor, then `Next()` will return a
429
+`nil` key and the cursor still points to the last element if present. When you
430
+have iterated to the beginning of the cursor, then `Prev()` will return a `nil`
431
+key and the cursor still points to the first element if present.
432
+
433
+If you remove key/value pairs during iteration, the cursor may automatically
434
+move to the next position if present in current node each time removing a key.
435
+When you call `c.Next()` after removing a key, it may skip one key/value pair.
436
+Refer to [pull/611](https://github.com/etcd-io/bbolt/pull/611) to get more detailed info.
428 437
 
429 438
 During iteration, if the key is non-`nil` but the value is `nil`, that means
430 439
 the key refers to a bucket rather than a value.  Use `Bucket.Bucket()` to
... ...
@@ -850,6 +859,12 @@ Here are a few things to note when evaluating and using Bolt:
850 850
   to grow. However, it's important to note that deleting large chunks of data
851 851
   will not allow you to reclaim that space on disk.
852 852
 
853
+* Removing key/values pairs in a bucket during iteration on the bucket using
854
+  cursor may not work properly. Each time when removing a key/value pair, the
855
+  cursor may automatically move to the next position if present. When users
856
+  call `c.Next()` after removing a key, it may skip one key/value pair.
857
+  Refer to https://github.com/etcd-io/bbolt/pull/611 for more detailed info.
858
+
853 859
   For more information on page allocation, [see this comment][page-allocation].
854 860
 
855 861
 [page-allocation]: https://github.com/boltdb/bolt/issues/308#issuecomment-74811638
... ...
@@ -71,7 +71,7 @@ func (c *Cursor) Last() (key []byte, value []byte) {
71 71
 
72 72
 	// If this is an empty page (calling Delete may result in empty pages)
73 73
 	// we call prev to find the last page that is not empty
74
-	for len(c.stack) > 0 && c.stack[len(c.stack)-1].count() == 0 {
74
+	for len(c.stack) > 1 && c.stack[len(c.stack)-1].count() == 0 {
75 75
 		c.prev()
76 76
 	}
77 77
 
... ...
@@ -254,6 +254,15 @@ func (c *Cursor) prev() (key []byte, value []byte, flags uint32) {
254 254
 			elem.index--
255 255
 			break
256 256
 		}
257
+		// If we've hit the beginning, we should stop moving the cursor,
258
+		// and stay at the first element, so that users can continue to
259
+		// iterate over the elements in reverse direction by calling `Next`.
260
+		// We should return nil in such case.
261
+		// Refer to https://github.com/etcd-io/bbolt/issues/733
262
+		if len(c.stack) == 1 {
263
+			c.first()
264
+			return nil, nil, 0
265
+		}
257 266
 		c.stack = c.stack[:i]
258 267
 	}
259 268
 
... ...
@@ -282,9 +282,8 @@ func (f *freelist) read(p *page) {
282 282
 	if count == 0 {
283 283
 		f.ids = nil
284 284
 	} else {
285
-		var ids []pgid
286
-		data := unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p), unsafe.Sizeof(ids[0]), idx)
287
-		unsafeSlice(unsafe.Pointer(&ids), data, count)
285
+		data := unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p), unsafe.Sizeof(pgid(0)), idx)
286
+		ids := unsafe.Slice((*pgid)(data), count)
288 287
 
289 288
 		// copy the ids, so we don't modify on the freelist page directly
290 289
 		idsCopy := make([]pgid, count)
... ...
@@ -322,15 +321,13 @@ func (f *freelist) write(p *page) error {
322 322
 		p.count = uint16(l)
323 323
 	} else if l < 0xFFFF {
324 324
 		p.count = uint16(l)
325
-		var ids []pgid
326 325
 		data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
327
-		unsafeSlice(unsafe.Pointer(&ids), data, l)
326
+		ids := unsafe.Slice((*pgid)(data), l)
328 327
 		f.copyall(ids)
329 328
 	} else {
330 329
 		p.count = 0xFFFF
331
-		var ids []pgid
332 330
 		data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
333
-		unsafeSlice(unsafe.Pointer(&ids), data, l+1)
331
+		ids := unsafe.Slice((*pgid)(data), l+1)
334 332
 		ids[0] = pgid(l)
335 333
 		f.copyall(ids[1:])
336 334
 	}
... ...
@@ -74,9 +74,8 @@ func (p *page) leafPageElements() []leafPageElement {
74 74
 	if p.count == 0 {
75 75
 		return nil
76 76
 	}
77
-	var elems []leafPageElement
78 77
 	data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
79
-	unsafeSlice(unsafe.Pointer(&elems), data, int(p.count))
78
+	elems := unsafe.Slice((*leafPageElement)(data), int(p.count))
80 79
 	return elems
81 80
 }
82 81
 
... ...
@@ -91,9 +90,8 @@ func (p *page) branchPageElements() []branchPageElement {
91 91
 	if p.count == 0 {
92 92
 		return nil
93 93
 	}
94
-	var elems []branchPageElement
95 94
 	data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
96
-	unsafeSlice(unsafe.Pointer(&elems), data, int(p.count))
95
+	elems := unsafe.Slice((*branchPageElement)(data), int(p.count))
97 96
 	return elems
98 97
 }
99 98
 
... ...
@@ -1,7 +1,6 @@
1 1
 package bbolt
2 2
 
3 3
 import (
4
-	"reflect"
5 4
 	"unsafe"
6 5
 )
7 6
 
... ...
@@ -26,14 +25,3 @@ func unsafeByteSlice(base unsafe.Pointer, offset uintptr, i, j int) []byte {
26 26
 	// all), so this is believed to be correct.
27 27
 	return (*[maxAllocSize]byte)(unsafeAdd(base, offset))[i:j:j]
28 28
 }
29
-
30
-// unsafeSlice modifies the data, len, and cap of a slice variable pointed to by
31
-// the slice parameter.  This helper should be used over other direct
32
-// manipulation of reflect.SliceHeader to prevent misuse, namely, converting
33
-// from reflect.SliceHeader to a Go slice type.
34
-func unsafeSlice(slice, data unsafe.Pointer, len int) {
35
-	s := (*reflect.SliceHeader)(slice)
36
-	s.Data = uintptr(data)
37
-	s.Cap = len
38
-	s.Len = len
39
-}
... ...
@@ -444,7 +444,7 @@ github.com/deckarep/golang-set/v2
444 444
 # github.com/dimchansky/utfbom v1.1.1
445 445
 ## explicit
446 446
 github.com/dimchansky/utfbom
447
-# github.com/distribution/reference v0.5.0
447
+# github.com/distribution/reference v0.6.0
448 448
 ## explicit; go 1.20
449 449
 github.com/distribution/reference
450 450
 # github.com/docker/distribution v2.8.3+incompatible
... ...
@@ -712,7 +712,7 @@ github.com/mitchellh/hashstructure/v2
712 712
 # github.com/mitchellh/reflectwalk v1.0.2
713 713
 ## explicit
714 714
 github.com/mitchellh/reflectwalk
715
-# github.com/moby/buildkit v0.14.0-rc2
715
+# github.com/moby/buildkit v0.14.0
716 716
 ## explicit; go 1.21
717 717
 github.com/moby/buildkit/api/services/control
718 718
 github.com/moby/buildkit/api/types
... ...
@@ -1145,8 +1145,8 @@ github.com/zmap/zlint/v3/lints/etsi
1145 1145
 github.com/zmap/zlint/v3/lints/mozilla
1146 1146
 github.com/zmap/zlint/v3/lints/rfc
1147 1147
 github.com/zmap/zlint/v3/util
1148
-# go.etcd.io/bbolt v1.3.9
1149
-## explicit; go 1.17
1148
+# go.etcd.io/bbolt v1.3.10
1149
+## explicit; go 1.21
1150 1150
 go.etcd.io/bbolt
1151 1151
 # go.etcd.io/etcd/client/pkg/v3 v3.5.6
1152 1152
 ## explicit; go 1.16