From ec114475863e0484458f060833071d33e1d742f7 Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 2 Oct 2026 19:43:06 +0100 Subject: [PATCH 01/17] chore: merge v0.14.1 --- cache/remotecache/v1/chains.go | 9 - cache/remotecache/v1/utils.go | 9 - client/client_test.go | 3 - cmd/buildkitd/main.go | 35 +- executor/runcexecutor/executor_linux.go | 7 +- exporter/earthlyoutputs/export.go | 11 + frontend/dockerfile/dockerfile_test.go | 16 - frontend/gateway/gateway.go | 17 +- frontend/gateway/grpcclient/client.go | 18 +- go.mod | 9 +- go.sum | 33 +- session/grpc.go | 7 - session/session.go | 14 +- solver/jobs.go | 28 +- solver/pb/ops.pb.go | 500 ++++++------------ solver/scheduler.go | 7 +- util/archutil/loong64_binary.go | 4 - util/gitutil/git_cli.go | 4 - util/gitutil/git_ref.go | 4 - .../grpc-ecosystem/go-grpc-middleware/LICENSE | 201 +++++++ .../tonistiigi/fsutil/diskwriter.go | 20 +- .../github.com/tonistiigi/fsutil/hardlinks.go | 68 --- .../github.com/tonistiigi/fsutil/receive.go | 48 +- vendor/github.com/tonistiigi/fsutil/send.go | 24 - vendor/modules.txt | 13 - 25 files changed, 436 insertions(+), 673 deletions(-) create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/LICENSE diff --git a/cache/remotecache/v1/chains.go b/cache/remotecache/v1/chains.go index 9c438ee86..87744d9ec 100644 --- a/cache/remotecache/v1/chains.go +++ b/cache/remotecache/v1/chains.go @@ -123,8 +123,6 @@ type DescriptorProviderPair struct { InfoProvider content.InfoProvider } -var _ withCheckDescriptor = DescriptorProviderPair{} - func (p DescriptorProviderPair) ReaderAt(ctx context.Context, desc ocispecs.Descriptor) (content.ReaderAt, error) { return p.Provider.ReaderAt(ctx, desc) } @@ -162,13 +160,6 @@ func (p DescriptorProviderPair) SnapshotLabels(descs []ocispecs.Descriptor, inde return nil } -func (p DescriptorProviderPair) CheckDescriptor(ctx context.Context, desc ocispecs.Descriptor) error { - if cd, ok := p.Provider.(withCheckDescriptor); ok { - return cd.CheckDescriptor(ctx, desc) - } - return nil -} - // item is an implementation of a record in the cache chain. After validation, // normalization and marshalling into the cache config, the item results form // into the "layers", while the digests and the links form into the "records". diff --git a/cache/remotecache/v1/utils.go b/cache/remotecache/v1/utils.go index 3d6f97ad0..79cf84639 100644 --- a/cache/remotecache/v1/utils.go +++ b/cache/remotecache/v1/utils.go @@ -11,11 +11,6 @@ import ( "github.com/pkg/errors" ) -type withCheckDescriptor interface { - // CheckDescriptor is additional method on Provider to check if the descriptor is available without opening the reader - CheckDescriptor(context.Context, ocispecs.Descriptor) error -} - // sortConfig sorts the config structure to make sure it is deterministic func sortConfig(cc *CacheConfig) { type indexedLayer struct { @@ -283,11 +278,7 @@ func marshalRemote(ctx context.Context, r *solver.Remote, state *marshalState) s return "" } -<<<<<<< HEAD - if cd, ok := r.Provider.(withCheckDescriptor); ok && len(r.Descriptors) > 0 { -======= if r.Provider != nil { ->>>>>>> v0.14.1 for _, d := range r.Descriptors { if _, err := r.Provider.Info(ctx, d.Digest); err != nil { return "" diff --git a/client/client_test.go b/client/client_test.go index 4f137b24a..14389decb 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -167,10 +167,7 @@ var allTests = []func(t *testing.T, sb integration.Sandbox){ testRelativeMountpoint, testLocalSourceDiffer, testLocalSourceWithHardlinksFilter, -<<<<<<< HEAD -======= testNoTarOCIIndexMediaType, ->>>>>>> v0.14.1 testOCILayoutSource, testOCILayoutPlatformSource, testBuildExportZstd, diff --git a/cmd/buildkitd/main.go b/cmd/buildkitd/main.go index 5b5c816f1..e4a50261d 100644 --- a/cmd/buildkitd/main.go +++ b/cmd/buildkitd/main.go @@ -16,7 +16,6 @@ import ( "sync" "time" - "github.com/containerd/containerd/defaults" "github.com/containerd/containerd/pkg/seed" //nolint:staticcheck // SA1019 deprecated "github.com/containerd/containerd/pkg/userns" "github.com/containerd/containerd/platforms" @@ -25,12 +24,8 @@ import ( sddaemon "github.com/coreos/go-systemd/v22/daemon" "github.com/docker/docker/pkg/reexec" "github.com/gofrs/flock" -<<<<<<< HEAD - grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" - regproxy "github.com/moby/buildkit/api/services/registry" -======= "github.com/hashicorp/go-multierror" ->>>>>>> v0.14.1 + regproxy "github.com/moby/buildkit/api/services/registry" "github.com/moby/buildkit/cache/remotecache" "github.com/moby/buildkit/cache/remotecache/azblob" "github.com/moby/buildkit/cache/remotecache/gha" @@ -270,15 +265,13 @@ func main() { logrus.SetLevel(logrus.TraceLevel) } -<<<<<<< HEAD logrus.SetOutput(os.Stderr) // earthly-specific: force logs to show up under earthly-buildkitd container logs -======= + if sc := cfg.System; sc != nil { if v := sc.PlatformsCacheMaxAge; v != nil { archutil.CacheMaxAge = v.Duration } } ->>>>>>> v0.14.1 if cfg.GRPC.DebugAddress != "" { if err := setupDebugHandlers(cfg.GRPC.DebugAddress); err != nil { @@ -303,29 +296,15 @@ func main() { otelgrpc.WithMeterProvider(mp), otelgrpc.WithPropagators(propagators), ) -<<<<<<< HEAD - - unary := grpc_middleware.ChainUnaryServer(unaryInterceptor(ctx, tp, mp), grpcerrors.UnaryServerInterceptor, - unaryTimeoutInterceptor(), // earthly-specific - ) - stream := grpc_middleware.ChainStreamServer(streamTracer, grpcerrors.StreamServerInterceptor, - streamTimeoutInterceptor(), // earthly-specific - ) - maxMsgSize := 67108864 // 64MB opts := []grpc.ServerOption{ - grpc.UnaryInterceptor(unary), grpc.StreamInterceptor(stream), - grpc.MaxRecvMsgSize(maxMsgSize), grpc.MaxSendMsgSize(maxMsgSize), + grpc.StatsHandler(statsHandler), + grpc.ChainUnaryInterceptor(unaryInterceptor, grpcerrors.UnaryServerInterceptor, unaryTimeoutInterceptor()), + grpc.ChainStreamInterceptor(grpcerrors.StreamServerInterceptor, streamTimeoutInterceptor()), + grpc.MaxRecvMsgSize(maxMsgSize), + grpc.MaxSendMsgSize(maxMsgSize), grpc.InitialWindowSize(65535 * 32), grpc.InitialConnWindowSize(65535 * 16), -======= - opts := []grpc.ServerOption{ - grpc.StatsHandler(statsHandler), - grpc.ChainUnaryInterceptor(unaryInterceptor, grpcerrors.UnaryServerInterceptor), - grpc.StreamInterceptor(grpcerrors.StreamServerInterceptor), - grpc.MaxRecvMsgSize(defaults.DefaultMaxRecvMsgSize), - grpc.MaxSendMsgSize(defaults.DefaultMaxSendMsgSize), ->>>>>>> v0.14.1 } server := grpc.NewServer(opts...) diff --git a/executor/runcexecutor/executor_linux.go b/executor/runcexecutor/executor_linux.go index d5f79b50c..a57b863be 100644 --- a/executor/runcexecutor/executor_linux.go +++ b/executor/runcexecutor/executor_linux.go @@ -24,15 +24,10 @@ func updateRuncFieldsForHostOS(runtime *runc.Runc) { func (w *runcExecutor) run(ctx context.Context, id, bundle string, process executor.ProcessInfo, started func(), keep bool) error { killer := newRunProcKiller(w.runc, id) -<<<<<<< HEAD - return w.callWithIO(ctx, id, bundle, process, started, killer, func(ctx context.Context, started chan<- int, io runc.IO, pidfile string) error { + return w.callWithIO(ctx, process, started, killer, func(ctx context.Context, started chan<- int, io runc.IO, pidfile string) error { // earthly-specific; without this runc processes sometimes exit with -1; the +test target in the root earthly repo reproduces it runtime.LockOSThread() defer runtime.UnlockOSThread() - -======= - return w.callWithIO(ctx, process, started, killer, func(ctx context.Context, started chan<- int, io runc.IO, pidfile string) error { ->>>>>>> v0.14.1 extraArgs := []string{} if keep { extraArgs = append(extraArgs, "--keep") diff --git a/exporter/earthlyoutputs/export.go b/exporter/earthlyoutputs/export.go index ef44cc530..4b9bb0617 100644 --- a/exporter/earthlyoutputs/export.go +++ b/exporter/earthlyoutputs/export.go @@ -21,6 +21,7 @@ import ( "github.com/docker/docker/pkg/idtools" "github.com/moby/buildkit/cache" cacheconfig "github.com/moby/buildkit/cache/config" + "github.com/moby/buildkit/client" "github.com/moby/buildkit/exporter" "github.com/moby/buildkit/exporter/containerimage" "github.com/moby/buildkit/exporter/containerimage/exptypes" @@ -84,6 +85,7 @@ func (e *imageExporter) Resolve(ctx context.Context, id int, opt map[string]stri i := &imageExporterInstance{ imageExporter: e, id: id, + attrs: opt, opts: containerimage.ImageCommitOpts{ RefCfg: cacheconfig.RefConfig{ Compression: compression.New(compression.Default), @@ -185,6 +187,7 @@ func (e *imageExporter) Resolve(ctx context.Context, id int, opt map[string]stri type imageExporterInstance struct { *imageExporter id int + attrs map[string]string opts containerimage.ImageCommitOpts push bool pushByDigest bool @@ -205,6 +208,14 @@ func (e *imageExporterInstance) Name() string { return "[output] exporting outputs" } +func (e *imageExporterInstance) Type() string { + return client.ExporterEarthly +} + +func (e *imageExporterInstance) Attrs() map[string]string { + return e.attrs +} + type imgData struct { // localExport represents whether the image should be exported locally as a tar. localExport bool diff --git a/frontend/dockerfile/dockerfile_test.go b/frontend/dockerfile/dockerfile_test.go index 04179d0dc..43dd5cee8 100644 --- a/frontend/dockerfile/dockerfile_test.go +++ b/frontend/dockerfile/dockerfile_test.go @@ -6882,10 +6882,7 @@ func testReproSourceDateEpoch(t *testing.T, sb integration.Sandbox) { dockerfile string files []fstest.Applier expectedDigest string -<<<<<<< HEAD -======= noCacheExport bool ->>>>>>> v0.14.1 } testCases := []testCase{ { @@ -6913,8 +6910,6 @@ COPY --link foo foo files: []fstest.Applier{fstest.CreateFile("foo", []byte("foo"), 0600)}, expectedDigest: "sha256:9f75e4bdbf3d825acb36bb603ddef4a25742afb8ccb674763ffc611ae047d8a6", }, -<<<<<<< HEAD -======= { // https://github.com/moby/buildkit/issues/4793 name: "NoAdditionalLayer", @@ -6923,7 +6918,6 @@ COPY --link foo foo expectedDigest: "sha256:eeba8ef81dec46359d099c5d674009da54e088fa8f29945d4d7fb3a7a88c450e", noCacheExport: true, // "skipping cache export for empty result" }, ->>>>>>> v0.14.1 } // https://explore.ggcr.dev/?image=amd64%2Fdebian%3Abullseye-20230109-slim @@ -6983,14 +6977,10 @@ COPY --link foo foo require.NoError(t, err) desc, manifest, img := readImage(t, ctx, target) -<<<<<<< HEAD - _, cacheManifest, _ := readImage(t, ctx, target+"-cache") -======= var cacheManifest ocispecs.Manifest if !tc.noCacheExport { _, cacheManifest, _ = readImage(t, ctx, target+"-cache") } ->>>>>>> v0.14.1 t.Log("The digest may change depending on the BuildKit version, the snapshotter configuration, etc.") require.Equal(t, tc.expectedDigest, desc.Digest.String()) @@ -7008,17 +6998,11 @@ COPY --link foo foo require.Equal(t, fmt.Sprintf("%d", tm.Unix()), l.Annotations["buildkit/rewritten-timestamp"]) } } -<<<<<<< HEAD - // Cache layers must *not* have rewritten-timestamp - for _, l := range cacheManifest.Layers { - require.Empty(t, l.Annotations["buildkit/rewritten-timestamp"]) -======= if !tc.noCacheExport { // Cache layers must *not* have rewritten-timestamp for _, l := range cacheManifest.Layers { require.Empty(t, l.Annotations["buildkit/rewritten-timestamp"]) } ->>>>>>> v0.14.1 } // Build again, after pruning the base image layer cache. diff --git a/frontend/gateway/gateway.go b/frontend/gateway/gateway.go index ddf930b04..0a2f2b6f1 100644 --- a/frontend/gateway/gateway.go +++ b/frontend/gateway/gateway.go @@ -14,7 +14,6 @@ import ( "syscall" "time" - "github.com/containerd/containerd/defaults" "github.com/containerd/containerd/mount" "github.com/distribution/reference" "github.com/docker/docker/pkg/idtools" @@ -498,24 +497,16 @@ func newBridgeForwarder(ctx context.Context, llbBridge frontend.FrontendLLBBridg func serveLLBBridgeForwarder(ctx context.Context, llbBridge frontend.FrontendLLBBridge, exec executor.Executor, workers worker.Infos, inputs map[string]*opspb.Definition, sid string, sm *session.Manager) (*llbBridgeForwarder, context.Context, error) { ctx, cancel := context.WithCancelCause(ctx) lbf := newBridgeForwarder(ctx, llbBridge, exec, workers, inputs, sid, sm) -<<<<<<< HEAD maxMsgSize := 67108864 // 64MB - server := grpc.NewServer( - grpc.UnaryInterceptor(grpcerrors.UnaryServerInterceptor), - grpc.StreamInterceptor(grpcerrors.StreamServerInterceptor), - grpc.MaxRecvMsgSize(maxMsgSize), grpc.MaxSendMsgSize(maxMsgSize), - grpc.InitialWindowSize(65535*32), - grpc.InitialConnWindowSize(65535*16), - ) -======= serverOpt := []grpc.ServerOption{ grpc.UnaryInterceptor(grpcerrors.UnaryServerInterceptor), grpc.StreamInterceptor(grpcerrors.StreamServerInterceptor), - grpc.MaxRecvMsgSize(defaults.DefaultMaxRecvMsgSize), - grpc.MaxSendMsgSize(defaults.DefaultMaxSendMsgSize), + grpc.MaxRecvMsgSize(maxMsgSize), + grpc.MaxSendMsgSize(maxMsgSize), + grpc.InitialWindowSize(65535 * 32), + grpc.InitialConnWindowSize(65535 * 16), } server := grpc.NewServer(serverOpt...) ->>>>>>> v0.14.1 grpc_health_v1.RegisterHealthServer(server, health.NewServer()) pb.RegisterLLBBridgeServer(server, lbf) diff --git a/frontend/gateway/grpcclient/client.go b/frontend/gateway/grpcclient/client.go index 0ef00f220..b67597ad1 100644 --- a/frontend/gateway/grpcclient/client.go +++ b/frontend/gateway/grpcclient/client.go @@ -1275,23 +1275,13 @@ func grpcClientConn(ctx context.Context) (context.Context, *grpc.ClientConn, err }), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithUnaryInterceptor(grpcerrors.UnaryClientInterceptor), - grpc.WithStreamInterceptor(grpcerrors.StreamClientInterceptor), - grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(16 << 20)), - grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(16 << 20)), + grpc.WithInitialWindowSize(65535 * 32), + grpc.WithInitialConnWindowSize(65535 * 16), + grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)), + grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)), } -<<<<<<< HEAD - cc, err := grpc.DialContext(ctx, "localhost", dialOpt, - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithUnaryInterceptor(grpcerrors.UnaryClientInterceptor), - grpc.WithStreamInterceptor(grpcerrors.StreamClientInterceptor), - grpc.WithInitialWindowSize(65535*32), - grpc.WithInitialConnWindowSize(65535*16), - grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)), - grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize))) -======= cc, err := grpc.DialContext(ctx, "localhost", dialOpts...) ->>>>>>> v0.14.1 if err != nil { return nil, nil, errors.Wrap(err, "failed to create grpc client") } diff --git a/go.mod b/go.mod index b1a8db2fd..eaa01f1bd 100644 --- a/go.mod +++ b/go.mod @@ -68,11 +68,7 @@ require ( github.com/spdx/tools-golang v0.5.3 github.com/stretchr/testify v1.8.4 github.com/tonistiigi/fsutil v0.0.0-20240424095704-91a3fc46842c -<<<<<<< HEAD - github.com/tonistiigi/go-actions-cache v0.0.0-20240227172821-a0b64f338598 -======= github.com/tonistiigi/go-actions-cache v0.0.0-20240320205438-9794bdbb2fb4 ->>>>>>> v0.14.1 github.com/tonistiigi/go-archvariant v1.0.0 github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab @@ -95,11 +91,7 @@ require ( go.opentelemetry.io/otel/trace v1.21.0 go.opentelemetry.io/proto/otlp v1.0.0 golang.org/x/crypto v0.21.0 -<<<<<<< HEAD - golang.org/x/mod v0.13.0 -======= golang.org/x/mod v0.17.0 ->>>>>>> v0.14.1 golang.org/x/net v0.23.0 golang.org/x/sync v0.5.0 golang.org/x/sys v0.18.0 @@ -112,6 +104,7 @@ require ( require ( github.com/docker/distribution v2.8.2+incompatible + github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/moby/sys/mount v0.3.5 ) diff --git a/go.sum b/go.sum index 3f852ac5e..4503729e9 100644 --- a/go.sum +++ b/go.sum @@ -139,19 +139,12 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= -<<<<<<< HEAD -github.com/docker/cli v25.0.3+incompatible h1:KLeNs7zws74oFuVhgZQ5ONGZiXUUdgsdy6/EsX/6284= -github.com/docker/cli v25.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= -github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v25.0.3+incompatible h1:D5fy/lYmY7bvZa0XTZ5/UJPljor41F+vdyJG5luQLfQ= -github.com/docker/docker v25.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -======= github.com/docker/cli v26.1.4+incompatible h1:I8PHdc0MtxEADqYJZvhBrW9bo8gawKwwenxRM7/rLu8= github.com/docker/cli v26.1.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v26.1.4+incompatible h1:vuTpXDuoga+Z38m1OZHzl7NKisKWaWlhjQk7IDPSLsU= github.com/docker/docker v26.1.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= ->>>>>>> v0.14.1 github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8= github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= @@ -181,6 +174,7 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/garyburd/redigo v1.6.4 h1:LFu2R3+ZOPgSMWMOL+saa/zXRjw0ID2G8FepO53BGlg= github.com/garyburd/redigo v1.6.4/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -212,6 +206,7 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -244,15 +239,12 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -<<<<<<< HEAD github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= -======= ->>>>>>> v0.14.1 github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/hanwen/go-fuse/v2 v2.4.0 h1:12OhD7CkXXQdvxG2osIdBQLdXh+nmLXY9unkUIe/xaU= @@ -358,6 +350,7 @@ github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bl github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170 h1:DiLBVp4DAcZlBVBEtJpNWZpZVq0AEeCY7Hqk8URVs4o= github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= @@ -365,6 +358,7 @@ github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= @@ -401,6 +395,7 @@ github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b/go.mod h1:/yeG0My github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI= github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM= @@ -413,6 +408,7 @@ github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -420,15 +416,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -<<<<<<< HEAD -github.com/tonistiigi/go-actions-cache v0.0.0-20240227172821-a0b64f338598 h1:DA/NDC0YbMdnfcOSUzAnbUZE6dSM54d+0hrBqG+bOfs= -github.com/tonistiigi/go-actions-cache v0.0.0-20240227172821-a0b64f338598/go.mod h1:anhKd3mnC1shAbQj1Q4IJ+w6xqezxnyDYlx/yKa7IXM= -======= -github.com/tonistiigi/fsutil v0.0.0-20240424095704-91a3fc46842c h1:+6wg/4ORAbnSoGDzg2Q1i3CeMcT/jjhye/ZfnBHy7/M= -github.com/tonistiigi/fsutil v0.0.0-20240424095704-91a3fc46842c/go.mod h1:vbbYqJlnswsbJqWUcJN8fKtBhnEgldDrcagTgnBVKKM= github.com/tonistiigi/go-actions-cache v0.0.0-20240320205438-9794bdbb2fb4 h1:R0lM8Jo3aZL95yjQHWQti7nszllleKBxCs9uyFbykII= github.com/tonistiigi/go-actions-cache v0.0.0-20240320205438-9794bdbb2fb4/go.mod h1:anhKd3mnC1shAbQj1Q4IJ+w6xqezxnyDYlx/yKa7IXM= ->>>>>>> v0.14.1 github.com/tonistiigi/go-archvariant v1.0.0 h1:5LC1eDWiBNflnTF1prCiX09yfNHIxDC/aukdhCdTyb0= github.com/tonistiigi/go-archvariant v1.0.0/go.mod h1:TxFmO5VS6vMq2kvs3ht04iPXtu2rUT/erOnGFYfk5Ho= github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea h1:SXhTLE6pb6eld/v/cCndK0AMpt1wiVFb/YYmqB3/QG0= @@ -484,8 +473,11 @@ go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8 go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -534,6 +526,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -584,6 +577,7 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA= google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= @@ -595,6 +589,7 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= diff --git a/session/grpc.go b/session/grpc.go index 07c24fddb..7d096c91b 100644 --- a/session/grpc.go +++ b/session/grpc.go @@ -26,14 +26,7 @@ func serve(ctx context.Context, grpcServer *grpc.Server, conn net.Conn) { (&http2.Server{}).ServeConn(conn, &http2.ServeConnOpts{Handler: grpcServer}) } -<<<<<<< HEAD func grpcClientConn(ctx context.Context, conn net.Conn, healthCfg ManagerHealthCfg) (context.Context, *grpc.ClientConn, error) { - var unary []grpc.UnaryClientInterceptor - var stream []grpc.StreamClientInterceptor - -======= -func grpcClientConn(ctx context.Context, conn net.Conn) (context.Context, *grpc.ClientConn, error) { ->>>>>>> v0.14.1 var dialCount int64 dialer := grpc.WithContextDialer(func(ctx context.Context, addr string) (net.Conn, error) { if c := atomic.AddInt64(&dialCount, 1); c > 1 { diff --git a/session/session.go b/session/session.go index 186b08274..2a731316a 100644 --- a/session/session.go +++ b/session/session.go @@ -52,20 +52,14 @@ type Session struct { func NewSession(ctx context.Context, name, sharedKey string) (*Session, error) { id := identity.NewID() -<<<<<<< HEAD - var unary []grpc.UnaryServerInterceptor - var stream []grpc.StreamServerInterceptor - maxMsgSize := 67108864 // 64MB - serverOpts := []grpc.ServerOption{ - grpc.MaxRecvMsgSize(maxMsgSize), grpc.MaxSendMsgSize(maxMsgSize), - grpc.InitialWindowSize(65535 * 32), - grpc.InitialConnWindowSize(65535 * 16), -======= serverOpts := []grpc.ServerOption{ grpc.UnaryInterceptor(grpcerrors.UnaryServerInterceptor), grpc.StreamInterceptor(grpcerrors.StreamServerInterceptor), ->>>>>>> v0.14.1 + grpc.MaxRecvMsgSize(maxMsgSize), + grpc.MaxSendMsgSize(maxMsgSize), + grpc.InitialWindowSize(65535 * 32), + grpc.InitialConnWindowSize(65535 * 16), } if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() { diff --git a/solver/jobs.go b/solver/jobs.go index c492514e5..6d7bbac15 100644 --- a/solver/jobs.go +++ b/solver/jobs.go @@ -517,12 +517,7 @@ func (jl *Solver) loadUnlocked(ctx context.Context, v, parent Vertex, j *Job, ca origDigest: origVtx.Digest(), } jl.actives[dgst] = st -<<<<<<< HEAD dgstTrackerInst.add(dgst, "loadUnlocked-add") - } else { - dgstTrackerInst.add(dgst, "loadUnlocked-exists") -======= - if debugScheduler { lg := bklog.G(ctx). WithField("vertex_name", v.Name()). @@ -540,16 +535,18 @@ func (jl *Solver) loadUnlocked(ctx context.Context, v, parent Vertex, j *Job, ca Debug("new active vertex input") } } - } else if debugScheduler { - lg := bklog.G(ctx). - WithField("vertex_name", v.Name()). - WithField("vertex_digest", v.Digest()). - WithField("actives_digest_key", dgst) - if j != nil { - lg = lg.WithField("job", j.id) + } else { + dgstTrackerInst.add(dgst, "loadUnlocked-exists") + if debugScheduler { + lg := bklog.G(ctx). + WithField("vertex_name", v.Name()). + WithField("vertex_digest", v.Digest()). + WithField("actives_digest_key", dgst) + if j != nil { + lg = lg.WithField("job", j.id) + } + lg.Debug("reusing active vertex") } - lg.Debug("reusing active vertex") ->>>>>>> v0.14.1 } st.mu.Lock() @@ -689,9 +686,7 @@ func (jl *Solver) deleteIfUnreferenced(k digest.Digest, st *state) { } st.Release() delete(jl.actives, k) -<<<<<<< HEAD dgstTrackerInst.add(k, "delete") -======= } else if debugScheduler { var jobIDs []string for j := range st.jobs { @@ -703,7 +698,6 @@ func (jl *Solver) deleteIfUnreferenced(k digest.Digest, st *state) { WithField("actives_key", k). WithField("jobs", jobIDs). Debug("not deleting referenced active vertex") ->>>>>>> v0.14.1 } } diff --git a/solver/pb/ops.pb.go b/solver/pb/ops.pb.go index 44520dbd7..3b6b505ad 100644 --- a/solver/pb/ops.pb.go +++ b/solver/pb/ops.pb.go @@ -2985,344 +2985,176 @@ func init() { func init() { proto.RegisterFile("ops.proto", fileDescriptor_8de16154b2733812) } var fileDescriptor_8de16154b2733812 = []byte{ -<<<<<<< HEAD - // 2663 bytes of a gzipped FileDescriptorProto + // 2691 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0x4f, 0x6f, 0x5b, 0xc7, 0x11, 0x17, 0xff, 0x93, 0x43, 0x89, 0x66, 0xd6, 0x4e, 0xc2, 0xa8, 0xae, 0xac, 0xbc, 0xa4, 0x81, 0x2c, 0xdb, 0x12, 0xa2, 0x00, 0x71, 0x6a, 0x04, 0x05, 0x24, 0x91, 0x8a, 0x18, 0xdb, 0xa2, 0xba, 0x94, 0x9c, 0x02, 0x2d, 0x60, 0x3c, 0x3d, 0x2e, 0xa9, 0x07, 0x3d, 0xbe, 0x7d, 0x78, 0x6f, 0x69, - 0x89, 0x3d, 0xf4, 0xd0, 0x53, 0x8f, 0x01, 0x0a, 0xf4, 0x56, 0xf4, 0x4b, 0xf4, 0xd8, 0xde, 0x03, - 0xe4, 0x92, 0x43, 0x0f, 0x41, 0x0f, 0x69, 0xe1, 0x5c, 0xfa, 0x19, 0x8a, 0x16, 0x28, 0x66, 0x76, - 0xdf, 0x1f, 0x52, 0x32, 0x1c, 0xb7, 0x41, 0x4f, 0x9c, 0x37, 0xf3, 0xdb, 0xd9, 0xd9, 0xd9, 0x99, - 0xd9, 0xd9, 0x25, 0xd4, 0x64, 0x10, 0x6d, 0x04, 0xa1, 0x54, 0x92, 0xe5, 0x83, 0x93, 0xe5, 0x7b, - 0x23, 0x57, 0x9d, 0x4e, 0x4e, 0x36, 0x1c, 0x39, 0xde, 0x1c, 0xc9, 0x91, 0xdc, 0x24, 0xd1, 0xc9, - 0x64, 0x48, 0x5f, 0xf4, 0x41, 0x94, 0x1e, 0x62, 0xfd, 0x23, 0x0f, 0xf9, 0x5e, 0xc0, 0xde, 0x86, - 0xb2, 0xeb, 0x07, 0x13, 0x15, 0xb5, 0x72, 0xab, 0x85, 0xb5, 0xfa, 0x56, 0x6d, 0x23, 0x38, 0xd9, - 0xe8, 0x22, 0x87, 0x1b, 0x01, 0x5b, 0x85, 0xa2, 0xb8, 0x10, 0x4e, 0x2b, 0xbf, 0x9a, 0x5b, 0xab, - 0x6f, 0x01, 0x02, 0x3a, 0x17, 0xc2, 0xe9, 0x05, 0xfb, 0x0b, 0x9c, 0x24, 0xec, 0x3d, 0x28, 0x47, - 0x72, 0x12, 0x3a, 0xa2, 0x55, 0x20, 0xcc, 0x22, 0x62, 0xfa, 0xc4, 0x21, 0x94, 0x91, 0xa2, 0xa6, - 0xa1, 0xeb, 0x89, 0x56, 0x31, 0xd5, 0xb4, 0xe7, 0x7a, 0x1a, 0x43, 0x12, 0xf6, 0x0e, 0x94, 0x4e, - 0x26, 0xae, 0x37, 0x68, 0x95, 0x08, 0x52, 0x47, 0xc8, 0x0e, 0x32, 0x08, 0xa3, 0x65, 0x08, 0x1a, - 0x8b, 0x70, 0x24, 0x5a, 0xe5, 0x14, 0xf4, 0x18, 0x19, 0x1a, 0x44, 0x32, 0x9c, 0x6b, 0xe0, 0x0e, - 0x87, 0xad, 0x4a, 0x3a, 0x57, 0xdb, 0x1d, 0x0e, 0xf5, 0x5c, 0x28, 0x61, 0x6b, 0x50, 0x0d, 0x3c, - 0x5b, 0x0d, 0x65, 0x38, 0x6e, 0x41, 0x6a, 0xf7, 0xa1, 0xe1, 0xf1, 0x44, 0xca, 0xee, 0x43, 0xdd, - 0x91, 0x7e, 0xa4, 0x42, 0xdb, 0xf5, 0x55, 0xd4, 0xaa, 0x13, 0xf8, 0x75, 0x04, 0x7f, 0x26, 0xc3, - 0x33, 0x11, 0xee, 0xa6, 0x42, 0x9e, 0x45, 0xee, 0x14, 0x21, 0x2f, 0x03, 0xeb, 0x77, 0x39, 0xa8, - 0xc6, 0x5a, 0x99, 0x05, 0x8b, 0xdb, 0xa1, 0x73, 0xea, 0x2a, 0xe1, 0xa8, 0x49, 0x28, 0x5a, 0xb9, - 0xd5, 0xdc, 0x5a, 0x8d, 0xcf, 0xf0, 0x58, 0x03, 0xf2, 0xbd, 0x3e, 0xf9, 0xbb, 0xc6, 0xf3, 0xbd, - 0x3e, 0x6b, 0x41, 0xe5, 0x89, 0x1d, 0xba, 0xb6, 0xaf, 0xc8, 0xc1, 0x35, 0x1e, 0x7f, 0xb2, 0x9b, - 0x50, 0xeb, 0xf5, 0x9f, 0x88, 0x30, 0x72, 0xa5, 0x4f, 0x6e, 0xad, 0xf1, 0x94, 0xc1, 0x56, 0x00, - 0x7a, 0xfd, 0x3d, 0x61, 0xa3, 0xd2, 0xa8, 0x55, 0x5a, 0x2d, 0xac, 0xd5, 0x78, 0x86, 0x63, 0xfd, - 0x0a, 0x4a, 0xb4, 0xd5, 0xec, 0x53, 0x28, 0x0f, 0xdc, 0x91, 0x88, 0x94, 0x36, 0x67, 0x67, 0xeb, - 0x8b, 0x6f, 0x6e, 0x2d, 0xfc, 0xf5, 0x9b, 0x5b, 0xeb, 0x99, 0x98, 0x92, 0x81, 0xf0, 0x1d, 0xe9, - 0x2b, 0xdb, 0xf5, 0x45, 0x18, 0x6d, 0x8e, 0xe4, 0x3d, 0x3d, 0x64, 0xa3, 0x4d, 0x3f, 0xdc, 0x68, - 0x60, 0xb7, 0xa1, 0xe4, 0xfa, 0x03, 0x71, 0x41, 0xf6, 0x17, 0x76, 0xae, 0x1b, 0x55, 0xf5, 0xde, - 0x44, 0x05, 0x13, 0xd5, 0x45, 0x11, 0xd7, 0x08, 0xeb, 0xcb, 0x1c, 0x94, 0x75, 0x28, 0xb1, 0x9b, - 0x50, 0x1c, 0x0b, 0x65, 0xd3, 0xfc, 0xf5, 0xad, 0xaa, 0xde, 0x52, 0x65, 0x73, 0xe2, 0x62, 0x94, - 0x8e, 0xe5, 0x04, 0x7d, 0x9f, 0x4f, 0xa3, 0xf4, 0x31, 0x72, 0xb8, 0x11, 0xb0, 0x1f, 0x41, 0xc5, - 0x17, 0xea, 0x5c, 0x86, 0x67, 0xe4, 0xa3, 0x86, 0x0e, 0x8b, 0x03, 0xa1, 0x1e, 0xcb, 0x81, 0xe0, - 0xb1, 0x8c, 0xdd, 0x85, 0x6a, 0x24, 0x9c, 0x49, 0xe8, 0xaa, 0x29, 0xf9, 0xab, 0xb1, 0xd5, 0xa4, - 0x60, 0x35, 0x3c, 0x02, 0x27, 0x08, 0x76, 0x07, 0x6a, 0x91, 0x70, 0x42, 0xa1, 0x84, 0xff, 0x8c, - 0xfc, 0x57, 0xdf, 0x5a, 0x32, 0xf0, 0x50, 0xa8, 0x8e, 0xff, 0x8c, 0xa7, 0x72, 0xeb, 0xcb, 0x3c, - 0x14, 0xd1, 0x66, 0xc6, 0xa0, 0x68, 0x87, 0x23, 0x9d, 0x51, 0x35, 0x4e, 0x34, 0x6b, 0x42, 0x01, - 0x75, 0xe4, 0x89, 0x85, 0x24, 0x72, 0x9c, 0xf3, 0x81, 0xd9, 0x50, 0x24, 0x71, 0xdc, 0x24, 0x12, - 0xa1, 0xd9, 0x47, 0xa2, 0xd9, 0x6d, 0xa8, 0x05, 0xa1, 0xbc, 0x98, 0x3e, 0xd5, 0x16, 0xa4, 0x51, - 0x8a, 0x4c, 0x34, 0xa0, 0x1a, 0x18, 0x8a, 0xad, 0x03, 0x88, 0x0b, 0x15, 0xda, 0xfb, 0x32, 0x52, - 0x51, 0xab, 0x4c, 0xd6, 0x52, 0xdc, 0x23, 0xa3, 0x7b, 0xc8, 0x33, 0x52, 0xb6, 0x0c, 0xd5, 0x53, - 0x19, 0x29, 0xdf, 0x1e, 0x0b, 0xca, 0x90, 0x1a, 0x4f, 0xbe, 0x99, 0x05, 0xe5, 0x89, 0xe7, 0x8e, - 0x5d, 0xd5, 0xaa, 0xa5, 0x3a, 0x8e, 0x89, 0xc3, 0x8d, 0x04, 0xa3, 0xd8, 0x19, 0x85, 0x72, 0x12, - 0x1c, 0xda, 0xa1, 0xf0, 0x15, 0xe5, 0x4f, 0x8d, 0xcf, 0xf0, 0xd8, 0xc7, 0xf0, 0x56, 0x28, 0xc6, - 0xf2, 0x99, 0xa0, 0x8d, 0xea, 0xab, 0xc9, 0x49, 0xc4, 0xd1, 0xb1, 0x91, 0xfb, 0x4c, 0x50, 0x0e, - 0x55, 0xf9, 0x8b, 0x01, 0xd6, 0x5d, 0x28, 0x6b, 0xbb, 0xd1, 0x2d, 0x48, 0x99, 0x4c, 0x21, 0x1a, - 0x33, 0xa4, 0x7b, 0x18, 0x67, 0x48, 0xf7, 0xd0, 0x6a, 0x43, 0x59, 0x5b, 0x88, 0xe8, 0x03, 0x5c, - 0x95, 0x41, 0x23, 0x8d, 0xbc, 0xbe, 0x1c, 0x2a, 0x1d, 0x91, 0x9c, 0x68, 0xd2, 0x6a, 0x87, 0xda, - 0xff, 0x05, 0x4e, 0xb4, 0xf5, 0x10, 0x6a, 0xc9, 0xce, 0xd2, 0x14, 0x6d, 0xa3, 0x26, 0xdf, 0x6d, - 0xe3, 0x00, 0x72, 0x97, 0x9e, 0x94, 0x68, 0x74, 0xa3, 0x0c, 0x94, 0x2b, 0x7d, 0xdb, 0x23, 0x45, - 0x55, 0x9e, 0x7c, 0x5b, 0xff, 0x2c, 0x40, 0x89, 0x16, 0xc6, 0xd6, 0x30, 0x23, 0x82, 0x89, 0x5e, - 0x41, 0x61, 0x87, 0x99, 0x8c, 0x00, 0xca, 0xbd, 0x24, 0x21, 0x30, 0x0f, 0x97, 0x31, 0x3a, 0x3d, - 0xe1, 0x28, 0x19, 0x9a, 0x79, 0x92, 0x6f, 0x9c, 0x7f, 0x80, 0x19, 0xaa, 0x03, 0x86, 0x68, 0x76, - 0x07, 0xca, 0x92, 0xd2, 0x8a, 0x62, 0xe6, 0x05, 0xc9, 0x66, 0x20, 0xa8, 0x3c, 0x14, 0xf6, 0x40, - 0xfa, 0xde, 0x94, 0x22, 0xa9, 0xca, 0x93, 0x6f, 0x0c, 0x74, 0xca, 0xa3, 0xa3, 0x69, 0xa0, 0xcb, - 0x6a, 0x43, 0x07, 0xfa, 0xe3, 0x98, 0xc9, 0x53, 0x39, 0x16, 0xce, 0xa3, 0x71, 0x30, 0x8c, 0x7a, - 0x81, 0x6a, 0x5d, 0x4f, 0x43, 0x32, 0xe6, 0xf1, 0x44, 0x8a, 0x48, 0xc7, 0x76, 0x4e, 0x05, 0x22, - 0x6f, 0xa4, 0xc8, 0x5d, 0xc3, 0xe3, 0x89, 0x34, 0xcd, 0x34, 0x84, 0xbe, 0x4e, 0xd0, 0x4c, 0xa6, - 0x21, 0x36, 0x95, 0x63, 0x84, 0xf6, 0xfb, 0xfb, 0x88, 0x7c, 0x23, 0xad, 0xee, 0x9a, 0xc3, 0x8d, - 0x44, 0xaf, 0x36, 0x9a, 0x78, 0xaa, 0xdb, 0x6e, 0xbd, 0xa9, 0x5d, 0x19, 0x7f, 0xb3, 0x1f, 0xc3, - 0x22, 0x56, 0x32, 0xe1, 0x2b, 0xb2, 0xa4, 0xd5, 0xa2, 0x05, 0xbf, 0x9e, 0x2c, 0x78, 0x37, 0x23, - 0xe4, 0x33, 0x50, 0x2c, 0x33, 0x7d, 0xe9, 0x9c, 0xe1, 0xdc, 0x83, 0xf4, 0xf4, 0x31, 0x2c, 0x1e, - 0xcb, 0xac, 0x95, 0xd4, 0x45, 0xb8, 0x71, 0x91, 0xfb, 0x4b, 0x1d, 0x91, 0x05, 0x4e, 0xb4, 0xd5, - 0x85, 0x6a, 0xec, 0x84, 0x4b, 0x81, 0x76, 0x0f, 0x2a, 0xd1, 0xa9, 0x1d, 0xba, 0xfe, 0x88, 0x62, - 0xa0, 0xb1, 0x75, 0x3d, 0xf1, 0x59, 0x5f, 0xf3, 0x69, 0x2a, 0x83, 0xb1, 0x64, 0x1c, 0xb4, 0x57, - 0xe9, 0x6a, 0x42, 0x61, 0xe2, 0x0e, 0x48, 0xcf, 0x12, 0x47, 0x12, 0x39, 0x23, 0x57, 0x87, 0xfd, - 0x12, 0x47, 0x12, 0xed, 0x1b, 0xcb, 0x81, 0x3e, 0x95, 0x97, 0x38, 0xd1, 0x33, 0x81, 0x5d, 0x9a, - 0x0b, 0x6c, 0x2f, 0xf6, 0xfe, 0xff, 0x65, 0xb6, 0x9f, 0x26, 0x0e, 0xff, 0xbe, 0xa6, 0xb3, 0x7e, - 0x9b, 0x83, 0x6a, 0xdc, 0x9d, 0xe0, 0x19, 0xe9, 0x0e, 0x84, 0xaf, 0xdc, 0xa1, 0x2b, 0x42, 0xa3, - 0x3c, 0xc3, 0x61, 0xf7, 0xa0, 0x64, 0x2b, 0x15, 0xc6, 0x27, 0xcf, 0x9b, 0xd9, 0xd6, 0x66, 0x63, - 0x1b, 0x25, 0x1d, 0x5f, 0x85, 0x53, 0xae, 0x51, 0xcb, 0x1f, 0x01, 0xa4, 0x4c, 0xb4, 0xe7, 0x4c, - 0x4c, 0x8d, 0x56, 0x24, 0xd9, 0x0d, 0x28, 0x3d, 0xb3, 0xbd, 0x49, 0x5c, 0x46, 0xf4, 0xc7, 0x83, - 0xfc, 0x47, 0x39, 0xeb, 0xcf, 0x79, 0xa8, 0x98, 0x56, 0x87, 0xdd, 0x85, 0x0a, 0xb5, 0x3a, 0xc6, - 0xa2, 0xab, 0x6b, 0x46, 0x0c, 0x61, 0x9b, 0x49, 0x0f, 0x97, 0xb1, 0xd1, 0xa8, 0xd2, 0xbd, 0x9c, - 0xb1, 0x31, 0xed, 0xe8, 0x0a, 0x03, 0x31, 0x34, 0xcd, 0x5a, 0x83, 0x5a, 0x23, 0x31, 0x74, 0x7d, - 0x17, 0x5d, 0xce, 0x51, 0xc4, 0xee, 0xc6, 0xab, 0x2e, 0x92, 0xc6, 0x37, 0xb2, 0x1a, 0x2f, 0x2f, - 0xba, 0x0b, 0xf5, 0xcc, 0x34, 0x57, 0xac, 0xfa, 0xdd, 0xec, 0xaa, 0xcd, 0x94, 0xa4, 0x4e, 0x77, - 0x9a, 0xa9, 0x17, 0xfe, 0x07, 0xff, 0x7d, 0x08, 0x90, 0xaa, 0xfc, 0xee, 0x35, 0xd7, 0xfa, 0x53, - 0x01, 0xa0, 0x17, 0xe0, 0xc1, 0x3d, 0xb0, 0xa9, 0xd5, 0x58, 0x74, 0x47, 0xbe, 0x0c, 0xc5, 0x53, - 0xaa, 0x4d, 0x34, 0xbe, 0xca, 0xeb, 0x9a, 0xa7, 0x6b, 0xc0, 0x36, 0xd4, 0x07, 0x22, 0x72, 0x42, - 0x97, 0x62, 0xd4, 0x38, 0xfd, 0x16, 0xae, 0x29, 0xd5, 0xb3, 0xd1, 0x4e, 0x11, 0xda, 0x57, 0xd9, - 0x31, 0x6c, 0x0b, 0x16, 0xc5, 0x45, 0x20, 0x43, 0x65, 0x66, 0xd1, 0x1d, 0xf1, 0x35, 0xdd, 0x5b, - 0x23, 0x5f, 0xd7, 0x9e, 0xba, 0x48, 0x3f, 0x98, 0x0d, 0x45, 0xc7, 0x0e, 0x22, 0xd3, 0x87, 0xb4, - 0xe6, 0xe6, 0xdb, 0xb5, 0x03, 0xed, 0xb4, 0x9d, 0x0f, 0x70, 0xad, 0xbf, 0xfe, 0xdb, 0xad, 0x3b, - 0x99, 0xe6, 0x6d, 0x2c, 0x4f, 0xa6, 0x9b, 0x14, 0x2f, 0x67, 0xae, 0xda, 0x9c, 0x28, 0xd7, 0xdb, - 0xb4, 0x03, 0x17, 0xd5, 0xe1, 0xc0, 0x6e, 0x9b, 0x93, 0x6a, 0xf6, 0x11, 0x34, 0x82, 0x50, 0x8e, - 0x42, 0x11, 0x45, 0x4f, 0xe9, 0x28, 0x37, 0x2d, 0xf6, 0x6b, 0xa6, 0xe5, 0x20, 0xc9, 0x27, 0x28, - 0xe0, 0x4b, 0x41, 0xf6, 0x73, 0xf9, 0x27, 0xd0, 0x9c, 0x5f, 0xf1, 0xab, 0xec, 0xde, 0xf2, 0x7d, - 0xa8, 0x25, 0x2b, 0x78, 0xd9, 0xc0, 0x6a, 0x76, 0xdb, 0xff, 0x98, 0x83, 0xb2, 0xce, 0x47, 0x76, - 0x1f, 0x6a, 0x9e, 0x74, 0x6c, 0x34, 0x20, 0xbe, 0xce, 0xbc, 0x95, 0xa6, 0xeb, 0xc6, 0xa3, 0x58, - 0xa6, 0xf7, 0x23, 0xc5, 0x62, 0x78, 0xba, 0xfe, 0x50, 0xc6, 0xf9, 0xd3, 0x48, 0x07, 0x75, 0xfd, - 0xa1, 0xe4, 0x5a, 0xb8, 0xfc, 0x10, 0x1a, 0xb3, 0x2a, 0xae, 0xb0, 0xf3, 0x9d, 0xd9, 0x40, 0xa7, - 0x23, 0x2c, 0x19, 0x94, 0x35, 0xfb, 0x3e, 0xd4, 0x12, 0x3e, 0x5b, 0xbf, 0x6c, 0xf8, 0x62, 0x76, - 0x64, 0xc6, 0x56, 0xeb, 0x37, 0x39, 0x80, 0xd4, 0x36, 0x2c, 0x9d, 0x78, 0x71, 0xf2, 0xd3, 0x96, - 0x27, 0xf9, 0xa6, 0x8e, 0xc1, 0x56, 0x36, 0xd9, 0xb2, 0xc8, 0x89, 0x66, 0x1b, 0x00, 0x83, 0x24, - 0xd7, 0x5f, 0x50, 0x01, 0x32, 0x08, 0xd4, 0xef, 0xd9, 0xfe, 0x68, 0x62, 0x8f, 0x84, 0xe9, 0x4b, - 0x93, 0x6f, 0xab, 0x07, 0xd5, 0xd8, 0x42, 0xb6, 0x0a, 0xf5, 0xc8, 0x58, 0x85, 0xbd, 0x3f, 0x9a, - 0x52, 0xe2, 0x59, 0x16, 0xf6, 0xf0, 0xa1, 0xed, 0x8f, 0xc4, 0x4c, 0x0f, 0xcf, 0x91, 0xc3, 0x8d, - 0xc0, 0xfa, 0x0c, 0x4a, 0xc4, 0xc0, 0xec, 0x8d, 0x94, 0x1d, 0x2a, 0x73, 0x1d, 0xd0, 0x1d, 0xaf, - 0x8c, 0xc8, 0xa4, 0x9d, 0x22, 0xc6, 0x37, 0xd7, 0x00, 0xf6, 0x2e, 0xf6, 0xd5, 0x03, 0xe3, 0xee, - 0xab, 0x70, 0x28, 0xb6, 0x3e, 0x86, 0x6a, 0xcc, 0x46, 0xaf, 0x78, 0xae, 0x2f, 0x8c, 0x89, 0x44, - 0xe3, 0x35, 0xca, 0x39, 0xb5, 0x43, 0xdb, 0x51, 0x42, 0x37, 0x5e, 0x25, 0x9e, 0x32, 0xac, 0x77, - 0xa0, 0x9e, 0x49, 0x4a, 0x8c, 0xc5, 0x27, 0xb4, 0xc7, 0xba, 0x34, 0xe8, 0x0f, 0xeb, 0x13, 0x58, - 0x9a, 0x49, 0x10, 0x3c, 0xad, 0xdc, 0x41, 0x7c, 0x5a, 0xe9, 0x93, 0xe8, 0x52, 0xff, 0xc8, 0xa0, - 0x78, 0x2e, 0xec, 0x33, 0xd3, 0x3b, 0x12, 0x6d, 0xfd, 0x01, 0x6f, 0x8b, 0x71, 0x4f, 0xff, 0x43, - 0x80, 0x53, 0xa5, 0x82, 0xa7, 0xd4, 0xe4, 0x1b, 0x65, 0x35, 0xe4, 0x10, 0x82, 0xdd, 0x82, 0x3a, - 0x7e, 0x44, 0x46, 0xae, 0x55, 0xd3, 0x88, 0x48, 0x03, 0x7e, 0x00, 0xb5, 0x61, 0x32, 0xbc, 0x60, - 0xe2, 0x23, 0x1e, 0xfd, 0x16, 0x54, 0x7d, 0x69, 0x64, 0x7a, 0x6f, 0x2b, 0xbe, 0x4c, 0xc6, 0xd9, - 0x9e, 0x67, 0x64, 0x25, 0x3d, 0xce, 0xf6, 0x3c, 0x12, 0x5a, 0x77, 0xe0, 0xb5, 0x4b, 0xf7, 0x5e, - 0xf6, 0x06, 0x94, 0x87, 0xae, 0xa7, 0xe8, 0xc4, 0xc2, 0x3b, 0x8e, 0xf9, 0xb2, 0xfe, 0x9d, 0x03, - 0x48, 0x63, 0x0b, 0x53, 0x06, 0x8f, 0x1e, 0xc4, 0x2c, 0xea, 0xa3, 0xc6, 0x83, 0xea, 0xd8, 0x14, - 0x31, 0x13, 0x19, 0x37, 0x67, 0xe3, 0x71, 0x23, 0xae, 0x71, 0xba, 0xbc, 0x6d, 0x99, 0xf2, 0xf6, - 0x2a, 0x77, 0xd3, 0x64, 0x06, 0x6a, 0x1d, 0xb3, 0x4f, 0x15, 0x90, 0xe6, 0x3a, 0x37, 0x92, 0xe5, - 0x87, 0xb0, 0x34, 0x33, 0xe5, 0x77, 0x3c, 0xd0, 0xd2, 0x62, 0x9c, 0x4d, 0xf4, 0x2d, 0x28, 0xeb, - 0x37, 0x0e, 0xb6, 0x06, 0x15, 0xdb, 0xd1, 0x39, 0x9e, 0xa9, 0x33, 0x28, 0xdc, 0x26, 0x36, 0x8f, - 0xc5, 0xd6, 0x5f, 0xf2, 0x00, 0x29, 0xff, 0x15, 0xee, 0x0f, 0x0f, 0xa0, 0x11, 0x09, 0x47, 0xfa, - 0x03, 0x3b, 0x9c, 0x92, 0xd4, 0x5c, 0xc2, 0xaf, 0x1a, 0x32, 0x87, 0xcc, 0xdc, 0x25, 0x0a, 0x2f, - 0xbf, 0x4b, 0xac, 0x41, 0xd1, 0x91, 0xc1, 0xd4, 0x9c, 0x5b, 0x6c, 0x76, 0x21, 0xbb, 0x32, 0x98, - 0xee, 0x2f, 0x70, 0x42, 0xb0, 0x0d, 0x28, 0x8f, 0xcf, 0xe8, 0xd5, 0x47, 0xdf, 0x5e, 0x6f, 0xcc, - 0x62, 0x1f, 0x9f, 0x21, 0xbd, 0xbf, 0xc0, 0x0d, 0x8a, 0xdd, 0x81, 0xd2, 0xf8, 0x6c, 0xe0, 0x86, - 0xe6, 0xe4, 0xb9, 0x3e, 0x0f, 0x6f, 0xbb, 0x21, 0x3d, 0xf2, 0x20, 0x86, 0x59, 0x90, 0x0f, 0xc7, - 0xe6, 0x89, 0xa7, 0x39, 0xe7, 0xcd, 0xf1, 0xfe, 0x02, 0xcf, 0x87, 0xe3, 0x9d, 0x2a, 0x94, 0xb5, - 0x5f, 0xad, 0x7f, 0x15, 0xa0, 0x31, 0x6b, 0x25, 0xee, 0x6c, 0x14, 0x3a, 0xf1, 0xce, 0x46, 0xa1, - 0x93, 0x5c, 0xb3, 0xf2, 0x99, 0x6b, 0x96, 0x05, 0x25, 0x79, 0xee, 0x8b, 0x30, 0xfb, 0xbc, 0xb5, - 0x7b, 0x2a, 0xcf, 0x7d, 0x6c, 0xc4, 0xb5, 0x68, 0xa6, 0xd1, 0x2c, 0x99, 0xbe, 0xf6, 0x5d, 0x58, - 0x1a, 0x4a, 0xcf, 0x93, 0xe7, 0xfd, 0xe9, 0xd8, 0x73, 0xfd, 0x33, 0xd3, 0xdc, 0xce, 0x32, 0xd9, - 0x1a, 0x5c, 0x1b, 0xb8, 0x21, 0x9a, 0x63, 0xee, 0x1d, 0x11, 0xad, 0xbd, 0xca, 0xe7, 0xd9, 0xec, - 0x53, 0x58, 0xb5, 0x95, 0x12, 0xe3, 0x40, 0x1d, 0xfb, 0x81, 0xed, 0x9c, 0xb5, 0xa5, 0x43, 0x59, - 0x38, 0x0e, 0x6c, 0xe5, 0x9e, 0xb8, 0x9e, 0xab, 0xa6, 0xe4, 0x8c, 0x2a, 0x7f, 0x29, 0x8e, 0xbd, - 0x07, 0x0d, 0x27, 0x14, 0xb6, 0x12, 0x6d, 0x11, 0xa9, 0x43, 0x5b, 0x9d, 0xb6, 0xaa, 0x34, 0x72, - 0x8e, 0x8b, 0x6b, 0xb0, 0xd1, 0xda, 0xcf, 0x5c, 0x6f, 0xe0, 0xe0, 0x85, 0xb9, 0xa6, 0xd7, 0x30, - 0xc3, 0x64, 0x1b, 0xc0, 0x88, 0xd1, 0x19, 0x07, 0x6a, 0x9a, 0x40, 0x81, 0xa0, 0x57, 0x48, 0xb0, - 0xe0, 0x2a, 0x77, 0x2c, 0x22, 0x65, 0x8f, 0x03, 0x7a, 0x0b, 0x28, 0xf0, 0x94, 0xc1, 0x6e, 0x43, - 0xd3, 0xf5, 0x1d, 0x6f, 0x32, 0x10, 0x4f, 0x03, 0x5c, 0x48, 0xe8, 0x47, 0xad, 0x45, 0xaa, 0x2a, - 0xd7, 0x0c, 0xff, 0xd0, 0xb0, 0x11, 0x2a, 0x2e, 0xe6, 0xa0, 0x4b, 0x1a, 0x6a, 0xf8, 0x31, 0xd4, - 0xfa, 0x3c, 0x07, 0xcd, 0xf9, 0xc0, 0xc3, 0x6d, 0x0b, 0x70, 0xf1, 0xe6, 0xb9, 0x00, 0xe9, 0x64, - 0x2b, 0xf3, 0x99, 0xad, 0x8c, 0xcf, 0xd2, 0x42, 0xe6, 0x2c, 0x4d, 0xc2, 0xa2, 0xf8, 0xe2, 0xb0, - 0x98, 0x59, 0x68, 0x69, 0x6e, 0xa1, 0xd6, 0xef, 0x73, 0x70, 0x6d, 0x2e, 0xb8, 0xbf, 0xb3, 0x45, - 0xab, 0x50, 0x1f, 0xdb, 0x67, 0x42, 0x3f, 0xb6, 0x44, 0xe6, 0x08, 0xc9, 0xb2, 0xbe, 0x07, 0xfb, - 0x7c, 0x58, 0xcc, 0x66, 0xd4, 0x95, 0xb6, 0xc5, 0x01, 0x72, 0x20, 0xd5, 0x9e, 0x9c, 0x98, 0xb3, - 0x38, 0x0e, 0x90, 0x98, 0x79, 0x39, 0x8c, 0x0a, 0x57, 0x84, 0x91, 0x75, 0x00, 0xd5, 0xd8, 0x40, - 0x76, 0xcb, 0xbc, 0x86, 0xe5, 0xd2, 0x6b, 0xf6, 0x71, 0x24, 0x42, 0xb4, 0x5d, 0x3f, 0x8d, 0xbd, - 0x0d, 0x25, 0xdd, 0xa3, 0xe6, 0x2f, 0x23, 0xb4, 0xc4, 0xea, 0x43, 0xc5, 0x70, 0xd8, 0x3a, 0x94, - 0x4f, 0xa6, 0xc9, 0xcb, 0x90, 0x29, 0x17, 0xf8, 0x3d, 0x30, 0x08, 0xac, 0x41, 0x1a, 0xc1, 0x6e, - 0x40, 0xf1, 0x64, 0xda, 0x6d, 0xeb, 0x9b, 0x25, 0x56, 0x32, 0xfc, 0xda, 0x29, 0x6b, 0x83, 0xac, - 0x47, 0xb0, 0x98, 0x1d, 0x97, 0x1c, 0xec, 0xb9, 0xcc, 0xc1, 0x9e, 0x94, 0xec, 0xfc, 0xcb, 0xae, - 0x1f, 0x1f, 0x02, 0xd0, 0xdb, 0xf5, 0xab, 0x5e, 0x5b, 0xde, 0x87, 0x8a, 0x79, 0xf3, 0x66, 0xef, - 0xcd, 0xbd, 0xe1, 0x37, 0x92, 0x07, 0xf1, 0x99, 0x87, 0x7c, 0xeb, 0x01, 0x36, 0xb0, 0xe7, 0x22, - 0x6c, 0xbb, 0xc3, 0xe1, 0xab, 0x4e, 0xf7, 0x00, 0x1a, 0xc7, 0x41, 0xf0, 0xdf, 0x8d, 0xfd, 0x05, - 0x94, 0xf5, 0xd3, 0x3b, 0x8e, 0xf1, 0xd0, 0x02, 0xb3, 0x07, 0x4c, 0x37, 0xb9, 0x59, 0x93, 0xb8, - 0x06, 0x20, 0x72, 0x82, 0xf3, 0x99, 0xcd, 0x25, 0xe4, 0xac, 0x01, 0x5c, 0x03, 0xd6, 0xd7, 0xa0, - 0x62, 0x5e, 0x79, 0x59, 0x0d, 0x4a, 0xc7, 0x07, 0xfd, 0xce, 0x51, 0x73, 0x81, 0x55, 0xa1, 0xb8, - 0xdf, 0xeb, 0x1f, 0x35, 0x73, 0x48, 0x1d, 0xf4, 0x0e, 0x3a, 0xcd, 0xfc, 0xfa, 0x6d, 0x58, 0xcc, - 0xbe, 0xf3, 0xb2, 0x3a, 0x54, 0xfa, 0xdb, 0x07, 0xed, 0x9d, 0xde, 0xcf, 0x9a, 0x0b, 0x6c, 0x11, - 0xaa, 0xdd, 0x83, 0x7e, 0x67, 0xf7, 0x98, 0x77, 0x9a, 0xb9, 0xf5, 0x9f, 0x43, 0x2d, 0x79, 0xfa, - 0x42, 0x0d, 0x3b, 0xdd, 0x83, 0x76, 0x73, 0x81, 0x01, 0x94, 0xfb, 0x9d, 0x5d, 0xde, 0x41, 0xbd, - 0x15, 0x28, 0xf4, 0xfb, 0xfb, 0xcd, 0x3c, 0xce, 0xba, 0xbb, 0xbd, 0xbb, 0xdf, 0x69, 0x16, 0x90, - 0x3c, 0x7a, 0x7c, 0xb8, 0xd7, 0x6f, 0x16, 0xd9, 0x12, 0xd4, 0xd0, 0x80, 0xa7, 0x34, 0x72, 0x40, - 0x23, 0x7b, 0xbb, 0x0f, 0x3b, 0x47, 0x4d, 0xb1, 0xfe, 0x3e, 0xbc, 0x76, 0xe9, 0x99, 0x09, 0x8d, - 0x69, 0x77, 0xf6, 0xb6, 0x8f, 0x1f, 0xa1, 0xf5, 0x65, 0xc8, 0xf7, 0x0e, 0xf4, 0x1c, 0xbd, 0xbd, - 0xbd, 0x66, 0x7e, 0xfd, 0x43, 0xb8, 0x36, 0xf7, 0x00, 0x44, 0x1a, 0xf7, 0xb7, 0x79, 0x07, 0xed, - 0xaa, 0x43, 0xe5, 0x90, 0x77, 0x9f, 0x6c, 0x1f, 0x75, 0x9a, 0x39, 0x14, 0x3c, 0xc2, 0xa9, 0xda, - 0xcd, 0xfc, 0xce, 0xcd, 0x2f, 0x9e, 0xaf, 0xe4, 0xbe, 0x7a, 0xbe, 0x92, 0xfb, 0xfa, 0xf9, 0x4a, - 0xee, 0xef, 0xcf, 0x57, 0x72, 0x9f, 0x7f, 0xbb, 0xb2, 0xf0, 0xd5, 0xb7, 0x2b, 0x0b, 0x5f, 0x7f, - 0xbb, 0xb2, 0x70, 0x52, 0xa6, 0xbf, 0x82, 0x3e, 0xf8, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x90, - 0x66, 0xbb, 0x95, 0x4a, 0x1a, 0x00, 0x00, -======= - // 2656 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0xcf, 0x6f, 0x1b, 0xc7, - 0xf5, 0x17, 0x7f, 0x93, 0x8f, 0x14, 0xcd, 0x8c, 0x9d, 0x84, 0xd1, 0xd7, 0x5f, 0x59, 0xd9, 0xe4, - 0x1b, 0xc8, 0xb2, 0x2d, 0x21, 0x0a, 0x10, 0xe7, 0x6b, 0x04, 0x45, 0x25, 0x91, 0x8a, 0x18, 0xdb, - 0xa2, 0x30, 0xb4, 0x9c, 0x1e, 0x0a, 0x18, 0xab, 0xe5, 0x90, 0x5a, 0x68, 0xb9, 0xbb, 0x98, 0x1d, - 0x5a, 0x62, 0x0f, 0x3d, 0xf4, 0xd4, 0x63, 0x80, 0x02, 0xbd, 0x15, 0xfd, 0x27, 0x7a, 0x6c, 0x6f, - 0x3d, 0x04, 0xc8, 0x25, 0x40, 0x7b, 0x08, 0x7a, 0x48, 0x0b, 0xe7, 0xd2, 0x7f, 0xa2, 0x40, 0xf1, - 0xde, 0xcc, 0xfe, 0x20, 0x25, 0xc3, 0x71, 0x5b, 0xf4, 0xc4, 0x99, 0xcf, 0xfb, 0xcc, 0x9b, 0x37, - 0x6f, 0xde, 0x9b, 0x79, 0x3b, 0x84, 0x5a, 0x10, 0x46, 0x9b, 0xa1, 0x0c, 0x54, 0xc0, 0xf2, 0xe1, - 0xc9, 0xca, 0xbd, 0xb1, 0xab, 0x4e, 0xa7, 0x27, 0x9b, 0x4e, 0x30, 0xd9, 0x1a, 0x07, 0xe3, 0x60, - 0x8b, 0x44, 0x27, 0xd3, 0x11, 0xf5, 0xa8, 0x43, 0x2d, 0x3d, 0xc4, 0xfa, 0x7b, 0x1e, 0xf2, 0xfd, - 0x90, 0xbd, 0x0b, 0x65, 0xd7, 0x0f, 0xa7, 0x2a, 0x6a, 0xe7, 0xd6, 0x0a, 0xeb, 0xf5, 0xed, 0xda, - 0x66, 0x78, 0xb2, 0xd9, 0x43, 0x84, 0x1b, 0x01, 0x5b, 0x83, 0xa2, 0xb8, 0x10, 0x4e, 0x3b, 0xbf, - 0x96, 0x5b, 0xaf, 0x6f, 0x03, 0x12, 0xba, 0x17, 0xc2, 0xe9, 0x87, 0x07, 0x4b, 0x9c, 0x24, 0xec, - 0x03, 0x28, 0x47, 0xc1, 0x54, 0x3a, 0xa2, 0x5d, 0x20, 0x4e, 0x03, 0x39, 0x03, 0x42, 0x88, 0x65, - 0xa4, 0xa8, 0x69, 0xe4, 0x7a, 0xa2, 0x5d, 0x4c, 0x35, 0xed, 0xbb, 0x9e, 0xe6, 0x90, 0x84, 0xbd, - 0x07, 0xa5, 0x93, 0xa9, 0xeb, 0x0d, 0xdb, 0x25, 0xa2, 0xd4, 0x91, 0xb2, 0x8b, 0x00, 0x71, 0xb4, - 0x0c, 0x49, 0x13, 0x21, 0xc7, 0xa2, 0x5d, 0x4e, 0x49, 0x8f, 0x11, 0xd0, 0x24, 0x92, 0xe1, 0x5c, - 0x43, 0x77, 0x34, 0x6a, 0x57, 0xd2, 0xb9, 0x3a, 0xee, 0x68, 0xa4, 0xe7, 0x42, 0x09, 0x5b, 0x87, - 0x6a, 0xe8, 0xd9, 0x6a, 0x14, 0xc8, 0x49, 0x1b, 0x52, 0xbb, 0x8f, 0x0c, 0xc6, 0x13, 0x29, 0xbb, - 0x0f, 0x75, 0x27, 0xf0, 0x23, 0x25, 0x6d, 0xd7, 0x57, 0x51, 0xbb, 0x4e, 0xe4, 0x37, 0x91, 0xfc, - 0x45, 0x20, 0xcf, 0x84, 0xdc, 0x4b, 0x85, 0x3c, 0xcb, 0xdc, 0x2d, 0x42, 0x3e, 0x08, 0xad, 0x5f, - 0xe7, 0xa0, 0x1a, 0x6b, 0x65, 0x16, 0x34, 0x76, 0xa4, 0x73, 0xea, 0x2a, 0xe1, 0xa8, 0xa9, 0x14, - 0xed, 0xdc, 0x5a, 0x6e, 0xbd, 0xc6, 0xe7, 0x30, 0xd6, 0x84, 0x7c, 0x7f, 0x40, 0xfe, 0xae, 0xf1, - 0x7c, 0x7f, 0xc0, 0xda, 0x50, 0x79, 0x6a, 0x4b, 0xd7, 0xf6, 0x15, 0x39, 0xb8, 0xc6, 0xe3, 0x2e, - 0xbb, 0x09, 0xb5, 0xfe, 0xe0, 0xa9, 0x90, 0x91, 0x1b, 0xf8, 0xe4, 0xd6, 0x1a, 0x4f, 0x01, 0xb6, - 0x0a, 0xd0, 0x1f, 0xec, 0x0b, 0x1b, 0x95, 0x46, 0xed, 0xd2, 0x5a, 0x61, 0xbd, 0xc6, 0x33, 0x88, - 0xf5, 0x73, 0x28, 0xd1, 0x56, 0xb3, 0xcf, 0xa1, 0x3c, 0x74, 0xc7, 0x22, 0x52, 0xda, 0x9c, 0xdd, - 0xed, 0xaf, 0xbe, 0xbb, 0xb5, 0xf4, 0x97, 0xef, 0x6e, 0x6d, 0x64, 0x62, 0x2a, 0x08, 0x85, 0xef, - 0x04, 0xbe, 0xb2, 0x5d, 0x5f, 0xc8, 0x68, 0x6b, 0x1c, 0xdc, 0xd3, 0x43, 0x36, 0x3b, 0xf4, 0xc3, - 0x8d, 0x06, 0x76, 0x1b, 0x4a, 0xae, 0x3f, 0x14, 0x17, 0x64, 0x7f, 0x61, 0xf7, 0xba, 0x51, 0x55, - 0xef, 0x4f, 0x55, 0x38, 0x55, 0x3d, 0x14, 0x71, 0xcd, 0xb0, 0xbe, 0xce, 0x41, 0x59, 0x87, 0x12, - 0xbb, 0x09, 0xc5, 0x89, 0x50, 0x36, 0xcd, 0x5f, 0xdf, 0xae, 0xea, 0x2d, 0x55, 0x36, 0x27, 0x14, - 0xa3, 0x74, 0x12, 0x4c, 0xd1, 0xf7, 0xf9, 0x34, 0x4a, 0x1f, 0x23, 0xc2, 0x8d, 0x80, 0xfd, 0x1f, - 0x54, 0x7c, 0xa1, 0xce, 0x03, 0x79, 0x46, 0x3e, 0x6a, 0xea, 0xb0, 0x38, 0x14, 0xea, 0x71, 0x30, - 0x14, 0x3c, 0x96, 0xb1, 0xbb, 0x50, 0x8d, 0x84, 0x33, 0x95, 0xae, 0x9a, 0x91, 0xbf, 0x9a, 0xdb, - 0x2d, 0x0a, 0x56, 0x83, 0x11, 0x39, 0x61, 0xb0, 0x3b, 0x50, 0x8b, 0x84, 0x23, 0x85, 0x12, 0xfe, - 0x73, 0xf2, 0x5f, 0x7d, 0x7b, 0xd9, 0xd0, 0xa5, 0x50, 0x5d, 0xff, 0x39, 0x4f, 0xe5, 0xd6, 0xd7, - 0x79, 0x28, 0xa2, 0xcd, 0x8c, 0x41, 0xd1, 0x96, 0x63, 0x9d, 0x51, 0x35, 0x4e, 0x6d, 0xd6, 0x82, - 0x02, 0xea, 0xc8, 0x13, 0x84, 0x4d, 0x44, 0x9c, 0xf3, 0xa1, 0xd9, 0x50, 0x6c, 0xe2, 0xb8, 0x69, - 0x24, 0xa4, 0xd9, 0x47, 0x6a, 0xb3, 0xdb, 0x50, 0x0b, 0x65, 0x70, 0x31, 0x7b, 0xa6, 0x2d, 0x48, - 0xa3, 0x14, 0x41, 0x34, 0xa0, 0x1a, 0x9a, 0x16, 0xdb, 0x00, 0x10, 0x17, 0x4a, 0xda, 0x07, 0x41, - 0xa4, 0xa2, 0x76, 0x99, 0xac, 0xa5, 0xb8, 0x47, 0xa0, 0x77, 0xc4, 0x33, 0x52, 0xb6, 0x02, 0xd5, - 0xd3, 0x20, 0x52, 0xbe, 0x3d, 0x11, 0x94, 0x21, 0x35, 0x9e, 0xf4, 0x99, 0x05, 0xe5, 0xa9, 0xe7, - 0x4e, 0x5c, 0xd5, 0xae, 0xa5, 0x3a, 0x8e, 0x09, 0xe1, 0x46, 0x82, 0x51, 0xec, 0x8c, 0x65, 0x30, - 0x0d, 0x8f, 0x6c, 0x29, 0x7c, 0x45, 0xf9, 0x53, 0xe3, 0x73, 0x18, 0xfb, 0x14, 0xde, 0x91, 0x62, - 0x12, 0x3c, 0x17, 0xb4, 0x51, 0x03, 0x35, 0x3d, 0x89, 0x38, 0x3a, 0x36, 0x72, 0x9f, 0x0b, 0xca, - 0xa1, 0x2a, 0x7f, 0x39, 0xc1, 0xba, 0x0b, 0x65, 0x6d, 0x37, 0xba, 0x05, 0x5b, 0x26, 0x53, 0xa8, - 0x8d, 0x19, 0xd2, 0x3b, 0x8a, 0x33, 0xa4, 0x77, 0x64, 0x75, 0xa0, 0xac, 0x2d, 0x44, 0xf6, 0x21, - 0xae, 0xca, 0xb0, 0xb1, 0x8d, 0xd8, 0x20, 0x18, 0x29, 0x1d, 0x91, 0x9c, 0xda, 0xa4, 0xd5, 0x96, - 0xda, 0xff, 0x05, 0x4e, 0x6d, 0xeb, 0x21, 0xd4, 0x92, 0x9d, 0xa5, 0x29, 0x3a, 0x46, 0x4d, 0xbe, - 0xd7, 0xc1, 0x01, 0xe4, 0x2e, 0x3d, 0x29, 0xb5, 0xd1, 0x8d, 0x41, 0xa8, 0xdc, 0xc0, 0xb7, 0x3d, - 0x52, 0x54, 0xe5, 0x49, 0xdf, 0xfa, 0x53, 0x01, 0x4a, 0xb4, 0x30, 0xb6, 0x8e, 0x19, 0x11, 0x4e, - 0xf5, 0x0a, 0x0a, 0xbb, 0xcc, 0x64, 0x04, 0x50, 0xee, 0x25, 0x09, 0x81, 0x79, 0xb8, 0x82, 0xd1, - 0xe9, 0x09, 0x47, 0x05, 0xd2, 0xcc, 0x93, 0xf4, 0x71, 0xfe, 0x21, 0x66, 0xa8, 0x0e, 0x18, 0x6a, - 0xb3, 0x3b, 0x50, 0x0e, 0x28, 0xad, 0x28, 0x66, 0x5e, 0x92, 0x6c, 0x86, 0x82, 0xca, 0xa5, 0xb0, - 0x87, 0x81, 0xef, 0xcd, 0x28, 0x92, 0xaa, 0x3c, 0xe9, 0x63, 0xa0, 0x53, 0x1e, 0x3d, 0x99, 0x85, - 0xfa, 0x58, 0x6d, 0xea, 0x40, 0x7f, 0x1c, 0x83, 0x3c, 0x95, 0xe3, 0xc1, 0xf9, 0x64, 0x12, 0x8e, - 0xa2, 0x7e, 0xa8, 0xda, 0xd7, 0xd3, 0x90, 0x8c, 0x31, 0x9e, 0x48, 0x91, 0xe9, 0xd8, 0xce, 0xa9, - 0x40, 0xe6, 0x8d, 0x94, 0xb9, 0x67, 0x30, 0x9e, 0x48, 0xd3, 0x4c, 0x43, 0xea, 0x9b, 0x44, 0xcd, - 0x64, 0x1a, 0x72, 0x53, 0x39, 0x46, 0xe8, 0x60, 0x70, 0x80, 0xcc, 0xb7, 0xd2, 0xd3, 0x5d, 0x23, - 0xdc, 0x48, 0xf4, 0x6a, 0xa3, 0xa9, 0xa7, 0x7a, 0x9d, 0xf6, 0xdb, 0xda, 0x95, 0x71, 0x9f, 0xfd, - 0x3f, 0x34, 0xf0, 0x24, 0x13, 0xbe, 0x22, 0x4b, 0xda, 0x6d, 0x5a, 0xf0, 0x9b, 0xc9, 0x82, 0xf7, - 0x32, 0x42, 0x3e, 0x47, 0xb5, 0x56, 0xd3, 0xb5, 0xe3, 0x8e, 0x44, 0xee, 0xcf, 0x74, 0xa8, 0x15, - 0x38, 0xb5, 0xad, 0x1e, 0x54, 0xe3, 0xd5, 0x5d, 0x8a, 0xa0, 0x7b, 0x50, 0x89, 0x4e, 0x6d, 0xe9, - 0xfa, 0x63, 0xda, 0xdc, 0xe6, 0xf6, 0xf5, 0xc4, 0x19, 0x03, 0x8d, 0xe3, 0x02, 0x62, 0x8e, 0x15, - 0xc4, 0xd1, 0x78, 0x95, 0xae, 0x16, 0x14, 0xa6, 0xee, 0x90, 0xf4, 0x2c, 0x73, 0x6c, 0x22, 0x32, - 0x76, 0x75, 0x3c, 0x2f, 0x73, 0x6c, 0xa2, 0x7d, 0x93, 0x60, 0xa8, 0xaf, 0xdb, 0x65, 0x4e, 0xed, - 0xb9, 0x88, 0x2d, 0x2d, 0x44, 0xac, 0x17, 0xbb, 0xf5, 0xbf, 0x32, 0xdb, 0xaf, 0x72, 0x50, 0x8d, - 0x6b, 0x04, 0xbc, 0xa9, 0xdc, 0xa1, 0xf0, 0x95, 0x3b, 0x72, 0x85, 0x34, 0x13, 0x67, 0x10, 0x76, - 0x0f, 0x4a, 0xb6, 0x52, 0x32, 0x3e, 0xff, 0xdf, 0xce, 0x16, 0x18, 0x9b, 0x3b, 0x28, 0xe9, 0xfa, - 0x4a, 0xce, 0xb8, 0x66, 0xad, 0x7c, 0x02, 0x90, 0x82, 0x68, 0xeb, 0x99, 0x98, 0x19, 0xad, 0xd8, - 0x64, 0x37, 0xa0, 0xf4, 0xdc, 0xf6, 0xa6, 0x71, 0x32, 0xeb, 0xce, 0x83, 0xfc, 0x27, 0x39, 0xeb, - 0x0f, 0x79, 0xa8, 0x98, 0x82, 0x83, 0xdd, 0x85, 0x0a, 0x15, 0x1c, 0xc6, 0xa2, 0xab, 0x33, 0x37, - 0xa6, 0xb0, 0xad, 0xa4, 0x92, 0xca, 0xd8, 0x68, 0x54, 0xe9, 0x8a, 0xca, 0xd8, 0x98, 0xd6, 0x55, - 0x85, 0xa1, 0x18, 0x99, 0x92, 0xa9, 0x49, 0x05, 0x8a, 0x18, 0xb9, 0xbe, 0x8b, 0xfe, 0xe1, 0x28, - 0x62, 0x77, 0xe3, 0x55, 0x17, 0x49, 0xe3, 0x5b, 0x59, 0x8d, 0x97, 0x17, 0xdd, 0x83, 0x7a, 0x66, - 0x9a, 0x2b, 0x56, 0xfd, 0x7e, 0x76, 0xd5, 0x66, 0x4a, 0x52, 0xa7, 0xeb, 0xbd, 0xd4, 0x0b, 0xff, - 0x86, 0xff, 0x3e, 0x06, 0x48, 0x55, 0xfe, 0xf0, 0x93, 0xcf, 0xfa, 0x7d, 0x01, 0xa0, 0x1f, 0xe2, - 0xf5, 0x39, 0xb4, 0xe9, 0xc2, 0x6f, 0xb8, 0x63, 0x3f, 0x90, 0xe2, 0x19, 0x9d, 0x10, 0x34, 0xbe, - 0xca, 0xeb, 0x1a, 0xa3, 0x8c, 0x61, 0x3b, 0x50, 0x1f, 0x8a, 0xc8, 0x91, 0x2e, 0x05, 0x94, 0x71, - 0xfa, 0x2d, 0x5c, 0x53, 0xaa, 0x67, 0xb3, 0x93, 0x32, 0xb4, 0xaf, 0xb2, 0x63, 0xd8, 0x36, 0x34, - 0xc4, 0x45, 0x18, 0x48, 0x65, 0x66, 0xd1, 0x75, 0xe9, 0x35, 0x5d, 0xe1, 0x22, 0xae, 0x4f, 0x80, - 0xba, 0x48, 0x3b, 0xcc, 0x86, 0xa2, 0x63, 0x87, 0x91, 0xa9, 0x06, 0xda, 0x0b, 0xf3, 0xed, 0xd9, - 0xa1, 0x76, 0xda, 0xee, 0x47, 0xb8, 0xd6, 0x5f, 0xfc, 0xf5, 0xd6, 0x9d, 0x4c, 0x09, 0x35, 0x09, - 0x4e, 0x66, 0x5b, 0x14, 0x2f, 0x67, 0xae, 0xda, 0x9a, 0x2a, 0xd7, 0xdb, 0xb2, 0x43, 0x17, 0xd5, - 0xe1, 0xc0, 0x5e, 0x87, 0x93, 0x6a, 0xf6, 0x09, 0x34, 0x43, 0x19, 0x8c, 0xa5, 0x88, 0xa2, 0x67, - 0x74, 0xa1, 0x9a, 0x42, 0xf7, 0x0d, 0x73, 0xf1, 0x93, 0xe4, 0x33, 0x14, 0xf0, 0xe5, 0x30, 0xdb, - 0x5d, 0xf9, 0x11, 0xb4, 0x16, 0x57, 0xfc, 0x3a, 0xbb, 0xb7, 0x72, 0x1f, 0x6a, 0xc9, 0x0a, 0x5e, - 0x35, 0xb0, 0x9a, 0xdd, 0xf6, 0xdf, 0xe5, 0xa0, 0xac, 0xf3, 0x91, 0xdd, 0x87, 0x9a, 0x17, 0x38, - 0x36, 0x1a, 0x10, 0x7f, 0x54, 0xbc, 0x93, 0xa6, 0xeb, 0xe6, 0xa3, 0x58, 0xa6, 0xf7, 0x23, 0xe5, - 0x62, 0x78, 0xba, 0xfe, 0x28, 0x88, 0xf3, 0xa7, 0x99, 0x0e, 0xea, 0xf9, 0xa3, 0x80, 0x6b, 0xe1, - 0xca, 0x43, 0x68, 0xce, 0xab, 0xb8, 0xc2, 0xce, 0xf7, 0xe6, 0x03, 0x9d, 0x2e, 0x92, 0x64, 0x50, - 0xd6, 0xec, 0xfb, 0x50, 0x4b, 0x70, 0xb6, 0x71, 0xd9, 0xf0, 0x46, 0x76, 0x64, 0xc6, 0x56, 0xeb, - 0x97, 0x39, 0x80, 0xd4, 0x36, 0x3c, 0xe7, 0xf0, 0xf3, 0xc5, 0x4f, 0x0b, 0x8f, 0xa4, 0x4f, 0xf7, - 0xb6, 0xad, 0x6c, 0xb2, 0xa5, 0xc1, 0xa9, 0xcd, 0x36, 0x01, 0x86, 0x49, 0xae, 0xbf, 0xe4, 0x04, - 0xc8, 0x30, 0x50, 0xbf, 0x67, 0xfb, 0xe3, 0xa9, 0x3d, 0x16, 0xa6, 0x3a, 0x4c, 0xfa, 0x56, 0x1f, - 0xaa, 0xb1, 0x85, 0x6c, 0x0d, 0xea, 0x91, 0xb1, 0x0a, 0x2b, 0x70, 0x34, 0xa5, 0xc4, 0xb3, 0x10, - 0x56, 0xd2, 0xd2, 0xf6, 0xc7, 0x62, 0xae, 0x92, 0xe6, 0x88, 0x70, 0x23, 0xb0, 0xbe, 0x80, 0x12, - 0x01, 0x98, 0xbd, 0x91, 0xb2, 0xa5, 0x32, 0x45, 0xb9, 0xae, 0x3b, 0x83, 0x88, 0x4c, 0xda, 0x2d, - 0x62, 0x7c, 0x73, 0x4d, 0x60, 0xef, 0x63, 0x75, 0x3b, 0x34, 0xee, 0xbe, 0x8a, 0x87, 0x62, 0xeb, - 0x53, 0xa8, 0xc6, 0x30, 0x7a, 0xc5, 0x73, 0x7d, 0x61, 0x4c, 0xa4, 0x36, 0x7e, 0xcc, 0x38, 0xa7, - 0xb6, 0xb4, 0x1d, 0x25, 0x74, 0xf9, 0x53, 0xe2, 0x29, 0x60, 0xbd, 0x07, 0xf5, 0x4c, 0x52, 0x62, - 0x2c, 0x3e, 0xa5, 0x3d, 0xd6, 0x47, 0x83, 0xee, 0x58, 0x9f, 0xc1, 0xf2, 0x5c, 0x82, 0xe0, 0x4d, - 0xe6, 0x0e, 0xe3, 0x9b, 0x4c, 0xdf, 0x52, 0x97, 0xaa, 0x38, 0x06, 0xc5, 0x73, 0x61, 0x9f, 0x99, - 0x0a, 0x8e, 0xda, 0xd6, 0x6f, 0xf1, 0x9b, 0x2d, 0xae, 0xac, 0xff, 0x17, 0xe0, 0x54, 0xa9, 0xf0, - 0x19, 0x95, 0xda, 0x46, 0x59, 0x0d, 0x11, 0x62, 0xb0, 0x5b, 0x50, 0xc7, 0x4e, 0x64, 0xe4, 0x5a, - 0x35, 0x8d, 0x88, 0x34, 0xe1, 0x7f, 0xa0, 0x36, 0x4a, 0x86, 0x17, 0x4c, 0x7c, 0xc4, 0xa3, 0xdf, - 0x81, 0xaa, 0x1f, 0x18, 0x99, 0xde, 0xdb, 0x8a, 0x1f, 0x24, 0xe3, 0x6c, 0xcf, 0x33, 0xb2, 0x92, - 0x1e, 0x67, 0x7b, 0x1e, 0x09, 0xad, 0x3b, 0xf0, 0xc6, 0xa5, 0xaf, 0x4f, 0xf6, 0x16, 0x94, 0x47, - 0xae, 0xa7, 0xe8, 0xc6, 0xc2, 0x2f, 0x0d, 0xd3, 0xb3, 0xfe, 0x91, 0x03, 0x48, 0x63, 0x0b, 0x53, - 0x06, 0xaf, 0x1e, 0xe4, 0x34, 0xf4, 0x55, 0xe3, 0x41, 0x75, 0x62, 0x0e, 0x31, 0x13, 0x19, 0x37, - 0xe7, 0xe3, 0x71, 0x33, 0x3e, 0xe3, 0xf4, 0xf1, 0xb6, 0x6d, 0x8e, 0xb7, 0xd7, 0xf9, 0x42, 0x4c, - 0x66, 0xa0, 0x02, 0x2e, 0xfb, 0x60, 0x00, 0x69, 0xae, 0x73, 0x23, 0x59, 0x79, 0x08, 0xcb, 0x73, - 0x53, 0xfe, 0xc0, 0x0b, 0x2d, 0x3d, 0x8c, 0xb3, 0x89, 0xbe, 0x0d, 0x65, 0xfd, 0xd2, 0xc0, 0xd6, - 0xa1, 0x62, 0x3b, 0x3a, 0xc7, 0x33, 0xe7, 0x0c, 0x0a, 0x77, 0x08, 0xe6, 0xb1, 0xd8, 0xfa, 0x73, - 0x1e, 0x20, 0xc5, 0x5f, 0xa3, 0x8a, 0x7f, 0x00, 0xcd, 0x48, 0x38, 0x81, 0x3f, 0xb4, 0xe5, 0x8c, - 0xa4, 0xe6, 0x53, 0xf8, 0xaa, 0x21, 0x0b, 0xcc, 0x4c, 0x45, 0x5f, 0x78, 0x75, 0x45, 0xbf, 0x0e, - 0x45, 0x27, 0x08, 0x67, 0xe6, 0xde, 0x62, 0xf3, 0x0b, 0xd9, 0x0b, 0xc2, 0xd9, 0xc1, 0x12, 0x27, - 0x06, 0xdb, 0x84, 0xf2, 0xe4, 0x8c, 0xde, 0x5e, 0xf4, 0x37, 0xe4, 0x8d, 0x79, 0xee, 0xe3, 0x33, - 0x6c, 0x1f, 0x2c, 0x71, 0xc3, 0x62, 0x77, 0xa0, 0x34, 0x39, 0x1b, 0xba, 0xd2, 0xdc, 0x3c, 0xd7, - 0x17, 0xe9, 0x1d, 0x57, 0xd2, 0x53, 0x0b, 0x72, 0x98, 0x05, 0x79, 0x39, 0x31, 0x0f, 0x2d, 0xad, - 0x05, 0x6f, 0x4e, 0x0e, 0x96, 0x78, 0x5e, 0x4e, 0x76, 0xab, 0x50, 0xd6, 0x7e, 0xb5, 0xfe, 0x58, - 0x84, 0xe6, 0xbc, 0x95, 0xb8, 0xb3, 0x91, 0x74, 0xe2, 0x9d, 0x8d, 0xa4, 0x93, 0x7c, 0xec, 0xe4, - 0x33, 0x1f, 0x3b, 0x16, 0x94, 0x82, 0x73, 0x5f, 0xc8, 0xec, 0x23, 0xd3, 0xde, 0x69, 0x70, 0xee, - 0x63, 0xd5, 0xac, 0x45, 0x73, 0x45, 0x68, 0xc9, 0x14, 0xa1, 0xef, 0xc3, 0xf2, 0x28, 0xf0, 0xbc, - 0xe0, 0x7c, 0x30, 0x9b, 0x78, 0xae, 0x7f, 0x66, 0x2a, 0xd1, 0x79, 0x90, 0xad, 0xc3, 0xb5, 0xa1, - 0x2b, 0xd1, 0x1c, 0x53, 0xfd, 0x47, 0xb4, 0xf6, 0x2a, 0x5f, 0x84, 0xd9, 0xe7, 0xb0, 0x66, 0x2b, - 0x25, 0x26, 0xa1, 0x3a, 0xf6, 0x43, 0xdb, 0x39, 0xeb, 0x04, 0x0e, 0x65, 0xe1, 0x24, 0xb4, 0x95, - 0x7b, 0xe2, 0x7a, 0xae, 0x9a, 0x91, 0x33, 0xaa, 0xfc, 0x95, 0x3c, 0xf6, 0x01, 0x34, 0x1d, 0x29, - 0x6c, 0x25, 0x3a, 0x22, 0x52, 0x47, 0xb6, 0x3a, 0x6d, 0x57, 0x69, 0xe4, 0x02, 0x8a, 0x6b, 0xb0, - 0xd1, 0xda, 0x2f, 0x5c, 0x6f, 0xe8, 0xe0, 0x67, 0x6b, 0x4d, 0xaf, 0x61, 0x0e, 0x64, 0x9b, 0xc0, - 0x08, 0xe8, 0x4e, 0x42, 0x35, 0x4b, 0xa8, 0x40, 0xd4, 0x2b, 0x24, 0x78, 0xe0, 0x2a, 0x77, 0x22, - 0x22, 0x65, 0x4f, 0x42, 0xfa, 0x22, 0x2f, 0xf0, 0x14, 0x60, 0xb7, 0xa1, 0xe5, 0xfa, 0x8e, 0x37, - 0x1d, 0x8a, 0x67, 0x21, 0x2e, 0x44, 0xfa, 0x51, 0xbb, 0x41, 0xa7, 0xca, 0x35, 0x83, 0x1f, 0x19, - 0x18, 0xa9, 0xe2, 0x62, 0x81, 0xba, 0xac, 0xa9, 0x06, 0x4f, 0xa8, 0xfb, 0xb0, 0x6a, 0x7b, 0xe7, - 0xf6, 0x2c, 0xe2, 0x22, 0xf4, 0x6c, 0x47, 0x74, 0x2f, 0xdc, 0x48, 0xb9, 0xfe, 0x38, 0x5e, 0x6a, - 0xd4, 0x6e, 0x92, 0xbd, 0xaf, 0x60, 0x59, 0x5f, 0xe6, 0xa0, 0xb5, 0x18, 0xc0, 0xb8, 0xfd, 0x21, - 0x3a, 0xd1, 0x7c, 0xfc, 0x63, 0x3b, 0x09, 0x89, 0x7c, 0x26, 0x24, 0xe2, 0x3b, 0xb9, 0x90, 0xb9, - 0x93, 0x93, 0xf0, 0x2a, 0xbe, 0x3c, 0xbc, 0xe6, 0x1c, 0x56, 0x5a, 0x70, 0x98, 0xf5, 0x9b, 0x1c, - 0x5c, 0x5b, 0x48, 0x92, 0x1f, 0x6c, 0xd1, 0x1a, 0xd4, 0x27, 0xf6, 0x99, 0xd0, 0x4f, 0x27, 0x91, - 0xb9, 0x8a, 0xb2, 0xd0, 0x7f, 0xc0, 0x3e, 0x1f, 0x1a, 0xd9, 0xcc, 0xbc, 0xd2, 0xb6, 0x38, 0xd0, - 0x0e, 0x03, 0xb5, 0x1f, 0x4c, 0xcd, 0x9d, 0x1e, 0x07, 0x5a, 0x0c, 0x5e, 0x0e, 0xc7, 0xc2, 0x15, - 0xe1, 0x68, 0x1d, 0x42, 0x35, 0x36, 0x90, 0xdd, 0x32, 0x6f, 0x5b, 0xb9, 0xf4, 0xc9, 0xf6, 0x38, - 0x12, 0x12, 0x6d, 0xd7, 0x0f, 0x5d, 0xef, 0x42, 0x49, 0xd7, 0xba, 0xf9, 0xcb, 0x0c, 0x2d, 0xb1, - 0x06, 0x50, 0x31, 0x08, 0xdb, 0x80, 0xf2, 0xc9, 0x2c, 0x79, 0xe7, 0x31, 0xc7, 0x0e, 0xf6, 0x87, - 0x86, 0x81, 0x67, 0x99, 0x66, 0xb0, 0x1b, 0x50, 0x3c, 0x99, 0xf5, 0x3a, 0xfa, 0xeb, 0x15, 0x4f, - 0x44, 0xec, 0xed, 0x96, 0xb5, 0x41, 0xd6, 0x23, 0x68, 0x64, 0xc7, 0x25, 0x05, 0x42, 0x2e, 0x53, - 0x20, 0x24, 0x47, 0x7f, 0xfe, 0x55, 0x9f, 0x31, 0x1f, 0x03, 0xd0, 0x4b, 0xf4, 0xeb, 0x7e, 0xfe, - 0x7c, 0x08, 0x15, 0xf3, 0x82, 0xcd, 0x3e, 0x58, 0x78, 0x91, 0x6f, 0x26, 0xcf, 0xdb, 0x73, 0xcf, - 0xf2, 0xd6, 0x03, 0x2c, 0x84, 0xcf, 0x85, 0xec, 0xb8, 0xa3, 0xd1, 0xeb, 0x4e, 0xf7, 0x00, 0x9a, - 0xc7, 0x61, 0xf8, 0xaf, 0x8d, 0xfd, 0x29, 0x94, 0xf5, 0x43, 0x3a, 0x8e, 0xf1, 0xd0, 0x02, 0xb3, - 0x07, 0x4c, 0x17, 0xcb, 0x59, 0x93, 0xb8, 0x26, 0x20, 0x73, 0x8a, 0xf3, 0x99, 0xcd, 0x25, 0xe6, - 0xbc, 0x01, 0x5c, 0x13, 0x36, 0xd6, 0xa1, 0x62, 0xde, 0x6c, 0x59, 0x0d, 0x4a, 0xc7, 0x87, 0x83, - 0xee, 0x93, 0xd6, 0x12, 0xab, 0x42, 0xf1, 0xa0, 0x3f, 0x78, 0xd2, 0xca, 0x61, 0xeb, 0xb0, 0x7f, - 0xd8, 0x6d, 0xe5, 0x37, 0x6e, 0x43, 0x23, 0xfb, 0x6a, 0xcb, 0xea, 0x50, 0x19, 0xec, 0x1c, 0x76, - 0x76, 0xfb, 0x3f, 0x69, 0x2d, 0xb1, 0x06, 0x54, 0x7b, 0x87, 0x83, 0xee, 0xde, 0x31, 0xef, 0xb6, - 0x72, 0x1b, 0x3f, 0x86, 0x5a, 0xf2, 0x90, 0x85, 0x1a, 0x76, 0x7b, 0x87, 0x9d, 0xd6, 0x12, 0x03, - 0x28, 0x0f, 0xba, 0x7b, 0xbc, 0x8b, 0x7a, 0x2b, 0x50, 0x18, 0x0c, 0x0e, 0x5a, 0x79, 0x9c, 0x75, - 0x6f, 0x67, 0xef, 0xa0, 0xdb, 0x2a, 0x60, 0xf3, 0xc9, 0xe3, 0xa3, 0xfd, 0x41, 0xab, 0xb8, 0xf1, - 0x21, 0xbc, 0x71, 0xe9, 0x65, 0x08, 0x67, 0xec, 0x74, 0xf7, 0x77, 0x8e, 0x1f, 0xa1, 0x89, 0x65, - 0xc8, 0xf7, 0x0f, 0xb5, 0xa2, 0xfe, 0xfe, 0x7e, 0x2b, 0xbf, 0xf1, 0x31, 0x5c, 0x5b, 0x78, 0xda, - 0xa1, 0x09, 0x0f, 0x76, 0x78, 0x17, 0x27, 0xaf, 0x43, 0xe5, 0x88, 0xf7, 0x9e, 0xee, 0x3c, 0xe9, - 0xb6, 0x72, 0x28, 0x78, 0xd4, 0xdf, 0x7b, 0xd8, 0xed, 0xb4, 0xf2, 0xbb, 0x37, 0xbf, 0x7a, 0xb1, - 0x9a, 0xfb, 0xe6, 0xc5, 0x6a, 0xee, 0xdb, 0x17, 0xab, 0xb9, 0xbf, 0xbd, 0x58, 0xcd, 0x7d, 0xf9, - 0xfd, 0xea, 0xd2, 0x37, 0xdf, 0xaf, 0x2e, 0x7d, 0xfb, 0xfd, 0xea, 0xd2, 0x49, 0x99, 0xfe, 0xbd, - 0xf9, 0xe8, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xef, 0xce, 0x68, 0x38, 0xfd, 0x19, 0x00, 0x00, ->>>>>>> v0.14.1 + 0x89, 0x3d, 0xf4, 0xd0, 0x53, 0x8f, 0x01, 0x0a, 0xf4, 0x56, 0xf4, 0x4b, 0xf4, 0xd8, 0xde, 0x7a, + 0x08, 0x90, 0x4b, 0x0e, 0x3d, 0x04, 0x3d, 0xa4, 0x85, 0x73, 0xe9, 0x67, 0x28, 0x50, 0xa0, 0x98, + 0xd9, 0x7d, 0x7f, 0x48, 0xc9, 0x70, 0xdc, 0x06, 0x3d, 0x71, 0x76, 0xe6, 0xb7, 0xb3, 0xb3, 0xf3, + 0x66, 0x66, 0x67, 0x97, 0x50, 0x93, 0x41, 0xb4, 0x11, 0x84, 0x52, 0x49, 0x96, 0x0f, 0x4e, 0x96, + 0xef, 0x8d, 0x5c, 0x75, 0x3a, 0x39, 0xd9, 0x70, 0xe4, 0x78, 0x73, 0x24, 0x47, 0x72, 0x93, 0x44, + 0x27, 0x93, 0x21, 0x8d, 0x68, 0x40, 0x94, 0x9e, 0x62, 0xfd, 0x33, 0x0f, 0xf9, 0x5e, 0xc0, 0xde, + 0x86, 0xb2, 0xeb, 0x07, 0x13, 0x15, 0xb5, 0x72, 0xab, 0x85, 0xb5, 0xfa, 0x56, 0x6d, 0x23, 0x38, + 0xd9, 0xe8, 0x22, 0x87, 0x1b, 0x01, 0x5b, 0x85, 0xa2, 0xb8, 0x10, 0x4e, 0x2b, 0xbf, 0x9a, 0x5b, + 0xab, 0x6f, 0x01, 0x02, 0x3a, 0x17, 0xc2, 0xe9, 0x05, 0xfb, 0x0b, 0x9c, 0x24, 0xec, 0x3d, 0x28, + 0x47, 0x72, 0x12, 0x3a, 0xa2, 0x55, 0x20, 0xcc, 0x22, 0x62, 0xfa, 0xc4, 0x21, 0x94, 0x91, 0xa2, + 0xa6, 0xa1, 0xeb, 0x89, 0x56, 0x31, 0xd5, 0xb4, 0xe7, 0x7a, 0x1a, 0x43, 0x12, 0xf6, 0x0e, 0x94, + 0x4e, 0x26, 0xae, 0x37, 0x68, 0x95, 0x08, 0x52, 0x47, 0xc8, 0x0e, 0x32, 0x08, 0xa3, 0x65, 0x08, + 0x1a, 0x8b, 0x70, 0x24, 0x5a, 0xe5, 0x14, 0xf4, 0x18, 0x19, 0x1a, 0x44, 0x32, 0x5c, 0x6b, 0xe0, + 0x0e, 0x87, 0xad, 0x4a, 0xba, 0x56, 0xdb, 0x1d, 0x0e, 0xf5, 0x5a, 0x28, 0x61, 0x6b, 0x50, 0x0d, + 0x3c, 0x5b, 0x0d, 0x65, 0x38, 0x6e, 0x41, 0x6a, 0xf7, 0xa1, 0xe1, 0xf1, 0x44, 0xca, 0xee, 0x43, + 0xdd, 0x91, 0x7e, 0xa4, 0x42, 0xdb, 0xf5, 0x55, 0xd4, 0xaa, 0x13, 0xf8, 0x75, 0x04, 0x7f, 0x26, + 0xc3, 0x33, 0x11, 0xee, 0xa6, 0x42, 0x9e, 0x45, 0xee, 0x14, 0x21, 0x2f, 0x03, 0xeb, 0x77, 0x39, + 0xa8, 0xc6, 0x5a, 0x99, 0x05, 0x8b, 0xdb, 0xa1, 0x73, 0xea, 0x2a, 0xe1, 0xa8, 0x49, 0x28, 0x5a, + 0xb9, 0xd5, 0xdc, 0x5a, 0x8d, 0xcf, 0xf0, 0x58, 0x03, 0xf2, 0xbd, 0x3e, 0xf9, 0xbb, 0xc6, 0xf3, + 0xbd, 0x3e, 0x6b, 0x41, 0xe5, 0x89, 0x1d, 0xba, 0xb6, 0xaf, 0xc8, 0xc1, 0x35, 0x1e, 0x0f, 0xd9, + 0x4d, 0xa8, 0xf5, 0xfa, 0x4f, 0x44, 0x18, 0xb9, 0xd2, 0x27, 0xb7, 0xd6, 0x78, 0xca, 0x60, 0x2b, + 0x00, 0xbd, 0xfe, 0x9e, 0xb0, 0x51, 0x69, 0xd4, 0x2a, 0xad, 0x16, 0xd6, 0x6a, 0x3c, 0xc3, 0xb1, + 0x7e, 0x05, 0x25, 0xfa, 0xd4, 0xec, 0x53, 0x28, 0x0f, 0xdc, 0x91, 0x88, 0x94, 0x36, 0x67, 0x67, + 0xeb, 0x8b, 0x6f, 0x6e, 0x2d, 0xfc, 0xed, 0x9b, 0x5b, 0xeb, 0x99, 0x98, 0x92, 0x81, 0xf0, 0x1d, + 0xe9, 0x2b, 0xdb, 0xf5, 0x45, 0x18, 0x6d, 0x8e, 0xe4, 0x3d, 0x3d, 0x65, 0xa3, 0x4d, 0x3f, 0xdc, + 0x68, 0x60, 0xb7, 0xa1, 0xe4, 0xfa, 0x03, 0x71, 0x41, 0xf6, 0x17, 0x76, 0xae, 0x1b, 0x55, 0xf5, + 0xde, 0x44, 0x05, 0x13, 0xd5, 0x45, 0x11, 0xd7, 0x08, 0xeb, 0xcb, 0x1c, 0x94, 0x75, 0x28, 0xb1, + 0x9b, 0x50, 0x1c, 0x0b, 0x65, 0xd3, 0xfa, 0xf5, 0xad, 0xaa, 0xfe, 0xa4, 0xca, 0xe6, 0xc4, 0xc5, + 0x28, 0x1d, 0xcb, 0x09, 0xfa, 0x3e, 0x9f, 0x46, 0xe9, 0x63, 0xe4, 0x70, 0x23, 0x60, 0x3f, 0x82, + 0x8a, 0x2f, 0xd4, 0xb9, 0x0c, 0xcf, 0xc8, 0x47, 0x0d, 0x1d, 0x16, 0x07, 0x42, 0x3d, 0x96, 0x03, + 0xc1, 0x63, 0x19, 0xbb, 0x0b, 0xd5, 0x48, 0x38, 0x93, 0xd0, 0x55, 0x53, 0xf2, 0x57, 0x63, 0xab, + 0x49, 0xc1, 0x6a, 0x78, 0x04, 0x4e, 0x10, 0xec, 0x0e, 0xd4, 0x22, 0xe1, 0x84, 0x42, 0x09, 0xff, + 0x19, 0xf9, 0xaf, 0xbe, 0xb5, 0x64, 0xe0, 0xa1, 0x50, 0x1d, 0xff, 0x19, 0x4f, 0xe5, 0xd6, 0x97, + 0x79, 0x28, 0xa2, 0xcd, 0x8c, 0x41, 0xd1, 0x0e, 0x47, 0x3a, 0xa3, 0x6a, 0x9c, 0x68, 0xd6, 0x84, + 0x02, 0xea, 0xc8, 0x13, 0x0b, 0x49, 0xe4, 0x38, 0xe7, 0x03, 0xf3, 0x41, 0x91, 0xc4, 0x79, 0x93, + 0x48, 0x84, 0xe6, 0x3b, 0x12, 0xcd, 0x6e, 0x43, 0x2d, 0x08, 0xe5, 0xc5, 0xf4, 0xa9, 0xb6, 0x20, + 0x8d, 0x52, 0x64, 0xa2, 0x01, 0xd5, 0xc0, 0x50, 0x6c, 0x1d, 0x40, 0x5c, 0xa8, 0xd0, 0xde, 0x97, + 0x91, 0x8a, 0x5a, 0x65, 0xb2, 0x96, 0xe2, 0x1e, 0x19, 0xdd, 0x43, 0x9e, 0x91, 0xb2, 0x65, 0xa8, + 0x9e, 0xca, 0x48, 0xf9, 0xf6, 0x58, 0x50, 0x86, 0xd4, 0x78, 0x32, 0x66, 0x16, 0x94, 0x27, 0x9e, + 0x3b, 0x76, 0x55, 0xab, 0x96, 0xea, 0x38, 0x26, 0x0e, 0x37, 0x12, 0x8c, 0x62, 0x67, 0x14, 0xca, + 0x49, 0x70, 0x68, 0x87, 0xc2, 0x57, 0x94, 0x3f, 0x35, 0x3e, 0xc3, 0x63, 0x1f, 0xc3, 0x5b, 0xa1, + 0x18, 0xcb, 0x67, 0x82, 0x3e, 0x54, 0x5f, 0x4d, 0x4e, 0x22, 0x8e, 0x8e, 0x8d, 0xdc, 0x67, 0x82, + 0x72, 0xa8, 0xca, 0x5f, 0x0c, 0xb0, 0xee, 0x42, 0x59, 0xdb, 0x8d, 0x6e, 0x41, 0xca, 0x64, 0x0a, + 0xd1, 0x98, 0x21, 0xdd, 0xc3, 0x38, 0x43, 0xba, 0x87, 0x56, 0x1b, 0xca, 0xda, 0x42, 0x44, 0x1f, + 0xe0, 0xae, 0x0c, 0x1a, 0x69, 0xe4, 0xf5, 0xe5, 0x50, 0xe9, 0x88, 0xe4, 0x44, 0x93, 0x56, 0x3b, + 0xd4, 0xfe, 0x2f, 0x70, 0xa2, 0xad, 0x87, 0x50, 0x4b, 0xbe, 0x2c, 0x2d, 0xd1, 0x36, 0x6a, 0xf2, + 0xdd, 0x36, 0x4e, 0x20, 0x77, 0xe9, 0x45, 0x89, 0x46, 0x37, 0xca, 0x40, 0xb9, 0xd2, 0xb7, 0x3d, + 0x52, 0x54, 0xe5, 0xc9, 0xd8, 0xfa, 0x57, 0x01, 0x4a, 0xb4, 0x31, 0xb6, 0x86, 0x19, 0x11, 0x4c, + 0xf4, 0x0e, 0x0a, 0x3b, 0xcc, 0x64, 0x04, 0x50, 0xee, 0x25, 0x09, 0x81, 0x79, 0xb8, 0x8c, 0xd1, + 0xe9, 0x09, 0x47, 0xc9, 0xd0, 0xac, 0x93, 0x8c, 0x71, 0xfd, 0x01, 0x66, 0xa8, 0x0e, 0x18, 0xa2, + 0xd9, 0x1d, 0x28, 0x4b, 0x4a, 0x2b, 0x8a, 0x99, 0x17, 0x24, 0x9b, 0x81, 0xa0, 0xf2, 0x50, 0xd8, + 0x03, 0xe9, 0x7b, 0x53, 0x8a, 0xa4, 0x2a, 0x4f, 0xc6, 0x18, 0xe8, 0x94, 0x47, 0x47, 0xd3, 0x40, + 0x97, 0xd5, 0x86, 0x0e, 0xf4, 0xc7, 0x31, 0x93, 0xa7, 0x72, 0x2c, 0x9c, 0x47, 0xe3, 0x60, 0x18, + 0xf5, 0x02, 0xd5, 0xba, 0x9e, 0x86, 0x64, 0xcc, 0xe3, 0x89, 0x14, 0x91, 0x8e, 0xed, 0x9c, 0x0a, + 0x44, 0xde, 0x48, 0x91, 0xbb, 0x86, 0xc7, 0x13, 0x69, 0x9a, 0x69, 0x08, 0x7d, 0x9d, 0xa0, 0x99, + 0x4c, 0x43, 0x6c, 0x2a, 0xc7, 0x08, 0xed, 0xf7, 0xf7, 0x11, 0xf9, 0x46, 0x5a, 0xdd, 0x35, 0x87, + 0x1b, 0x89, 0xde, 0x6d, 0x34, 0xf1, 0x54, 0xb7, 0xdd, 0x7a, 0x53, 0xbb, 0x32, 0x1e, 0xb3, 0x1f, + 0xc3, 0x22, 0x56, 0x32, 0xe1, 0x2b, 0xb2, 0xa4, 0xd5, 0xa2, 0x0d, 0xbf, 0x9e, 0x6c, 0x78, 0x37, + 0x23, 0xe4, 0x33, 0x50, 0x2c, 0x33, 0x7d, 0xe9, 0x9c, 0xe1, 0xda, 0x83, 0xf4, 0xf4, 0x31, 0x2c, + 0x1e, 0xcb, 0xac, 0x95, 0xd4, 0x45, 0xf8, 0xe1, 0x22, 0xf7, 0x97, 0x3a, 0x22, 0x0b, 0x9c, 0x68, + 0xab, 0x0b, 0xd5, 0xd8, 0x09, 0x97, 0x02, 0xed, 0x1e, 0x54, 0xa2, 0x53, 0x3b, 0x74, 0xfd, 0x11, + 0xc5, 0x40, 0x63, 0xeb, 0x7a, 0xe2, 0xb3, 0xbe, 0xe6, 0xd3, 0x52, 0x06, 0x63, 0xc9, 0x38, 0x68, + 0xaf, 0xd2, 0xd5, 0x84, 0xc2, 0xc4, 0x1d, 0x90, 0x9e, 0x25, 0x8e, 0x24, 0x72, 0x46, 0xae, 0x0e, + 0xfb, 0x25, 0x8e, 0x24, 0xda, 0x37, 0x96, 0x03, 0x7d, 0x2a, 0x2f, 0x71, 0xa2, 0x67, 0x02, 0xbb, + 0x34, 0x17, 0xd8, 0x5e, 0xec, 0xfd, 0xff, 0xcb, 0x6a, 0x3f, 0x4d, 0x1c, 0xfe, 0x7d, 0x2d, 0x67, + 0xfd, 0x36, 0x07, 0xd5, 0xb8, 0x3b, 0xc1, 0x33, 0xd2, 0x1d, 0x08, 0x5f, 0xb9, 0x43, 0x57, 0x84, + 0x46, 0x79, 0x86, 0xc3, 0xee, 0x41, 0xc9, 0x56, 0x2a, 0x8c, 0x4f, 0x9e, 0x37, 0xb3, 0xad, 0xcd, + 0xc6, 0x36, 0x4a, 0x3a, 0xbe, 0x0a, 0xa7, 0x5c, 0xa3, 0x96, 0x3f, 0x02, 0x48, 0x99, 0x68, 0xcf, + 0x99, 0x98, 0x1a, 0xad, 0x48, 0xb2, 0x1b, 0x50, 0x7a, 0x66, 0x7b, 0x93, 0xb8, 0x8c, 0xe8, 0xc1, + 0x83, 0xfc, 0x47, 0x39, 0xeb, 0xcf, 0x79, 0xa8, 0x98, 0x56, 0x87, 0xdd, 0x85, 0x0a, 0xb5, 0x3a, + 0xc6, 0xa2, 0xab, 0x6b, 0x46, 0x0c, 0x61, 0x9b, 0x49, 0x0f, 0x97, 0xb1, 0xd1, 0xa8, 0xd2, 0xbd, + 0x9c, 0xb1, 0x31, 0xed, 0xe8, 0x0a, 0x03, 0x31, 0x34, 0xcd, 0x5a, 0x83, 0x5a, 0x23, 0x31, 0x74, + 0x7d, 0x17, 0x5d, 0xce, 0x51, 0xc4, 0xee, 0xc6, 0xbb, 0x2e, 0x92, 0xc6, 0x37, 0xb2, 0x1a, 0x2f, + 0x6f, 0xba, 0x0b, 0xf5, 0xcc, 0x32, 0x57, 0xec, 0xfa, 0xdd, 0xec, 0xae, 0xcd, 0x92, 0xa4, 0x4e, + 0x77, 0x9a, 0xa9, 0x17, 0xfe, 0x07, 0xff, 0x7d, 0x08, 0x90, 0xaa, 0xfc, 0xee, 0x35, 0xd7, 0xfa, + 0x53, 0x01, 0xa0, 0x17, 0xe0, 0xc1, 0x3d, 0xb0, 0xa9, 0xd5, 0x58, 0x74, 0x47, 0xbe, 0x0c, 0xc5, + 0x53, 0xaa, 0x4d, 0x34, 0xbf, 0xca, 0xeb, 0x9a, 0xa7, 0x6b, 0xc0, 0x36, 0xd4, 0x07, 0x22, 0x72, + 0x42, 0x97, 0x62, 0xd4, 0x38, 0xfd, 0x16, 0xee, 0x29, 0xd5, 0xb3, 0xd1, 0x4e, 0x11, 0xda, 0x57, + 0xd9, 0x39, 0x6c, 0x0b, 0x16, 0xc5, 0x45, 0x20, 0x43, 0x65, 0x56, 0xd1, 0x1d, 0xf1, 0x35, 0xdd, + 0x5b, 0x23, 0x5f, 0xd7, 0x9e, 0xba, 0x48, 0x07, 0xcc, 0x86, 0xa2, 0x63, 0x07, 0x91, 0xe9, 0x43, + 0x5a, 0x73, 0xeb, 0xed, 0xda, 0x81, 0x76, 0xda, 0xce, 0x07, 0xb8, 0xd7, 0x5f, 0xff, 0xfd, 0xd6, + 0x9d, 0x4c, 0xf3, 0x36, 0x96, 0x27, 0xd3, 0x4d, 0x8a, 0x97, 0x33, 0x57, 0x6d, 0x4e, 0x94, 0xeb, + 0x6d, 0xda, 0x81, 0x8b, 0xea, 0x70, 0x62, 0xb7, 0xcd, 0x49, 0x35, 0xfb, 0x08, 0x1a, 0x41, 0x28, + 0x47, 0xa1, 0x88, 0xa2, 0xa7, 0x74, 0x94, 0x9b, 0x16, 0xfb, 0x35, 0xd3, 0x72, 0x90, 0xe4, 0x13, + 0x14, 0xf0, 0xa5, 0x20, 0x3b, 0x5c, 0xfe, 0x09, 0x34, 0xe7, 0x77, 0xfc, 0x2a, 0x5f, 0x6f, 0xf9, + 0x3e, 0xd4, 0x92, 0x1d, 0xbc, 0x6c, 0x62, 0x35, 0xfb, 0xd9, 0xff, 0x98, 0x83, 0xb2, 0xce, 0x47, + 0x76, 0x1f, 0x6a, 0x9e, 0x74, 0x6c, 0x34, 0x20, 0xbe, 0xce, 0xbc, 0x95, 0xa6, 0xeb, 0xc6, 0xa3, + 0x58, 0xa6, 0xbf, 0x47, 0x8a, 0xc5, 0xf0, 0x74, 0xfd, 0xa1, 0x8c, 0xf3, 0xa7, 0x91, 0x4e, 0xea, + 0xfa, 0x43, 0xc9, 0xb5, 0x70, 0xf9, 0x21, 0x34, 0x66, 0x55, 0x5c, 0x61, 0xe7, 0x3b, 0xb3, 0x81, + 0x4e, 0x47, 0x58, 0x32, 0x29, 0x6b, 0xf6, 0x7d, 0xa8, 0x25, 0x7c, 0xb6, 0x7e, 0xd9, 0xf0, 0xc5, + 0xec, 0xcc, 0x8c, 0xad, 0xd6, 0x6f, 0x72, 0x00, 0xa9, 0x6d, 0x58, 0x3a, 0xf1, 0xe2, 0xe4, 0xa7, + 0x2d, 0x4f, 0x32, 0xa6, 0x8e, 0xc1, 0x56, 0x36, 0xd9, 0xb2, 0xc8, 0x89, 0x66, 0x1b, 0x00, 0x83, + 0x24, 0xd7, 0x5f, 0x50, 0x01, 0x32, 0x08, 0xd4, 0xef, 0xd9, 0xfe, 0x68, 0x62, 0x8f, 0x84, 0xe9, + 0x4b, 0x93, 0xb1, 0xd5, 0x83, 0x6a, 0x6c, 0x21, 0x5b, 0x85, 0x7a, 0x64, 0xac, 0xc2, 0xde, 0x1f, + 0x4d, 0x29, 0xf1, 0x2c, 0x0b, 0x7b, 0xf8, 0xd0, 0xf6, 0x47, 0x62, 0xa6, 0x87, 0xe7, 0xc8, 0xe1, + 0x46, 0x60, 0x7d, 0x06, 0x25, 0x62, 0x60, 0xf6, 0x46, 0xca, 0x0e, 0x95, 0xb9, 0x0e, 0xe8, 0x8e, + 0x57, 0x46, 0x64, 0xd2, 0x4e, 0x11, 0xe3, 0x9b, 0x6b, 0x00, 0x7b, 0x17, 0xfb, 0xea, 0x81, 0x71, + 0xf7, 0x55, 0x38, 0x14, 0x5b, 0x1f, 0x43, 0x35, 0x66, 0xa3, 0x57, 0x3c, 0xd7, 0x17, 0xc6, 0x44, + 0xa2, 0xf1, 0x1a, 0xe5, 0x9c, 0xda, 0xa1, 0xed, 0x28, 0xa1, 0x1b, 0xaf, 0x12, 0x4f, 0x19, 0xd6, + 0x3b, 0x50, 0xcf, 0x24, 0x25, 0xc6, 0xe2, 0x13, 0xfa, 0xc6, 0xba, 0x34, 0xe8, 0x81, 0xf5, 0x09, + 0x2c, 0xcd, 0x24, 0x08, 0x9e, 0x56, 0xee, 0x20, 0x3e, 0xad, 0xf4, 0x49, 0x74, 0xa9, 0x7f, 0x64, + 0x50, 0x3c, 0x17, 0xf6, 0x99, 0xe9, 0x1d, 0x89, 0xb6, 0xfe, 0x80, 0xb7, 0xc5, 0xb8, 0xa7, 0xff, + 0x21, 0xc0, 0xa9, 0x52, 0xc1, 0x53, 0x6a, 0xf2, 0x8d, 0xb2, 0x1a, 0x72, 0x08, 0xc1, 0x6e, 0x41, + 0x1d, 0x07, 0x91, 0x91, 0x6b, 0xd5, 0x34, 0x23, 0xd2, 0x80, 0x1f, 0x40, 0x6d, 0x98, 0x4c, 0x2f, + 0x98, 0xf8, 0x88, 0x67, 0xbf, 0x05, 0x55, 0x5f, 0x1a, 0x99, 0xfe, 0xb6, 0x15, 0x5f, 0x26, 0xf3, + 0x6c, 0xcf, 0x33, 0xb2, 0x92, 0x9e, 0x67, 0x7b, 0x1e, 0x09, 0xad, 0x3b, 0xf0, 0xda, 0xa5, 0x7b, + 0x2f, 0x7b, 0x03, 0xca, 0x43, 0xd7, 0x53, 0x74, 0x62, 0xe1, 0x1d, 0xc7, 0x8c, 0xac, 0x7f, 0xe7, + 0x00, 0xd2, 0xd8, 0xc2, 0x94, 0xc1, 0xa3, 0x07, 0x31, 0x8b, 0xfa, 0xa8, 0xf1, 0xa0, 0x3a, 0x36, + 0x45, 0xcc, 0x44, 0xc6, 0xcd, 0xd9, 0x78, 0xdc, 0x88, 0x6b, 0x9c, 0x2e, 0x6f, 0x5b, 0xa6, 0xbc, + 0xbd, 0xca, 0xdd, 0x34, 0x59, 0x81, 0x5a, 0xc7, 0xec, 0x53, 0x05, 0xa4, 0xb9, 0xce, 0x8d, 0x64, + 0xf9, 0x21, 0x2c, 0xcd, 0x2c, 0xf9, 0x1d, 0x0f, 0xb4, 0xb4, 0x18, 0x67, 0x13, 0x7d, 0x0b, 0xca, + 0xfa, 0x8d, 0x83, 0xad, 0x41, 0xc5, 0x76, 0x74, 0x8e, 0x67, 0xea, 0x0c, 0x0a, 0xb7, 0x89, 0xcd, + 0x63, 0xb1, 0xf5, 0xd7, 0x3c, 0x40, 0xca, 0x7f, 0x85, 0xfb, 0xc3, 0x03, 0x68, 0x44, 0xc2, 0x91, + 0xfe, 0xc0, 0x0e, 0xa7, 0x24, 0x35, 0x97, 0xf0, 0xab, 0xa6, 0xcc, 0x21, 0x33, 0x77, 0x89, 0xc2, + 0xcb, 0xef, 0x12, 0x6b, 0x50, 0x74, 0x64, 0x30, 0x35, 0xe7, 0x16, 0x9b, 0xdd, 0xc8, 0xae, 0x0c, + 0xa6, 0xfb, 0x0b, 0x9c, 0x10, 0x6c, 0x03, 0xca, 0xe3, 0x33, 0x7a, 0xf5, 0xd1, 0xb7, 0xd7, 0x1b, + 0xb3, 0xd8, 0xc7, 0x67, 0x48, 0xef, 0x2f, 0x70, 0x83, 0x62, 0x77, 0xa0, 0x34, 0x3e, 0x1b, 0xb8, + 0xa1, 0x39, 0x79, 0xae, 0xcf, 0xc3, 0xdb, 0x6e, 0x48, 0x8f, 0x3c, 0x88, 0x61, 0x16, 0xe4, 0xc3, + 0xb1, 0x79, 0xe2, 0x69, 0xce, 0x79, 0x73, 0xbc, 0xbf, 0xc0, 0xf3, 0xe1, 0x78, 0xa7, 0x0a, 0x65, + 0xed, 0x57, 0xeb, 0x2f, 0x45, 0x68, 0xcc, 0x5a, 0x89, 0x5f, 0x36, 0x0a, 0x9d, 0xf8, 0xcb, 0x46, + 0xa1, 0x93, 0x5c, 0xb3, 0xf2, 0x99, 0x6b, 0x96, 0x05, 0x25, 0x79, 0xee, 0x8b, 0x30, 0xfb, 0xbc, + 0xb5, 0x7b, 0x2a, 0xcf, 0x7d, 0x6c, 0xc4, 0xb5, 0x68, 0xa6, 0xd1, 0x2c, 0x99, 0xbe, 0xf6, 0x5d, + 0x58, 0x1a, 0x4a, 0xcf, 0x93, 0xe7, 0xfd, 0xe9, 0xd8, 0x73, 0xfd, 0x33, 0xd3, 0xdc, 0xce, 0x32, + 0xd9, 0x1a, 0x5c, 0x1b, 0xb8, 0x21, 0x9a, 0x63, 0xee, 0x1d, 0x11, 0xed, 0xbd, 0xca, 0xe7, 0xd9, + 0xec, 0x53, 0x58, 0xb5, 0x95, 0x12, 0xe3, 0x40, 0x1d, 0xfb, 0x81, 0xed, 0x9c, 0xb5, 0xa5, 0x43, + 0x59, 0x38, 0x0e, 0x6c, 0xe5, 0x9e, 0xb8, 0x9e, 0xab, 0xa6, 0xe4, 0x8c, 0x2a, 0x7f, 0x29, 0x8e, + 0xbd, 0x07, 0x0d, 0x27, 0x14, 0xb6, 0x12, 0x6d, 0x11, 0xa9, 0x43, 0x5b, 0x9d, 0xb6, 0xaa, 0x34, + 0x73, 0x8e, 0x8b, 0x7b, 0xb0, 0xd1, 0xda, 0xcf, 0x5c, 0x6f, 0xe0, 0xe0, 0x85, 0xb9, 0xa6, 0xf7, + 0x30, 0xc3, 0x64, 0x1b, 0xc0, 0x88, 0xd1, 0x19, 0x07, 0x6a, 0x9a, 0x40, 0x81, 0xa0, 0x57, 0x48, + 0xb0, 0xe0, 0x2a, 0x77, 0x2c, 0x22, 0x65, 0x8f, 0x03, 0x7a, 0x0b, 0x28, 0xf0, 0x94, 0xc1, 0x6e, + 0x43, 0xd3, 0xf5, 0x1d, 0x6f, 0x32, 0x10, 0x4f, 0x03, 0xdc, 0x48, 0xe8, 0x47, 0xad, 0x45, 0xaa, + 0x2a, 0xd7, 0x0c, 0xff, 0xd0, 0xb0, 0x11, 0x2a, 0x2e, 0xe6, 0xa0, 0x4b, 0x1a, 0x6a, 0xf8, 0x09, + 0x74, 0x0f, 0x56, 0x6c, 0xef, 0xdc, 0x9e, 0x46, 0x5c, 0x04, 0x9e, 0xed, 0x88, 0xce, 0x85, 0x1b, + 0x29, 0xd7, 0x1f, 0xc5, 0x5b, 0x8d, 0x5a, 0x0d, 0xb2, 0xf7, 0x25, 0x28, 0xeb, 0xf3, 0x1c, 0x34, + 0xe7, 0x03, 0x18, 0x3f, 0x7f, 0x80, 0x4e, 0x34, 0xcf, 0x0e, 0x48, 0x27, 0x21, 0x91, 0xcf, 0x84, + 0x44, 0x7c, 0x26, 0x17, 0x32, 0x67, 0x72, 0x12, 0x5e, 0xc5, 0x17, 0x87, 0xd7, 0x8c, 0xc3, 0x4a, + 0x73, 0x0e, 0xb3, 0x7e, 0x9f, 0x83, 0x6b, 0x73, 0x49, 0xf2, 0x9d, 0x2d, 0x5a, 0x85, 0xfa, 0xd8, + 0x3e, 0x13, 0xfa, 0xd1, 0x26, 0x32, 0x47, 0x51, 0x96, 0xf5, 0x3d, 0xd8, 0xe7, 0xc3, 0x62, 0x36, + 0x33, 0xaf, 0xb4, 0x2d, 0x0e, 0xb4, 0x03, 0xa9, 0xf6, 0xe4, 0xc4, 0x9c, 0xe9, 0x71, 0xa0, 0xc5, + 0xcc, 0xcb, 0xe1, 0x58, 0xb8, 0x22, 0x1c, 0xad, 0x03, 0xa8, 0xc6, 0x06, 0xb2, 0x5b, 0xe6, 0x55, + 0x2d, 0x97, 0x5e, 0xd7, 0x8f, 0x23, 0x11, 0xa2, 0xed, 0xfa, 0x89, 0xed, 0x6d, 0x28, 0xe9, 0x5e, + 0x37, 0x7f, 0x19, 0xa1, 0x25, 0x56, 0x1f, 0x2a, 0x86, 0xc3, 0xd6, 0xa1, 0x7c, 0x32, 0x4d, 0x5e, + 0x98, 0x4c, 0xd9, 0xc1, 0xf1, 0xc0, 0x20, 0xb0, 0x96, 0x69, 0x04, 0xbb, 0x01, 0xc5, 0x93, 0x69, + 0xb7, 0xad, 0x6f, 0xa8, 0x58, 0x11, 0x71, 0xb4, 0x53, 0xd6, 0x06, 0x59, 0x8f, 0x60, 0x31, 0x3b, + 0x2f, 0x69, 0x10, 0x72, 0x99, 0x06, 0x21, 0x29, 0xfd, 0xf9, 0x97, 0x5d, 0x63, 0x3e, 0x04, 0xa0, + 0x37, 0xf0, 0x57, 0xbd, 0xfe, 0xbc, 0x0f, 0x15, 0xf3, 0x76, 0xce, 0xde, 0x9b, 0xfb, 0x2f, 0xa0, + 0x91, 0x3c, 0xac, 0xcf, 0xfc, 0x21, 0x60, 0x3d, 0xc0, 0x46, 0xf8, 0x5c, 0x84, 0x6d, 0x77, 0x38, + 0x7c, 0xd5, 0xe5, 0x1e, 0x40, 0xe3, 0x38, 0x08, 0xfe, 0xbb, 0xb9, 0xbf, 0x80, 0xb2, 0x7e, 0xc2, + 0xc7, 0x39, 0x1e, 0x5a, 0x60, 0xbe, 0x01, 0xd3, 0xcd, 0x72, 0xd6, 0x24, 0xae, 0x01, 0x88, 0x9c, + 0xe0, 0x7a, 0xe6, 0xe3, 0x12, 0x72, 0xd6, 0x00, 0xae, 0x01, 0xeb, 0x6b, 0x50, 0x31, 0xaf, 0xc5, + 0xac, 0x06, 0xa5, 0xe3, 0x83, 0x7e, 0xe7, 0xa8, 0xb9, 0xc0, 0xaa, 0x50, 0xdc, 0xef, 0xf5, 0x8f, + 0x9a, 0x39, 0xa4, 0x0e, 0x7a, 0x07, 0x9d, 0x66, 0x7e, 0xfd, 0x36, 0x2c, 0x66, 0xdf, 0x8b, 0x59, + 0x1d, 0x2a, 0xfd, 0xed, 0x83, 0xf6, 0x4e, 0xef, 0x67, 0xcd, 0x05, 0xb6, 0x08, 0xd5, 0xee, 0x41, + 0xbf, 0xb3, 0x7b, 0xcc, 0x3b, 0xcd, 0xdc, 0xfa, 0xcf, 0xa1, 0x96, 0x3c, 0xa1, 0xa1, 0x86, 0x9d, + 0xee, 0x41, 0xbb, 0xb9, 0xc0, 0x00, 0xca, 0xfd, 0xce, 0x2e, 0xef, 0xa0, 0xde, 0x0a, 0x14, 0xfa, + 0xfd, 0xfd, 0x66, 0x1e, 0x57, 0xdd, 0xdd, 0xde, 0xdd, 0xef, 0x34, 0x0b, 0x48, 0x1e, 0x3d, 0x3e, + 0xdc, 0xeb, 0x37, 0x8b, 0x6c, 0x09, 0x6a, 0x68, 0xc0, 0x53, 0x9a, 0x39, 0xa0, 0x99, 0xbd, 0xdd, + 0x87, 0x9d, 0xa3, 0xa6, 0x58, 0x7f, 0x1f, 0x5e, 0xbb, 0xf4, 0x5c, 0x85, 0xc6, 0xb4, 0x3b, 0x7b, + 0xdb, 0xc7, 0x8f, 0xd0, 0xfa, 0x32, 0xe4, 0x7b, 0x07, 0x7a, 0x8d, 0xde, 0xde, 0x5e, 0x33, 0xbf, + 0xfe, 0x21, 0x5c, 0x9b, 0x7b, 0x48, 0x22, 0x8d, 0xfb, 0xdb, 0xbc, 0x83, 0x76, 0xd5, 0xa1, 0x72, + 0xc8, 0xbb, 0x4f, 0xb6, 0x8f, 0x3a, 0xcd, 0x1c, 0x0a, 0x1e, 0xe1, 0x52, 0xed, 0x66, 0x7e, 0xe7, + 0xe6, 0x17, 0xcf, 0x57, 0x72, 0x5f, 0x3d, 0x5f, 0xc9, 0x7d, 0xfd, 0x7c, 0x25, 0xf7, 0x8f, 0xe7, + 0x2b, 0xb9, 0xcf, 0xbf, 0x5d, 0x59, 0xf8, 0xea, 0xdb, 0x95, 0x85, 0xaf, 0xbf, 0x5d, 0x59, 0x38, + 0x29, 0xd3, 0x5f, 0x4a, 0x1f, 0xfc, 0x27, 0x00, 0x00, 0xff, 0xff, 0x23, 0xbd, 0x6e, 0x79, 0x92, + 0x1a, 0x00, 0x00, } func (m *Op) Marshal() (dAtA []byte, err error) { diff --git a/solver/scheduler.go b/solver/scheduler.go index f94b61576..db4d053d3 100644 --- a/solver/scheduler.go +++ b/solver/scheduler.go @@ -415,16 +415,13 @@ type pipeFactory struct { func (pf *pipeFactory) NewInputRequest(ee Edge, req *edgeRequest) pipe.Receiver { target := pf.s.ef.getEdge(ee) if target == nil { -<<<<<<< HEAD - dgst := ee.Vertex.Digest() - bklog.G(context.TODO()).Errorf("failed to get edge dgst=%s name=%s desiredState=%s; actives history: %s", dgst, ee.Vertex.Name(), req.desiredState, dgstTrackerInst.String()) // earthly-specific -======= bklog.G(context.TODO()). WithField("edge_vertex_name", ee.Vertex.Name()). WithField("edge_vertex_digest", ee.Vertex.Digest()). WithField("edge_index", ee.Index). + WithField("desired_state", req.desiredState). + WithField("actives_history", dgstTrackerInst.String()). Error("failed to get edge: inconsistent graph state") ->>>>>>> v0.14.1 return pf.NewFuncRequest(func(_ context.Context) (interface{}, error) { return nil, errors.Errorf("failed to get edge: inconsistent graph state in edge %s %s %d", ee.Vertex.Name(), ee.Vertex.Digest(), ee.Index) }) diff --git a/util/archutil/loong64_binary.go b/util/archutil/loong64_binary.go index b6d8616c7..01d445431 100644 --- a/util/archutil/loong64_binary.go +++ b/util/archutil/loong64_binary.go @@ -6,8 +6,4 @@ package archutil // This file is generated by running "make archutil". // Do not edit manually. -<<<<<<< HEAD -const Binaryloong64 = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xaa\x77\xf5\x71\x63\x62\x64\x64\x80\x01\x26\x06\x08\x6f\x03\x03\x83\x02\x88\x76\x80\x8a\x5f\x80\xd2\xce\x60\x31\x0b\x06\x26\x06\x07\x06\x66\x06\x26\x06\x90\x1a\x56\x06\x14\xa0\xc0\x88\x44\xef\x81\x0a\xee\x81\x4b\x43\x64\x03\x9f\x96\xa4\xb0\x31\x10\x0f\x04\xa0\x34\x0b\x83\x28\x03\x77\x49\x23\x33\x03\x83\x36\x03\x83\x5e\x71\x46\x71\x49\x51\x49\x62\x12\x83\x5e\x49\x6a\x45\x09\x03\x15\x00\x37\xd4\x85\x30\xb7\xc1\xc2\x61\x03\x94\xcf\x83\xa6\x9e\x11\x0b\x9f\x19\x8b\xb9\x30\xff\x0b\x12\xd0\x0f\x08\x00\x00\xff\xff\x72\x81\xda\x64\x90\x01\x00\x00" -======= const Binaryloong64 = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xaa\x77\xf5\x71\x63\x62\x64\x64\x80\x01\x26\x06\x08\x6f\x03\x03\x83\x02\x88\x76\x80\x8a\x5f\x80\xd2\xce\x60\x31\x0b\x06\x26\x06\x07\x06\x66\x06\x26\x06\x90\x1a\x56\x06\x14\xa0\xc0\x88\x44\xef\x81\x0a\xc2\x68\x98\x81\x81\x4f\x4b\x52\xd8\x18\x88\x07\x02\x50\x9a\x85\x41\x94\x81\xbb\xa4\x91\x99\x81\x41\x9b\x81\x41\xaf\x38\xa3\xb8\xa4\xa8\x24\x31\x89\x41\xaf\x24\xb5\xa2\x84\x81\x0a\x80\x9b\x81\x01\xec\x27\x98\xdb\x60\xe1\xb0\x01\xca\xe7\x41\x53\xcf\x88\x85\xcf\x8c\xc5\x5c\x98\xff\x05\x09\xe8\x07\x04\x00\x00\xff\xff\x5f\xc5\x9b\x9d\x90\x01\x00\x00" ->>>>>>> v0.14.1 diff --git a/util/gitutil/git_cli.go b/util/gitutil/git_cli.go index cf0cebffd..5b895cac2 100644 --- a/util/gitutil/git_cli.go +++ b/util/gitutil/git_cli.go @@ -278,7 +278,6 @@ func (cli *GitCLI) Run(ctx context.Context, args ...string) (_ []byte, err error } } -<<<<<<< HEAD // Earthly-TODO: moby/master didn't use to include the git stderr; however, change it at some point AFTER we added in this EARTHLY_GIT_STDERR hack; however we will keep ours for the time being (since we look specifically for EARTHLY_GIT_STDERR in earthly) //return buf.Bytes(), errors.Errorf("git error: %s\nstderr:\n%s", err, errbuf.String()) @@ -290,9 +289,6 @@ func (cli *GitCLI) Run(ctx context.Context, args ...string) (_ []byte, err error } err = errors.Wrapf(err, "EARTHLY_GIT_STDERR: %s", base64.StdEncoding.EncodeToString([]byte(urlutil.RedactAllCredentials(fmt.Sprintf("git %s\n%s", strings.Join(args, " "), errbuf.String()))))) // earthly-specific return buf.Bytes(), err -======= - return buf.Bytes(), errors.Wrapf(err, "git stderr:\n%s", errbuf.String()) ->>>>>>> v0.14.1 } return buf.Bytes(), nil diff --git a/util/gitutil/git_ref.go b/util/gitutil/git_ref.go index deecd6334..59d658264 100644 --- a/util/gitutil/git_ref.go +++ b/util/gitutil/git_ref.go @@ -58,11 +58,7 @@ func ParseGitRef(ref string) (*GitRef, error) { ) if strings.HasPrefix(ref, "./") || strings.HasPrefix(ref, "../") { -<<<<<<< HEAD - return nil, errdefs.ErrInvalidArgument -======= return nil, cerrdefs.ErrInvalidArgument ->>>>>>> v0.14.1 } else if strings.HasPrefix(ref, "github.com/") { res.IndistinguishableFromLocal = true // Deprecated remote = fromURL(&url.URL{ diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/LICENSE b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/LICENSE new file mode 100644 index 000000000..b2b065037 --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/vendor/github.com/tonistiigi/fsutil/diskwriter.go b/vendor/github.com/tonistiigi/fsutil/diskwriter.go index a62c6b0c9..10b608513 100644 --- a/vendor/github.com/tonistiigi/fsutil/diskwriter.go +++ b/vendor/github.com/tonistiigi/fsutil/diskwriter.go @@ -37,7 +37,6 @@ type DiskWriter struct { ctx context.Context cancel func() eg *errgroup.Group - egCtx context.Context filter FilterFunc dirModTimes map[string]int64 } @@ -51,14 +50,13 @@ func NewDiskWriter(ctx context.Context, dest string, opt DiskWriterOpt) (*DiskWr } ctx, cancel := context.WithCancel(ctx) - eg, egCtx := errgroup.WithContext(ctx) + eg, ctx := errgroup.WithContext(ctx) return &DiskWriter{ opt: opt, dest: dest, eg: eg, ctx: ctx, - egCtx: egCtx, cancel: cancel, filter: opt.Filter, dirModTimes: map[string]int64{}, @@ -100,7 +98,7 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er } }() - destPath := filepath.Join(dw.dest, p) + destPath := filepath.Join(dw.dest, filepath.FromSlash(p)) if kind == ChangeKindDelete { if dw.filter != nil { @@ -185,12 +183,12 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er } default: isRegularFile = true - file, err := os.OpenFile(newPath, os.O_CREATE|os.O_WRONLY, fi.Mode()) + file, err := os.OpenFile(newPath, os.O_CREATE|os.O_WRONLY, fi.Mode()) //todo: windows if err != nil { return errors.Wrapf(err, "failed to create %s", newPath) } if dw.opt.SyncDataCb != nil { - if err := dw.processChange(dw.ctx, ChangeKindAdd, p, fi, file); err != nil { + if err := dw.processChange(ChangeKindAdd, p, fi, file); err != nil { file.Close() return err } @@ -221,7 +219,7 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er dw.requestAsyncFileData(p, destPath, fi, &statCopy) } } else { - return dw.processChange(dw.ctx, kind, p, fi, nil) + return dw.processChange(kind, p, fi, nil) } return nil @@ -230,7 +228,7 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er func (dw *DiskWriter) requestAsyncFileData(p, dest string, fi os.FileInfo, st *types.Stat) { // todo: limit worker threads dw.eg.Go(func() error { - if err := dw.processChange(dw.egCtx, ChangeKindAdd, p, fi, &lazyFileWriter{ + if err := dw.processChange(ChangeKindAdd, p, fi, &lazyFileWriter{ dest: dest, }); err != nil { return err @@ -239,7 +237,7 @@ func (dw *DiskWriter) requestAsyncFileData(p, dest string, fi os.FileInfo, st *t }) } -func (dw *DiskWriter) processChange(ctx context.Context, kind ChangeKind, p string, fi os.FileInfo, w io.WriteCloser) error { +func (dw *DiskWriter) processChange(kind ChangeKind, p string, fi os.FileInfo, w io.WriteCloser) error { origw := w var hw *hashedWriter if dw.opt.NotifyCb != nil { @@ -254,7 +252,7 @@ func (dw *DiskWriter) processChange(ctx context.Context, kind ChangeKind, p stri if fn == nil && dw.opt.AsyncDataCb != nil { fn = dw.opt.AsyncDataCb } - if err := fn(ctx, p, w); err != nil { + if err := fn(dw.ctx, p, w); err != nil { return err } } else { @@ -315,7 +313,7 @@ type lazyFileWriter struct { func (lfw *lazyFileWriter) Write(dt []byte) (int, error) { if lfw.f == nil { - file, err := os.OpenFile(lfw.dest, os.O_WRONLY, 0) + file, err := os.OpenFile(lfw.dest, os.O_WRONLY, 0) //todo: windows if os.IsPermission(err) { // retry after chmod fi, er := os.Stat(lfw.dest) diff --git a/vendor/github.com/tonistiigi/fsutil/hardlinks.go b/vendor/github.com/tonistiigi/fsutil/hardlinks.go index d9bf2fc1c..ef8bbfb5d 100644 --- a/vendor/github.com/tonistiigi/fsutil/hardlinks.go +++ b/vendor/github.com/tonistiigi/fsutil/hardlinks.go @@ -1,9 +1,6 @@ package fsutil import ( - "context" - "io" - gofs "io/fs" "os" "syscall" @@ -49,68 +46,3 @@ func (v *Hardlinks) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err return nil } - -// WithHardlinkReset returns a FS that fixes hardlinks for FS that has been filtered -// so that original hardlink sources might be missing -func WithHardlinkReset(fs FS) FS { - return &hardlinkFilter{fs: fs} -} - -type hardlinkFilter struct { - fs FS -} - -var _ FS = &hardlinkFilter{} - -func (r *hardlinkFilter) Walk(ctx context.Context, target string, fn gofs.WalkDirFunc) error { - seenFiles := make(map[string]string) - return r.fs.Walk(ctx, target, func(path string, entry gofs.DirEntry, err error) error { - if err != nil { - return err - } - - fi, err := entry.Info() - if err != nil { - return err - } - - if fi.IsDir() || fi.Mode()&os.ModeSymlink != 0 { - return fn(path, entry, nil) - } - - stat, ok := fi.Sys().(*types.Stat) - if !ok { - return errors.WithStack(&os.PathError{Path: path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"}) - } - - if stat.Linkname != "" { - if v, ok := seenFiles[stat.Linkname]; !ok { - seenFiles[stat.Linkname] = stat.Path - stat.Linkname = "" - entry = &dirEntryWithStat{DirEntry: entry, stat: stat} - } else { - if v != stat.Path { - stat.Linkname = v - entry = &dirEntryWithStat{DirEntry: entry, stat: stat} - } - } - } - - seenFiles[path] = stat.Path - - return fn(path, entry, nil) - }) -} - -func (r *hardlinkFilter) Open(p string) (io.ReadCloser, error) { - return r.fs.Open(p) -} - -type dirEntryWithStat struct { - gofs.DirEntry - stat *types.Stat -} - -func (d *dirEntryWithStat) Info() (gofs.FileInfo, error) { - return &StatInfo{d.stat}, nil -} diff --git a/vendor/github.com/tonistiigi/fsutil/receive.go b/vendor/github.com/tonistiigi/fsutil/receive.go index 07a68db71..9924ce072 100644 --- a/vendor/github.com/tonistiigi/fsutil/receive.go +++ b/vendor/github.com/tonistiigi/fsutil/receive.go @@ -1,42 +1,10 @@ -// send.go and receive.go describe the fsutil file-transfer protocol, which -// allows transferring file trees across a network connection. -// -// The protocol operates as follows: -// - The client (the receiver) connects to the server (the sender). -// - The sender walks the target tree lexicographically and sends a series of -// STAT packets that describe each file (an empty stat indicates EOF). -// - The receiver sends a REQ packet for each file it requires the contents for, -// using the ID for the file (determined as its index in the STAT sequence). -// - The sender sends a DATA packet with byte arrays for the contents of the -// file, associated with an ID (an empty array indicates EOF). -// - Once the receiver has received all files it wants, it sends a FIN packet, -// and the file transfer is complete. -// If an error is encountered on either side, an ERR packet is sent containing -// a human-readable error. -// -// All paths transferred over the protocol are normalized to unix-style paths, -// regardless of which platforms are present on either side. These path -// conversions are performed right before sending a STAT packet (for the -// sender) or right after receiving the corresponding STAT packet (for the -// receiver); this abstraction doesn't leak into the rest of fsutil, which -// operates on native platform-specific paths. -// -// Note that in the case of cross-platform file transfers, the transfer is -// best-effort. Some filenames that are valid on a unix sender would not be -// valid on a windows receiver, so these paths are rejected as they are -// received. Additionally, file metadata, like user/group owners and xattrs do -// not have an exact correspondence on windows, and so would be discarded by -// a windows receiver. - package fsutil import ( "context" "io" "os" - "path/filepath" "sync" - "syscall" "github.com/pkg/errors" "github.com/tonistiigi/fsutil/types" @@ -221,30 +189,16 @@ func (r *receiver) run(ctx context.Context) error { } break } -<<<<<<< HEAD if r.verboseProgressCb != nil { r.verboseProgressCb(p.Stat.Path, StatusStat, p.Size()) } -======= - - // normalize unix wire-specific paths to platform-specific paths - path := filepath.FromSlash(p.Stat.Path) - if filepath.ToSlash(path) != p.Stat.Path { - // e.g. a linux path foo/bar\baz cannot be represented on windows - return errors.WithStack(&os.PathError{Path: p.Stat.Path, Err: syscall.EINVAL, Op: "unrepresentable path"}) - } - p.Stat.Path = path - p.Stat.Linkname = filepath.FromSlash(p.Stat.Linkname) - ->>>>>>> v0.14.1 if fileCanRequestData(os.FileMode(p.Stat.Mode)) { r.mu.Lock() r.files[p.Stat.Path] = i r.mu.Unlock() } i++ - - cp := ¤tPath{path: path, stat: p.Stat} + cp := ¤tPath{path: p.Stat.Path, stat: p.Stat} if err := r.orderValidator.HandleChange(ChangeKindAdd, cp.path, &StatInfo{cp.stat}, nil); err != nil { return err } diff --git a/vendor/github.com/tonistiigi/fsutil/send.go b/vendor/github.com/tonistiigi/fsutil/send.go index e4ade9d00..7fe01a07e 100644 --- a/vendor/github.com/tonistiigi/fsutil/send.go +++ b/vendor/github.com/tonistiigi/fsutil/send.go @@ -27,20 +27,12 @@ type Stream interface { func Send(ctx context.Context, conn Stream, fs FS, progressCb func(int, bool), verboseProgressCb VerboseProgressCB) error { s := &sender{ -<<<<<<< HEAD conn: &syncStream{Stream: conn}, fs: fs, files: make(map[uint32]string), progressCb: progressCb, verboseProgressCb: verboseProgressCb, sendpipeline: make(chan *sendHandle, 128), -======= - conn: &syncStream{Stream: conn}, - fs: WithHardlinkReset(fs), - files: make(map[uint32]string), - progressCb: progressCb, - sendpipeline: make(chan *sendHandle, 128), ->>>>>>> v0.14.1 } return s.run(ctx) } @@ -56,13 +48,8 @@ type sender struct { files map[uint32]string mu sync.RWMutex progressCb func(int, bool) -<<<<<<< HEAD verboseProgressCb VerboseProgressCB progressCurrent int -======= - progressCurrent int - progressCurrentMu sync.Mutex ->>>>>>> v0.14.1 sendpipeline chan *sendHandle } @@ -129,12 +116,6 @@ func (s *sender) updateProgress(size int, last bool) { defer s.mu.Unlock() s.progressCurrent += size if s.progressCb != nil { -<<<<<<< HEAD -======= - s.progressCurrentMu.Lock() - defer s.progressCurrentMu.Unlock() - s.progressCurrent += size ->>>>>>> v0.14.1 s.progressCb(s.progressCurrent, last) } } @@ -183,12 +164,7 @@ func (s *sender) walk(ctx context.Context) error { if !ok { return errors.WithStack(&os.PathError{Path: path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"}) } -<<<<<<< HEAD -======= - stat.Path = filepath.ToSlash(stat.Path) - stat.Linkname = filepath.ToSlash(stat.Linkname) ->>>>>>> v0.14.1 p := &types.Packet{ Type: types.PACKET_STAT, Stat: stat, diff --git a/vendor/modules.txt b/vendor/modules.txt index df15273af..36adbe574 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -455,7 +455,6 @@ github.com/docker/cli/cli/config/configfile github.com/docker/cli/cli/config/credentials github.com/docker/cli/cli/config/types github.com/docker/cli/cli/connhelper/commandconn -<<<<<<< HEAD # github.com/docker/distribution v2.8.2+incompatible ## explicit github.com/docker/distribution @@ -495,10 +494,7 @@ github.com/docker/distribution/registry/storage/driver/factory github.com/docker/distribution/registry/storage/driver/middleware github.com/docker/distribution/uuid github.com/docker/distribution/version -# github.com/docker/docker v25.0.3+incompatible -======= # github.com/docker/docker v26.1.4+incompatible ->>>>>>> v0.14.1 ## explicit github.com/docker/docker/api github.com/docker/docker/api/types @@ -643,7 +639,6 @@ github.com/google/shlex # github.com/google/uuid v1.5.0 ## explicit github.com/google/uuid -<<<<<<< HEAD # github.com/gorilla/handlers v1.5.2 ## explicit; go 1.20 github.com/gorilla/handlers @@ -652,12 +647,9 @@ github.com/gorilla/handlers github.com/gorilla/mux # github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 ## explicit; go 1.14 -github.com/grpc-ecosystem/go-grpc-middleware github.com/grpc-ecosystem/go-grpc-middleware/retry github.com/grpc-ecosystem/go-grpc-middleware/util/backoffutils github.com/grpc-ecosystem/go-grpc-middleware/util/metautils -======= ->>>>>>> v0.14.1 # github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 ## explicit; go 1.17 github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule @@ -829,13 +821,8 @@ github.com/spdx/tools-golang/spdx/v2/v2_3 ## explicit; go 1.20 github.com/stretchr/testify/assert github.com/stretchr/testify/require -<<<<<<< HEAD # github.com/tonistiigi/fsutil v0.0.0-20240424095704-91a3fc46842c => github.com/alexcb/fsutil v0.0.0-20231030221755-644b08355b65 ## explicit; go 1.19 -======= -# github.com/tonistiigi/fsutil v0.0.0-20240424095704-91a3fc46842c -## explicit; go 1.20 ->>>>>>> v0.14.1 github.com/tonistiigi/fsutil github.com/tonistiigi/fsutil/copy github.com/tonistiigi/fsutil/types From d92c00a88d8296cf83267e7aea3db61cc8f6845b Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 2 Oct 2026 20:58:46 +0100 Subject: [PATCH 02/17] chore: earthbuild/fsutil --- client/client.go | 8 +-- client/llb/exec.go | 2 +- exporter/earthlyoutputs/export.go | 8 +-- .../registry/eodriver/multimultiprovider.go | 14 ++-- frontend/gateway/container/container.go | 2 +- go.mod | 2 +- go.sum | 4 +- session/filesync/diffcopy.go | 2 +- session/localhost/localhost.go | 2 +- solver/llbsolver/bridge.go | 2 +- solver/llbsolver/ops/exec.go | 12 ++-- util/gitutil/git_cli.go | 6 +- .../github.com/tonistiigi/fsutil/.gitignore | 6 +- .../tonistiigi/fsutil/.golangci.yml | 14 ++++ .../github.com/tonistiigi/fsutil/Dockerfile | 18 +++-- .../github.com/tonistiigi/fsutil/codecov.yml | 12 ++++ .../github.com/tonistiigi/fsutil/copy/copy.go | 69 +++++++++++++------ .../tonistiigi/fsutil/copy/copy_darwin.go | 2 +- .../tonistiigi/fsutil/copy/copy_linux.go | 11 ++- .../tonistiigi/fsutil/copy/copy_unix.go | 11 ++- .../tonistiigi/fsutil/diff_containerd.go | 5 +- .../tonistiigi/fsutil/diskwriter.go | 20 +++--- .../tonistiigi/fsutil/docker-bake.hcl | 12 +++- vendor/github.com/tonistiigi/fsutil/filter.go | 22 ++++-- .../tonistiigi/fsutil/followlinks.go | 8 +-- .../github.com/tonistiigi/fsutil/hardlinks.go | 68 ++++++++++++++++++ vendor/github.com/tonistiigi/fsutil/readme.md | 5 ++ .../github.com/tonistiigi/fsutil/receive.go | 45 +++++++++++- vendor/github.com/tonistiigi/fsutil/send.go | 10 ++- vendor/github.com/tonistiigi/fsutil/stat.go | 2 +- .../github.com/tonistiigi/fsutil/validator.go | 22 +++--- vendor/modules.txt | 6 +- worker/runc/runc.go | 2 +- 33 files changed, 322 insertions(+), 112 deletions(-) create mode 100644 vendor/github.com/tonistiigi/fsutil/codecov.yml diff --git a/client/client.go b/client/client.go index 7e36d8948..29a62a4e9 100644 --- a/client/client.go +++ b/client/client.go @@ -44,12 +44,12 @@ type ClientOpt interface { // New returns a new buildkit client. Address can be empty for the system-default address. func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error) { gopts := []grpc.DialOption{ - grpc.WithInitialWindowSize(65535 * 32), //earthly - grpc.WithInitialConnWindowSize(65535 * 16), //earthly + grpc.WithInitialWindowSize(65535 * 32), // earthly + grpc.WithInitialConnWindowSize(65535 * 16), // earthly grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)), grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)), - grpc.WithDefaultCallOptions(grpc_retry.WithMax(8)), //earthly - grpc.WithDefaultCallOptions(grpc_retry.WithBackoff(grpc_retry.BackoffExponentialWithJitter(10*time.Millisecond, 0.1))), //earthly + grpc.WithDefaultCallOptions(grpc_retry.WithMax(8)), // earthly + grpc.WithDefaultCallOptions(grpc_retry.WithBackoff(grpc_retry.BackoffExponentialWithJitter(10*time.Millisecond, 0.1))), // earthly } needDialer := true diff --git a/client/llb/exec.go b/client/llb/exec.go index 606004814..8a5bcdbb6 100644 --- a/client/llb/exec.go +++ b/client/llb/exec.go @@ -389,7 +389,7 @@ func (e *ExecOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, [] Size_: m.tmpfsOpt.Size, } } - if m.hostBind { //earthly + if m.hostBind { // earthly pm.MountType = pb.MountType_HOST_BIND } peo.Mounts = append(peo.Mounts, pm) diff --git a/exporter/earthlyoutputs/export.go b/exporter/earthlyoutputs/export.go index 4b9bb0617..d9494324b 100644 --- a/exporter/earthlyoutputs/export.go +++ b/exporter/earthlyoutputs/export.go @@ -831,10 +831,10 @@ func exportDirFunc(ctx context.Context, md map[string]string, caller session.Cal // apply host uid/gid res = idMapFunc(p, st) } - //TODO if opt.Epoch != nil { - //TODO // apply used-specified epoch time - //TODO st.ModTime = opt.Epoch.UnixNano() - //TODO } + // TODO if opt.Epoch != nil { + // TODO // apply used-specified epoch time + // TODO st.ModTime = opt.Epoch.UnixNano() + // TODO } return res } fs, err = fsutil.NewFilterFS(fs, filterOpt) diff --git a/exporter/earthlyoutputs/registry/eodriver/multimultiprovider.go b/exporter/earthlyoutputs/registry/eodriver/multimultiprovider.go index 2a8cd45a8..d4ab8435e 100644 --- a/exporter/earthlyoutputs/registry/eodriver/multimultiprovider.go +++ b/exporter/earthlyoutputs/registry/eodriver/multimultiprovider.go @@ -6,7 +6,7 @@ import ( "sync" "github.com/containerd/containerd/content" - "github.com/containerd/containerd/errdefs" + cerrdefs "github.com/containerd/errdefs" "github.com/moby/buildkit/util/contentutil" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" @@ -45,26 +45,26 @@ func (mmp *MultiMultiProvider) ReaderAt(ctx context.Context, desc ocispecs.Descr imgs := mmp.digests[desc.Digest] // take the first one if multiple are found. for imgName := range imgs { - mp, _, err := mmp.getNoLock(ctx, imgName) + mp, _, err := mmp.getNoLock(imgName) if err != nil { continue } return mp.ReaderAt(ctx, desc) } - return nil, errors.Wrapf(errdefs.ErrNotFound, "content %v", desc.Digest) + return nil, errors.Wrapf(cerrdefs.ErrNotFound, "content %v", desc.Digest) } // Get returns a read-only MultiProvider and the base digest for a given imgName. func (mmp *MultiMultiProvider) Get(ctx context.Context, imgName string) (*contentutil.MultiProvider, digest.Digest, error) { mmp.mu.RLock() defer mmp.mu.RUnlock() - return mmp.getNoLock(ctx, imgName) + return mmp.getNoLock(imgName) } -func (mmp *MultiMultiProvider) getNoLock(ctx context.Context, imgName string) (*contentutil.MultiProvider, digest.Digest, error) { +func (mmp *MultiMultiProvider) getNoLock(imgName string) (*contentutil.MultiProvider, digest.Digest, error) { imgData, ok := mmp.imgs[imgName] if !ok { - return nil, "", errors.Wrapf(errdefs.ErrNotFound, "img name %v", imgName) + return nil, "", errors.Wrapf(cerrdefs.ErrNotFound, "img name %v", imgName) } mp := contentutil.NewMultiProvider(imgData.base) for dgst, p := range imgData.subs { @@ -79,7 +79,7 @@ func (mmp *MultiMultiProvider) AddImgSub(imgName string, dgst digest.Digest, p c defer mmp.mu.Unlock() imgData, ok := mmp.imgs[imgName] if !ok { - return errors.Wrapf(errdefs.ErrNotFound, "img name %v", imgName) + return errors.Wrapf(cerrdefs.ErrNotFound, "img name %v", imgName) } imgData.subs[dgst] = p mmp.addDigestEntry(dgst, imgName) diff --git a/frontend/gateway/container/container.go b/frontend/gateway/container/container.go index f8a15a878..83fb88657 100644 --- a/frontend/gateway/container/container.go +++ b/frontend/gateway/container/container.go @@ -164,7 +164,7 @@ func PrepareMounts(ctx context.Context, mm *mounts.MountManager, cm cache.Manage } switch m.MountType { - case opspb.MountType_HOST_BIND: //earthly + case opspb.MountType_HOST_BIND: // earthly mountable = mm.MountableHostBind(ctx, m) case opspb.MountType_BIND: diff --git a/go.mod b/go.mod index eaa01f1bd..2d4931137 100644 --- a/go.mod +++ b/go.mod @@ -183,4 +183,4 @@ require ( kernel.org/pub/linux/libs/security/libcap/psx v1.2.67 // indirect ) -replace github.com/tonistiigi/fsutil => github.com/alexcb/fsutil v0.0.0-20231030221755-644b08355b65 +replace github.com/tonistiigi/fsutil => github.com/earthbuild/fsutil v0.0.0-20261002194825-890baaee2294 diff --git a/go.sum b/go.sum index 4503729e9..545c44553 100644 --- a/go.sum +++ b/go.sum @@ -30,8 +30,6 @@ github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7l github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alexcb/fsutil v0.0.0-20231030221755-644b08355b65 h1:owMPrDW24IXzQwhrg6DAM7a5VFdOoRoQ4urVFCaGMy4= -github.com/alexcb/fsutil v0.0.0-20231030221755-644b08355b65/go.mod h1:9kMVqMyQ/Sx2df5LtnGG+nbrmiZzCS7V6gjW3oGHsvI= github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 h1:aM1rlcoLz8y5B2r4tTLMiVTrMtpfY0O8EScKJxaSaEc= github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA= github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloDxZfhMm0xrLXZS8+COSu2bXmEQs= @@ -157,6 +155,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/earthbuild/fsutil v0.0.0-20261002194825-890baaee2294 h1:gFtQodZi786++bc4OPIeVKIwrQWdP0sJLGCHKWenQmo= +github.com/earthbuild/fsutil v0.0.0-20261002194825-890baaee2294/go.mod h1:vbbYqJlnswsbJqWUcJN8fKtBhnEgldDrcagTgnBVKKM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= diff --git a/session/filesync/diffcopy.go b/session/filesync/diffcopy.go index c5ae8c8f0..46b29020e 100644 --- a/session/filesync/diffcopy.go +++ b/session/filesync/diffcopy.go @@ -22,7 +22,7 @@ type Stream interface { } func sendDiffCopy(stream Stream, fs fsutil.FS, progress progressCb) error { - return errors.WithStack(fsutil.Send(stream.Context(), stream, fs, progress, nil)) //earthly needs to pass nil + return errors.WithStack(fsutil.Send(stream.Context(), stream, fs, progress, nil)) // earthly needs to pass nil } func newStreamWriter(stream grpc.ClientStream) io.WriteCloser { diff --git a/session/localhost/localhost.go b/session/localhost/localhost.go index 32a9628e1..14bdc3b44 100644 --- a/session/localhost/localhost.go +++ b/session/localhost/localhost.go @@ -65,7 +65,7 @@ func LocalhostExec(ctx context.Context, c session.Caller, args []string, dir str stderr.Write(msg.Stderr) switch msg.Status { case RUNNING: - //ignore + // ignore case DONE: if exitCodeSet { panic("received multiple DONE messages (shouldn't happen)") diff --git a/solver/llbsolver/bridge.go b/solver/llbsolver/bridge.go index 5e02a6cdd..86d43aa7c 100644 --- a/solver/llbsolver/bridge.go +++ b/solver/llbsolver/bridge.go @@ -189,7 +189,7 @@ func (b *llbBridge) loadResult(ctx context.Context, def *pb.Definition, cacheImp func (b *llbBridge) getExporter(ctx context.Context) (*ExporterRequest, error) { var exp *ExporterRequest numExporters := 0 - b.builder.EachValue(context.TODO(), keyEarthlyExporterInstance, func(v interface{}) error { + b.builder.EachValue(ctx, keyEarthlyExporterInstance, func(v interface{}) error { numExporters++ exp = v.(*ExporterRequest) return nil diff --git a/solver/llbsolver/ops/exec.go b/solver/llbsolver/ops/exec.go index a33f6dd8a..927533584 100644 --- a/solver/llbsolver/ops/exec.go +++ b/solver/llbsolver/ops/exec.go @@ -532,17 +532,17 @@ func (e *ExecOp) doFromLocalHack(ctx context.Context, root executor.Mount, mount } switch cmd { case localhost.CopyFileMagicStr: - return true, e.copyLocally(ctx, root, g, meta, stdout, stderr) + return true, e.copyLocally(ctx, root, g, meta) case localhost.RunOnLocalHostMagicStr: - return true, e.execLocally(ctx, root, g, meta, stdout, stderr) + return true, e.execLocally(ctx, g, meta, stdout, stderr) case localhost.SendFileMagicStr: - return true, e.sendLocally(ctx, root, mounts, g, meta, stdout, stderr) + return true, e.sendLocally(ctx, mounts, g, meta) default: return false, nil } } -func (e *ExecOp) copyLocally(ctx context.Context, root executor.Mount, g session.Group, meta executor.Meta, stdout, stderr io.WriteCloser) error { +func (e *ExecOp) copyLocally(ctx context.Context, root executor.Mount, g session.Group, meta executor.Meta) error { if len(meta.Args) != 3 { return errors.Errorf("CopyFileMagicStr takes exactly 2 args") } @@ -596,7 +596,7 @@ func (e *ExecOp) copyLocally(ctx context.Context, root executor.Mount, g session var errSendFileMagicStrMissingArgs = errors.Errorf("SendFileMagicStr args missing; should be SendFileMagicStr [--dir] [--] [ ...] ") -func (e *ExecOp) sendLocally(ctx context.Context, root executor.Mount, mounts []executor.Mount, g session.Group, meta executor.Meta, stdout, stderr io.WriteCloser) error { +func (e *ExecOp) sendLocally(ctx context.Context, mounts []executor.Mount, g session.Group, meta executor.Meta) error { i := 0 nArgs := len(meta.Args) @@ -678,7 +678,7 @@ func (e *ExecOp) sendLocally(ctx context.Context, root executor.Mount, mounts [] }) } -func (e *ExecOp) execLocally(ctx context.Context, root executor.Mount, g session.Group, meta executor.Meta, stdout, stderr io.WriteCloser) error { +func (e *ExecOp) execLocally(ctx context.Context, g session.Group, meta executor.Meta, stdout, stderr io.WriteCloser) error { if len(meta.Args) == 0 || meta.Args[0] != localhost.RunOnLocalHostMagicStr { panic("first arg should be RunOnLocalHostMagicStr; this should not happen") } diff --git a/util/gitutil/git_cli.go b/util/gitutil/git_cli.go index 5b895cac2..5eb642bc0 100644 --- a/util/gitutil/git_cli.go +++ b/util/gitutil/git_cli.go @@ -238,8 +238,8 @@ func (cli *GitCLI) Run(ctx context.Context, args ...string) (_ []byte, err error "GIT_SSH_COMMAND=" + getGitSSHCommand(cli.sshKnownHosts, logLevel, cli.sshCommand), // "GIT_TRACE=1", // earthly-specific: Commented out. We do not want to disable reading from gitconfig. - //"GIT_CONFIG_NOSYSTEM=1", // Disable reading from system gitconfig. - //"HOME=/dev/null", // Disable reading from user gitconfig. + // "GIT_CONFIG_NOSYSTEM=1", // Disable reading from system gitconfig. + // "HOME=/dev/null", // Disable reading from user gitconfig. "LC_ALL=C", // Ensure consistent output. } @@ -279,7 +279,7 @@ func (cli *GitCLI) Run(ctx context.Context, args ...string) (_ []byte, err error } // Earthly-TODO: moby/master didn't use to include the git stderr; however, change it at some point AFTER we added in this EARTHLY_GIT_STDERR hack; however we will keep ours for the time being (since we look specifically for EARTHLY_GIT_STDERR in earthly) - //return buf.Bytes(), errors.Errorf("git error: %s\nstderr:\n%s", err, errbuf.String()) + // return buf.Bytes(), errors.Errorf("git error: %s\nstderr:\n%s", err, errbuf.String()) // earthly-specific if gitDebug() { diff --git a/vendor/github.com/tonistiigi/fsutil/.gitignore b/vendor/github.com/tonistiigi/fsutil/.gitignore index 51b9602c8..e5c343e2d 100644 --- a/vendor/github.com/tonistiigi/fsutil/.gitignore +++ b/vendor/github.com/tonistiigi/fsutil/.gitignore @@ -1,9 +1,5 @@ # if you want to ignore files created by your editor/tools, consider using a # global .gitignore or .git/info/exclude see https://help.github.com/articles/ignoring-files -.* -!.github -!.gitignore -!.travis.yml -*.prof +bin/ # support running go modules in vendor mode for local development vendor/ diff --git a/vendor/github.com/tonistiigi/fsutil/.golangci.yml b/vendor/github.com/tonistiigi/fsutil/.golangci.yml index 2a8b86ae2..7300a0e58 100644 --- a/vendor/github.com/tonistiigi/fsutil/.golangci.yml +++ b/vendor/github.com/tonistiigi/fsutil/.golangci.yml @@ -14,3 +14,17 @@ linters: - staticcheck - typecheck disable-all: true + +linters-settings: + depguard: + rules: + main: + deny: + # The io/ioutil package has been deprecated. + # https://go.dev/doc/go1.16#ioutil + - pkg: "io/ioutil" + desc: The io/ioutil package has been deprecated. + +# show all +max-issues-per-linter: 0 +max-same-issues: 0 diff --git a/vendor/github.com/tonistiigi/fsutil/Dockerfile b/vendor/github.com/tonistiigi/fsutil/Dockerfile index 9584648d0..21c1f39f6 100644 --- a/vendor/github.com/tonistiigi/fsutil/Dockerfile +++ b/vendor/github.com/tonistiigi/fsutil/Dockerfile @@ -1,7 +1,9 @@ -#syntax=docker/dockerfile:1 -ARG GO_VERSION=1.20 +# syntax=docker/dockerfile:1 -FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.1.0 AS xx +ARG GO_VERSION=1.21 +ARG XX_VERSION=1.4.0 + +FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS base RUN apk add --no-cache git @@ -18,13 +20,19 @@ FROM base AS test ARG TESTFLAGS RUN --mount=target=. --mount=target=/go/pkg/mod,type=cache \ --mount=target=/root/.cache,type=cache \ - CGO_ENABLED=0 xx-go test -test.v ${TESTFLAGS} ./... + CGO_ENABLED=0 xx-go test -v -coverprofile=/tmp/coverage.txt -covermode=atomic ${TESTFLAGS} ./... FROM base AS test-noroot RUN mkdir /go/pkg && chmod 0777 /go/pkg USER 1000:1000 RUN --mount=target=. \ --mount=target=/tmp/.cache,type=cache \ - CGO_ENABLED=0 GOCACHE=/tmp/gocache xx-go test -test.v ./... + CGO_ENABLED=0 GOCACHE=/tmp/gocache xx-go test -v -coverprofile=/tmp/coverage.txt -covermode=atomic ./... + +FROM scratch AS test-coverage +COPY --from=test /tmp/coverage.txt /coverage-root.txt + +FROM scratch AS test-noroot-coverage +COPY --from=test-noroot /tmp/coverage.txt /coverage-noroot.txt FROM build diff --git a/vendor/github.com/tonistiigi/fsutil/codecov.yml b/vendor/github.com/tonistiigi/fsutil/codecov.yml new file mode 100644 index 000000000..f5f9e02cc --- /dev/null +++ b/vendor/github.com/tonistiigi/fsutil/codecov.yml @@ -0,0 +1,12 @@ +comment: false + +coverage: + status: + project: # settings affecting project coverage + default: + target: auto # auto % coverage target + threshold: 1% # allow for 1% reduction of coverage without failing + patch: off + +github_checks: + annotations: false diff --git a/vendor/github.com/tonistiigi/fsutil/copy/copy.go b/vendor/github.com/tonistiigi/fsutil/copy/copy.go index 558c553f7..f8cc0a433 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/copy.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/copy.go @@ -88,7 +88,7 @@ func Copy(ctx context.Context, srcRoot, src, dstRoot, dst string, opts ...Opt) e return err } - c, err := newCopier(dstRoot, ci.Chown, ci.Utime, ci.Mode, ci.XAttrErrorHandler, ci.IncludePatterns, ci.ExcludePatterns, ci.ChangeFunc) + c, err := newCopier(dstRoot, ci.Chown, ci.Utime, ci.Mode, ci.XAttrErrorHandler, ci.IncludePatterns, ci.ExcludePatterns, ci.AlwaysReplaceExistingDestPaths, ci.ChangeFunc) if err != nil { return err } @@ -172,7 +172,11 @@ type CopyInfo struct { IncludePatterns []string // Exclude files/dir matching any of these patterns (even if they match an include pattern) ExcludePatterns []string - ChangeFunc fsutil.ChangeFunc + // If true, any source path that overwrite existing destination paths will always replace + // the existing destination path, even if they are of different types (e.g. a directory will + // replace any existing symlink or file) + AlwaysReplaceExistingDestPaths bool + ChangeFunc fsutil.ChangeFunc } type Opt func(*CopyInfo) @@ -227,16 +231,17 @@ func WithChangeNotifier(fn fsutil.ChangeFunc) Opt { } type copier struct { - chown Chowner - utime *time.Time - mode *int - inodes map[uint64]string - xattrErrorHandler XAttrErrorHandler - includePatternMatcher *patternmatcher.PatternMatcher - excludePatternMatcher *patternmatcher.PatternMatcher - parentDirs []parentDir - changefn fsutil.ChangeFunc - root string + chown Chowner + utime *time.Time + mode *int + inodes map[uint64]string + xattrErrorHandler XAttrErrorHandler + includePatternMatcher *patternmatcher.PatternMatcher + excludePatternMatcher *patternmatcher.PatternMatcher + parentDirs []parentDir + changefn fsutil.ChangeFunc + root string + alwaysReplaceExistingDestPaths bool } type parentDir struct { @@ -245,7 +250,7 @@ type parentDir struct { copied bool } -func newCopier(root string, chown Chowner, tm *time.Time, mode *int, xeh XAttrErrorHandler, includePatterns, excludePatterns []string, changeFunc fsutil.ChangeFunc) (*copier, error) { +func newCopier(root string, chown Chowner, tm *time.Time, mode *int, xeh XAttrErrorHandler, includePatterns, excludePatterns []string, alwaysReplaceExistingDestPaths bool, changeFunc fsutil.ChangeFunc) (*copier, error) { if xeh == nil { xeh = func(dst, src, key string, err error) error { return err @@ -271,15 +276,16 @@ func newCopier(root string, chown Chowner, tm *time.Time, mode *int, xeh XAttrEr } return &copier{ - root: root, - inodes: map[uint64]string{}, - chown: chown, - utime: tm, - xattrErrorHandler: xeh, - mode: mode, - includePatternMatcher: includePatternMatcher, - excludePatternMatcher: excludePatternMatcher, - changefn: changeFunc, + root: root, + inodes: map[uint64]string{}, + chown: chown, + utime: tm, + xattrErrorHandler: xeh, + mode: mode, + includePatternMatcher: includePatternMatcher, + excludePatternMatcher: excludePatternMatcher, + changefn: changeFunc, + alwaysReplaceExistingDestPaths: alwaysReplaceExistingDestPaths, }, nil } @@ -324,6 +330,10 @@ func (c *copier) copy(ctx context.Context, src, srcComponents, target string, ov } if include { + if err := c.removeTargetIfNeeded(src, target, fi, targetFi); err != nil { + return err + } + if err := c.createParentDirs(src, srcComponents, target, overwriteTargetMetadata); err != nil { return err } @@ -440,6 +450,21 @@ func (c *copier) exclude(path string, fi os.FileInfo, parentExcludeMatchInfo pat return m, matchInfo, nil } +func (c *copier) removeTargetIfNeeded(src, target string, srcFi, targetFi os.FileInfo) error { + if !c.alwaysReplaceExistingDestPaths { + return nil + } + if targetFi == nil { + // already doesn't exist + return nil + } + if srcFi.IsDir() && targetFi.IsDir() { + // directories are merged, not replaced + return nil + } + return os.RemoveAll(target) +} + // Delayed creation of parent directories when a file or dir matches an include // pattern. func (c *copier) createParentDirs(src, srcComponents, target string, overwriteTargetMetadata bool) error { diff --git a/vendor/github.com/tonistiigi/fsutil/copy/copy_darwin.go b/vendor/github.com/tonistiigi/fsutil/copy/copy_darwin.go index bc93b21ce..0cdc00a82 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/copy_darwin.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/copy_darwin.go @@ -13,7 +13,7 @@ import ( func copyFile(source, target string) error { if err := unix.Clonefileat(unix.AT_FDCWD, source, unix.AT_FDCWD, target, unix.CLONE_NOFOLLOW); err != nil { - if err != unix.EINVAL { + if err != unix.EINVAL && err != unix.EXDEV { return err } } else { diff --git a/vendor/github.com/tonistiigi/fsutil/copy/copy_linux.go b/vendor/github.com/tonistiigi/fsutil/copy/copy_linux.go index 971cb5c5d..6d9b490c6 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/copy_linux.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/copy_linux.go @@ -30,7 +30,16 @@ func (c *copier) copyFileInfo(fi os.FileInfo, src, name string) error { m := fi.Mode() if c.mode != nil { - m = (m & ^os.FileMode(0777)) | os.FileMode(*c.mode&0777) + m = os.FileMode(*c.mode).Perm() + if *c.mode&syscall.S_ISGID != 0 { + m |= os.ModeSetgid + } + if *c.mode&syscall.S_ISUID != 0 { + m |= os.ModeSetuid + } + if *c.mode&syscall.S_ISVTX != 0 { + m |= os.ModeSticky + } } if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink { if err := os.Chmod(name, m); err != nil { diff --git a/vendor/github.com/tonistiigi/fsutil/copy/copy_unix.go b/vendor/github.com/tonistiigi/fsutil/copy/copy_unix.go index 945e96c5f..4a7d0c86b 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/copy_unix.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/copy_unix.go @@ -31,7 +31,16 @@ func (c *copier) copyFileInfo(fi os.FileInfo, src, name string) error { m := fi.Mode() if c.mode != nil { - m = (m & ^os.FileMode(0777)) | os.FileMode(*c.mode&0777) + m = os.FileMode(*c.mode).Perm() + if *c.mode&syscall.S_ISGID != 0 { + m |= os.ModeSetgid + } + if *c.mode&syscall.S_ISUID != 0 { + m |= os.ModeSetuid + } + if *c.mode&syscall.S_ISVTX != 0 { + m |= os.ModeSticky + } } if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink { if err := os.Chmod(name, m); err != nil { diff --git a/vendor/github.com/tonistiigi/fsutil/diff_containerd.go b/vendor/github.com/tonistiigi/fsutil/diff_containerd.go index d8619abf1..86d646027 100644 --- a/vendor/github.com/tonistiigi/fsutil/diff_containerd.go +++ b/vendor/github.com/tonistiigi/fsutil/diff_containerd.go @@ -5,6 +5,7 @@ import ( "context" "io" "os" + "path/filepath" "strings" "github.com/tonistiigi/fsutil/types" @@ -127,7 +128,7 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b walkerFn, fil f1 = nil continue } else if rmdir == "" && f1.stat.IsDir() { - rmdir = f1.path + string(os.PathSeparator) + rmdir = f1.path + string(filepath.Separator) } else if rmdir != "" { rmdir = "" } @@ -138,7 +139,7 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b walkerFn, fil return err } if f1.stat.IsDir() && !f2copy.stat.IsDir() { - rmdir = f1.path + string(os.PathSeparator) + rmdir = f1.path + string(filepath.Separator) } else if rmdir != "" { rmdir = "" } diff --git a/vendor/github.com/tonistiigi/fsutil/diskwriter.go b/vendor/github.com/tonistiigi/fsutil/diskwriter.go index 10b608513..a62c6b0c9 100644 --- a/vendor/github.com/tonistiigi/fsutil/diskwriter.go +++ b/vendor/github.com/tonistiigi/fsutil/diskwriter.go @@ -37,6 +37,7 @@ type DiskWriter struct { ctx context.Context cancel func() eg *errgroup.Group + egCtx context.Context filter FilterFunc dirModTimes map[string]int64 } @@ -50,13 +51,14 @@ func NewDiskWriter(ctx context.Context, dest string, opt DiskWriterOpt) (*DiskWr } ctx, cancel := context.WithCancel(ctx) - eg, ctx := errgroup.WithContext(ctx) + eg, egCtx := errgroup.WithContext(ctx) return &DiskWriter{ opt: opt, dest: dest, eg: eg, ctx: ctx, + egCtx: egCtx, cancel: cancel, filter: opt.Filter, dirModTimes: map[string]int64{}, @@ -98,7 +100,7 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er } }() - destPath := filepath.Join(dw.dest, filepath.FromSlash(p)) + destPath := filepath.Join(dw.dest, p) if kind == ChangeKindDelete { if dw.filter != nil { @@ -183,12 +185,12 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er } default: isRegularFile = true - file, err := os.OpenFile(newPath, os.O_CREATE|os.O_WRONLY, fi.Mode()) //todo: windows + file, err := os.OpenFile(newPath, os.O_CREATE|os.O_WRONLY, fi.Mode()) if err != nil { return errors.Wrapf(err, "failed to create %s", newPath) } if dw.opt.SyncDataCb != nil { - if err := dw.processChange(ChangeKindAdd, p, fi, file); err != nil { + if err := dw.processChange(dw.ctx, ChangeKindAdd, p, fi, file); err != nil { file.Close() return err } @@ -219,7 +221,7 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er dw.requestAsyncFileData(p, destPath, fi, &statCopy) } } else { - return dw.processChange(kind, p, fi, nil) + return dw.processChange(dw.ctx, kind, p, fi, nil) } return nil @@ -228,7 +230,7 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er func (dw *DiskWriter) requestAsyncFileData(p, dest string, fi os.FileInfo, st *types.Stat) { // todo: limit worker threads dw.eg.Go(func() error { - if err := dw.processChange(ChangeKindAdd, p, fi, &lazyFileWriter{ + if err := dw.processChange(dw.egCtx, ChangeKindAdd, p, fi, &lazyFileWriter{ dest: dest, }); err != nil { return err @@ -237,7 +239,7 @@ func (dw *DiskWriter) requestAsyncFileData(p, dest string, fi os.FileInfo, st *t }) } -func (dw *DiskWriter) processChange(kind ChangeKind, p string, fi os.FileInfo, w io.WriteCloser) error { +func (dw *DiskWriter) processChange(ctx context.Context, kind ChangeKind, p string, fi os.FileInfo, w io.WriteCloser) error { origw := w var hw *hashedWriter if dw.opt.NotifyCb != nil { @@ -252,7 +254,7 @@ func (dw *DiskWriter) processChange(kind ChangeKind, p string, fi os.FileInfo, w if fn == nil && dw.opt.AsyncDataCb != nil { fn = dw.opt.AsyncDataCb } - if err := fn(dw.ctx, p, w); err != nil { + if err := fn(ctx, p, w); err != nil { return err } } else { @@ -313,7 +315,7 @@ type lazyFileWriter struct { func (lfw *lazyFileWriter) Write(dt []byte) (int, error) { if lfw.f == nil { - file, err := os.OpenFile(lfw.dest, os.O_WRONLY, 0) //todo: windows + file, err := os.OpenFile(lfw.dest, os.O_WRONLY, 0) if os.IsPermission(err) { // retry after chmod fi, er := os.Stat(lfw.dest) diff --git a/vendor/github.com/tonistiigi/fsutil/docker-bake.hcl b/vendor/github.com/tonistiigi/fsutil/docker-bake.hcl index 6ba3c8672..48127d4ff 100644 --- a/vendor/github.com/tonistiigi/fsutil/docker-bake.hcl +++ b/vendor/github.com/tonistiigi/fsutil/docker-bake.hcl @@ -1,5 +1,9 @@ variable "GO_VERSION" { - default = "1.20" + default = null +} + +variable "DESTDIR" { + default = "./bin" } group "default" { @@ -18,12 +22,14 @@ group "test" { target "test-root" { inherits = ["build"] - target = "test" + target = "test-coverage" + output = ["${DESTDIR}/coverage"] } target "test-noroot" { inherits = ["build"] - target = "test-noroot" + target = "test-noroot-coverage" + output = ["${DESTDIR}/coverage"] } target "lint" { diff --git a/vendor/github.com/tonistiigi/fsutil/filter.go b/vendor/github.com/tonistiigi/fsutil/filter.go index 1925146c2..483980091 100644 --- a/vendor/github.com/tonistiigi/fsutil/filter.go +++ b/vendor/github.com/tonistiigi/fsutil/filter.go @@ -68,9 +68,9 @@ type filterFS struct { // NewFilterFS creates a new FS that filters the given FS using the given // FilterOpt. - +// // The returned FS will not contain any paths that do not match the provided -// include and exclude patterns, or that are are exlcluded using the mapping +// include and exclude patterns, or that are are excluded using the mapping // function. // // The FS is assumed to be a snapshot of the filesystem at the time of the @@ -98,7 +98,7 @@ func NewFilterFS(fs FS, opt *FilterOpt) (FS, error) { } patternChars := "*[]?^" - if os.PathSeparator != '\\' { + if filepath.Separator != '\\' { patternChars += `\` } @@ -179,6 +179,7 @@ func (fs *filterFS) Walk(ctx context.Context, target string, fn gofs.WalkDirFunc includeMatchInfo patternmatcher.MatchInfo excludeMatchInfo patternmatcher.MatchInfo calledFn bool + skipFn bool } // used only for include/exclude handling @@ -339,6 +340,9 @@ func (fs *filterFS) Walk(ctx context.Context, target string, fn gofs.WalkDirFunc } } for i, parentDir := range parentDirs { + if parentDir.skipFn { + return filepath.SkipDir + } if parentDir.calledFn { continue } @@ -358,15 +362,21 @@ func (fs *filterFS) Walk(ctx context.Context, target string, fn gofs.WalkDirFunc } if fs.mapFn != nil { result := fs.mapFn(parentStat.Path, parentStat) - if result == MapResultSkipDir || result == MapResultExclude { + if result == MapResultExclude { continue + } else if result == MapResultSkipDir { + parentDirs[i].skipFn = true + return filepath.SkipDir } } - if err := fn(parentStat.Path, &DirEntryInfo{Stat: parentStat}, nil); err != nil { + parentDirs[i].calledFn = true + if err := fn(parentStat.Path, &DirEntryInfo{Stat: parentStat}, nil); err == filepath.SkipDir { + parentDirs[i].skipFn = true + return filepath.SkipDir + } else if err != nil { return err } - parentDirs[i].calledFn = true } if err := fn(stat.Path, &DirEntryInfo{Stat: stat}, nil); err != nil { return err diff --git a/vendor/github.com/tonistiigi/fsutil/followlinks.go b/vendor/github.com/tonistiigi/fsutil/followlinks.go index 3a0bd2bb7..559291d79 100644 --- a/vendor/github.com/tonistiigi/fsutil/followlinks.go +++ b/vendor/github.com/tonistiigi/fsutil/followlinks.go @@ -137,8 +137,8 @@ func (r *symlinkResolver) readSymlink(p string, allowWildcard bool) ([]string, e func statFile(fs FS, root string) (os.DirEntry, error) { var out os.DirEntry - root = filepath.Clean(root) - if root == "/" || root == "." { + root = filepath.FromSlash(filepath.Clean(root)) + if root == string(filepath.Separator) || root == "." { return nil, nil } @@ -168,8 +168,8 @@ func statFile(fs FS, root string) (os.DirEntry, error) { func readDir(fs FS, root string) ([]os.DirEntry, error) { var out []os.DirEntry - root = filepath.Clean(root) - if root == "/" || root == "." { + root = filepath.FromSlash(filepath.Clean(root)) + if root == string(filepath.Separator) || root == "." { root = "." out = make([]gofs.DirEntry, 0) } diff --git a/vendor/github.com/tonistiigi/fsutil/hardlinks.go b/vendor/github.com/tonistiigi/fsutil/hardlinks.go index ef8bbfb5d..d9bf2fc1c 100644 --- a/vendor/github.com/tonistiigi/fsutil/hardlinks.go +++ b/vendor/github.com/tonistiigi/fsutil/hardlinks.go @@ -1,6 +1,9 @@ package fsutil import ( + "context" + "io" + gofs "io/fs" "os" "syscall" @@ -46,3 +49,68 @@ func (v *Hardlinks) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err return nil } + +// WithHardlinkReset returns a FS that fixes hardlinks for FS that has been filtered +// so that original hardlink sources might be missing +func WithHardlinkReset(fs FS) FS { + return &hardlinkFilter{fs: fs} +} + +type hardlinkFilter struct { + fs FS +} + +var _ FS = &hardlinkFilter{} + +func (r *hardlinkFilter) Walk(ctx context.Context, target string, fn gofs.WalkDirFunc) error { + seenFiles := make(map[string]string) + return r.fs.Walk(ctx, target, func(path string, entry gofs.DirEntry, err error) error { + if err != nil { + return err + } + + fi, err := entry.Info() + if err != nil { + return err + } + + if fi.IsDir() || fi.Mode()&os.ModeSymlink != 0 { + return fn(path, entry, nil) + } + + stat, ok := fi.Sys().(*types.Stat) + if !ok { + return errors.WithStack(&os.PathError{Path: path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"}) + } + + if stat.Linkname != "" { + if v, ok := seenFiles[stat.Linkname]; !ok { + seenFiles[stat.Linkname] = stat.Path + stat.Linkname = "" + entry = &dirEntryWithStat{DirEntry: entry, stat: stat} + } else { + if v != stat.Path { + stat.Linkname = v + entry = &dirEntryWithStat{DirEntry: entry, stat: stat} + } + } + } + + seenFiles[path] = stat.Path + + return fn(path, entry, nil) + }) +} + +func (r *hardlinkFilter) Open(p string) (io.ReadCloser, error) { + return r.fs.Open(p) +} + +type dirEntryWithStat struct { + gofs.DirEntry + stat *types.Stat +} + +func (d *dirEntryWithStat) Info() (gofs.FileInfo, error) { + return &StatInfo{d.stat}, nil +} diff --git a/vendor/github.com/tonistiigi/fsutil/readme.md b/vendor/github.com/tonistiigi/fsutil/readme.md index 5ce685b7e..c41716887 100644 --- a/vendor/github.com/tonistiigi/fsutil/readme.md +++ b/vendor/github.com/tonistiigi/fsutil/readme.md @@ -1,3 +1,8 @@ +[![PkgGoDev](https://img.shields.io/badge/go.dev-docs-007d9c?style=flat-square&logo=go&logoColor=white)](https://pkg.go.dev/github.com/tonistiigi/fsutil) +[![CI Status](https://img.shields.io/github/actions/workflow/status/tonistiigi/fsutil/ci.yml?label=ci&logo=github&style=flat-square)](https://github.com/tonistiigi/fsutil/actions?query=workflow%3Aci) +[![Go Report Card](https://goreportcard.com/badge/github.com/tonistiigi/fsutil?style=flat-square)](https://goreportcard.com/report/github.com/tonistiigi/fsutil) +[![Codecov](https://img.shields.io/codecov/c/github/tonistiigi/fsutil?logo=codecov&style=flat-square)](https://codecov.io/gh/tonistiigi/fsutil) + Incremental file directory sync tools in golang. ``` diff --git a/vendor/github.com/tonistiigi/fsutil/receive.go b/vendor/github.com/tonistiigi/fsutil/receive.go index 9924ce072..afb118bb7 100644 --- a/vendor/github.com/tonistiigi/fsutil/receive.go +++ b/vendor/github.com/tonistiigi/fsutil/receive.go @@ -1,10 +1,42 @@ +// send.go and receive.go describe the fsutil file-transfer protocol, which +// allows transferring file trees across a network connection. +// +// The protocol operates as follows: +// - The client (the receiver) connects to the server (the sender). +// - The sender walks the target tree lexicographically and sends a series of +// STAT packets that describe each file (an empty stat indicates EOF). +// - The receiver sends a REQ packet for each file it requires the contents for, +// using the ID for the file (determined as its index in the STAT sequence). +// - The sender sends a DATA packet with byte arrays for the contents of the +// file, associated with an ID (an empty array indicates EOF). +// - Once the receiver has received all files it wants, it sends a FIN packet, +// and the file transfer is complete. +// If an error is encountered on either side, an ERR packet is sent containing +// a human-readable error. +// +// All paths transferred over the protocol are normalized to unix-style paths, +// regardless of which platforms are present on either side. These path +// conversions are performed right before sending a STAT packet (for the +// sender) or right after receiving the corresponding STAT packet (for the +// receiver); this abstraction doesn't leak into the rest of fsutil, which +// operates on native platform-specific paths. +// +// Note that in the case of cross-platform file transfers, the transfer is +// best-effort. Some filenames that are valid on a unix sender would not be +// valid on a windows receiver, so these paths are rejected as they are +// received. Additionally, file metadata, like user/group owners and xattrs do +// not have an exact correspondence on windows, and so would be discarded by +// a windows receiver. + package fsutil import ( "context" "io" "os" + "path/filepath" "sync" + "syscall" "github.com/pkg/errors" "github.com/tonistiigi/fsutil/types" @@ -192,13 +224,24 @@ func (r *receiver) run(ctx context.Context) error { if r.verboseProgressCb != nil { r.verboseProgressCb(p.Stat.Path, StatusStat, p.Size()) } + + // normalize unix wire-specific paths to platform-specific paths + path := filepath.FromSlash(p.Stat.Path) + if filepath.ToSlash(path) != p.Stat.Path { + // e.g. a linux path foo/bar\baz cannot be represented on windows + return errors.WithStack(&os.PathError{Path: p.Stat.Path, Err: syscall.EINVAL, Op: "unrepresentable path"}) + } + p.Stat.Path = path + p.Stat.Linkname = filepath.FromSlash(p.Stat.Linkname) + if fileCanRequestData(os.FileMode(p.Stat.Mode)) { r.mu.Lock() r.files[p.Stat.Path] = i r.mu.Unlock() } i++ - cp := ¤tPath{path: p.Stat.Path, stat: p.Stat} + + cp := ¤tPath{path: path, stat: p.Stat} if err := r.orderValidator.HandleChange(ChangeKindAdd, cp.path, &StatInfo{cp.stat}, nil); err != nil { return err } diff --git a/vendor/github.com/tonistiigi/fsutil/send.go b/vendor/github.com/tonistiigi/fsutil/send.go index 7fe01a07e..8e6942215 100644 --- a/vendor/github.com/tonistiigi/fsutil/send.go +++ b/vendor/github.com/tonistiigi/fsutil/send.go @@ -4,6 +4,7 @@ import ( "context" "io" "os" + "path/filepath" "sync" "syscall" @@ -28,7 +29,7 @@ type Stream interface { func Send(ctx context.Context, conn Stream, fs FS, progressCb func(int, bool), verboseProgressCb VerboseProgressCB) error { s := &sender{ conn: &syncStream{Stream: conn}, - fs: fs, + fs: WithHardlinkReset(fs), files: make(map[uint32]string), progressCb: progressCb, verboseProgressCb: verboseProgressCb, @@ -50,6 +51,7 @@ type sender struct { progressCb func(int, bool) verboseProgressCb VerboseProgressCB progressCurrent int + progressCurrentMu sync.Mutex sendpipeline chan *sendHandle } @@ -116,6 +118,9 @@ func (s *sender) updateProgress(size int, last bool) { defer s.mu.Unlock() s.progressCurrent += size if s.progressCb != nil { + s.progressCurrentMu.Lock() + defer s.progressCurrentMu.Unlock() + s.progressCurrent += size s.progressCb(s.progressCurrent, last) } } @@ -164,7 +169,8 @@ func (s *sender) walk(ctx context.Context) error { if !ok { return errors.WithStack(&os.PathError{Path: path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"}) } - + stat.Path = filepath.ToSlash(stat.Path) + stat.Linkname = filepath.ToSlash(stat.Linkname) p := &types.Packet{ Type: types.PACKET_STAT, Stat: stat, diff --git a/vendor/github.com/tonistiigi/fsutil/stat.go b/vendor/github.com/tonistiigi/fsutil/stat.go index 2ab8da118..44441cb65 100644 --- a/vendor/github.com/tonistiigi/fsutil/stat.go +++ b/vendor/github.com/tonistiigi/fsutil/stat.go @@ -19,7 +19,7 @@ func mkstat(path, relpath string, fi os.FileInfo, inodemap map[uint64]string) (* relpath = filepath.ToSlash(relpath) stat := &types.Stat{ - Path: relpath, + Path: filepath.FromSlash(relpath), Mode: uint32(fi.Mode()), ModTime: fi.ModTime().UnixNano(), } diff --git a/vendor/github.com/tonistiigi/fsutil/validator.go b/vendor/github.com/tonistiigi/fsutil/validator.go index 9bd7d94d3..8b0dd91ec 100644 --- a/vendor/github.com/tonistiigi/fsutil/validator.go +++ b/vendor/github.com/tonistiigi/fsutil/validator.go @@ -2,8 +2,7 @@ package fsutil import ( "os" - "path" - "runtime" + "path/filepath" "sort" "strings" "syscall" @@ -28,21 +27,18 @@ func (v *Validator) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err if v.parentDirs == nil { v.parentDirs = make([]parent, 1, 10) } - if runtime.GOOS == "windows" { - p = strings.Replace(p, "\\", "", -1) - } - if p != path.Clean(p) { + if p != filepath.Clean(p) { return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "unclean path"}) } - if path.IsAbs(p) { + if filepath.IsAbs(p) { return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "absolute path"}) } - dir := path.Dir(p) - base := path.Base(p) + dir := filepath.Dir(p) + base := filepath.Base(p) if dir == "." { dir = "" } - if dir == ".." || strings.HasPrefix(p, "../") { + if dir == ".." || strings.HasPrefix(p, filepath.FromSlash("../")) { return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "escape check"}) } @@ -56,12 +52,12 @@ func (v *Validator) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err } if dir != v.parentDirs[len(v.parentDirs)-1].dir || v.parentDirs[i].last >= base { - return errors.Errorf("changes out of order: %q %q", p, path.Join(v.parentDirs[i].dir, v.parentDirs[i].last)) + return errors.Errorf("changes out of order: %q %q", p, filepath.Join(v.parentDirs[i].dir, v.parentDirs[i].last)) } v.parentDirs[i].last = base if kind != ChangeKindDelete && fi.IsDir() { v.parentDirs = append(v.parentDirs, parent{ - dir: path.Join(dir, base), + dir: filepath.Join(dir, base), last: "", }) } @@ -76,7 +72,7 @@ func ComparePath(p1, p2 string) int { switch { case p1[i] == p2[i]: continue - case p2[i] != '/' && p1[i] < p2[i] || p1[i] == '/': + case p2[i] != filepath.Separator && p1[i] < p2[i] || p1[i] == filepath.Separator: return -1 default: return 1 diff --git a/vendor/modules.txt b/vendor/modules.txt index 36adbe574..e59863d8f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -821,8 +821,8 @@ github.com/spdx/tools-golang/spdx/v2/v2_3 ## explicit; go 1.20 github.com/stretchr/testify/assert github.com/stretchr/testify/require -# github.com/tonistiigi/fsutil v0.0.0-20240424095704-91a3fc46842c => github.com/alexcb/fsutil v0.0.0-20231030221755-644b08355b65 -## explicit; go 1.19 +# github.com/tonistiigi/fsutil v0.0.0-20240424095704-91a3fc46842c => github.com/earthbuild/fsutil v0.0.0-20261002194825-890baaee2294 +## explicit; go 1.20 github.com/tonistiigi/fsutil github.com/tonistiigi/fsutil/copy github.com/tonistiigi/fsutil/types @@ -1140,4 +1140,4 @@ kernel.org/pub/linux/libs/security/libcap/cap # kernel.org/pub/linux/libs/security/libcap/psx v1.2.67 ## explicit; go 1.11 kernel.org/pub/linux/libs/security/libcap/psx -# github.com/tonistiigi/fsutil => github.com/alexcb/fsutil v0.0.0-20231030221755-644b08355b65 +# github.com/tonistiigi/fsutil => github.com/earthbuild/fsutil v0.0.0-20261002194825-890baaee2294 diff --git a/worker/runc/runc.go b/worker/runc/runc.go index 6d2ae42b4..170f9e6de 100644 --- a/worker/runc/runc.go +++ b/worker/runc/runc.go @@ -79,7 +79,7 @@ func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, proc SELinux: selinux, TracingSocket: traceSocket, DefaultCgroupParent: defaultCgroupParent, - Hooks: hooks, //earthly-specific + Hooks: hooks, // earthly-specific ResourceMonitor: rm, SampleFrequency: sampleFrequency, // earthly-specific }, np) From cd012dbd41db0aaea2e684f1c1f7cac927bd274f Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 2 Oct 2026 20:59:17 +0100 Subject: [PATCH 03/17] chore: make archutil --- util/archutil/loong64_binary.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/archutil/loong64_binary.go b/util/archutil/loong64_binary.go index 01d445431..664c5105e 100644 --- a/util/archutil/loong64_binary.go +++ b/util/archutil/loong64_binary.go @@ -6,4 +6,4 @@ package archutil // This file is generated by running "make archutil". // Do not edit manually. -const Binaryloong64 = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xaa\x77\xf5\x71\x63\x62\x64\x64\x80\x01\x26\x06\x08\x6f\x03\x03\x83\x02\x88\x76\x80\x8a\x5f\x80\xd2\xce\x60\x31\x0b\x06\x26\x06\x07\x06\x66\x06\x26\x06\x90\x1a\x56\x06\x14\xa0\xc0\x88\x44\xef\x81\x0a\xc2\x68\x98\x81\x81\x4f\x4b\x52\xd8\x18\x88\x07\x02\x50\x9a\x85\x41\x94\x81\xbb\xa4\x91\x99\x81\x41\x9b\x81\x41\xaf\x38\xa3\xb8\xa4\xa8\x24\x31\x89\x41\xaf\x24\xb5\xa2\x84\x81\x0a\x80\x9b\x81\x01\xec\x27\x98\xdb\x60\xe1\xb0\x01\xca\xe7\x41\x53\xcf\x88\x85\xcf\x8c\xc5\x5c\x98\xff\x05\x09\xe8\x07\x04\x00\x00\xff\xff\x5f\xc5\x9b\x9d\x90\x01\x00\x00" +const Binaryloong64 = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xaa\x77\xf5\x71\x63\x62\x64\x64\x80\x01\x26\x06\x08\x6f\x03\x03\x83\x02\x88\x76\x80\x8a\x5f\x80\xd2\xce\x60\x31\x0b\x06\x26\x06\x07\x06\x66\x06\x26\x06\x90\x1a\x56\x06\x14\xa0\xc0\x88\x44\xef\x81\x0a\xee\x81\x4b\x43\x64\x03\x9f\x96\xa4\xb0\x31\x10\x0f\x04\xa0\x34\x0b\x83\x28\x03\x77\x49\x23\x33\x03\x83\x36\x03\x83\x5e\x71\x46\x71\x49\x51\x49\x62\x12\x83\x5e\x49\x6a\x45\x09\x03\x15\x00\x37\xd4\x85\x30\xb7\xc1\xc2\x61\x03\x94\xcf\x83\xa6\x9e\x11\x0b\x9f\x19\x8b\xb9\x30\xff\x0b\x12\xd0\x0f\x08\x00\x00\xff\xff\x72\x81\xda\x64\x90\x01\x00\x00" From a08fff0305c4f5f7cf13f17e199c11e9e4a03ca8 Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 2 Oct 2026 21:16:41 +0100 Subject: [PATCH 04/17] chore: tidy --- Dockerfile | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7a0f8f280..58d28224f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -329,7 +329,20 @@ ARG TARGETPLATFORM RUN --mount=target=/root/.cache,type=cache <= 1.26.0 and fails the build. + # When upstream upgrades the builder to Go >= 1.26 (or pins gocovmerge), + # this temporary module workaround can be reverted back to upstream's single xx-go install line. + mkdir -p /tmp/gocovmerge && cd /tmp/gocovmerge + go mod init gocovmerge + go get golang.org/x/tools@v0.21.0 + go get github.com/wadey/gocovmerge@b5bfa59ec0ad + xx-go install github.com/wadey/gocovmerge + cd / + rm -rf /tmp/gocovmerge mkdir /out if ! xx-info is-cross; then /go/bin/gotestsum --version @@ -419,7 +432,11 @@ ENV BUILDKIT_INTEGRATION_SNAPSHOTTER=stargz ENV BUILDKIT_SETUP_CGROUPV2_ROOT=1 ENV CGO_ENABLED=0 ENV GOTESTSUM_FORMAT=standard-verbose -COPY --link --from=gotestsum /out/gotestsum /usr/bin/ +# NOTE for future upstream merges: +# Upstream copies all test helpers (/out) to /usr/bin/ because it includes +# gotestsum, gocovmerge, and the gotestsumandcover runner script. +# Do NOT change this to /out/gotestsum or gotestsumandcover will be missing at test runtime. +COPY --link --from=gotestsum /out /usr/bin/ COPY --link --from=silo /usr/bin/silo /usr/bin/minio COPY --link --from=silo /usr/bin/mcli /usr/bin/mc COPY --link --from=nydus /out/nydus-static/* /usr/bin/ From 733f3a1fd7436e48d464f908bf2a62856f59cab4 Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Sat, 3 Oct 2026 10:02:25 +0100 Subject: [PATCH 05/17] fix: skip check invalid platforms --- solver/llbsolver/solver.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/solver/llbsolver/solver.go b/solver/llbsolver/solver.go index a6028850e..08fa54449 100644 --- a/solver/llbsolver/solver.go +++ b/solver/llbsolver/solver.go @@ -739,9 +739,23 @@ func runInlineCacheExporter(ctx context.Context, e exporter.ExporterInstance, in } func (s *Solver) runExporters(ctx context.Context, exporters []exporter.ExporterInstance, inlineCacheExporter inlineCacheExporter, job *solver.Job, cached *result.Result[solver.CachedResult], inp *result.Result[cache.ImmutableRef]) (exporterResponse map[string]string, descrefs []exporter.DescriptorReference, err error) { - warnings, err := verifier.CheckInvalidPlatforms(ctx, inp) - if err != nil { - return nil, nil, err + var isEarthBuild bool + + // EarthBuild uses res.Refs as a dictionary of named build outputs, not target platforms. + // Platform verification is handled per-image inside the Earthly exporter. + for _, exp := range exporters { + if exp.Name() == client.ExporterEarthly { + isEarthBuild = true + break + } + } + + var warnings []client.VertexWarning + if !isEarthBuild { + warnings, err = verifier.CheckInvalidPlatforms(ctx, inp) + if err != nil { + return nil, nil, err + } } eg, ctx := errgroup.WithContext(ctx) From 9695bb3706abf387713b702fe8a8fb36cb706351 Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Sat, 3 Oct 2026 18:51:38 +0100 Subject: [PATCH 06/17] fix: invalid platforms check --- solver/llbsolver/solver.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solver/llbsolver/solver.go b/solver/llbsolver/solver.go index 08fa54449..17054a6c9 100644 --- a/solver/llbsolver/solver.go +++ b/solver/llbsolver/solver.go @@ -744,7 +744,7 @@ func (s *Solver) runExporters(ctx context.Context, exporters []exporter.Exporter // EarthBuild uses res.Refs as a dictionary of named build outputs, not target platforms. // Platform verification is handled per-image inside the Earthly exporter. for _, exp := range exporters { - if exp.Name() == client.ExporterEarthly { + if exp.Type() == client.ExporterEarthly { isEarthBuild = true break } From 614605c7d0e36000fefa8b216b879fa4b602b66d Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Wed, 7 Oct 2026 11:18:50 +0100 Subject: [PATCH 07/17] fix: re-add gRPC stream errors interceptor --- frontend/gateway/grpcclient/client.go | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/gateway/grpcclient/client.go b/frontend/gateway/grpcclient/client.go index b67597ad1..33a7b2bf0 100644 --- a/frontend/gateway/grpcclient/client.go +++ b/frontend/gateway/grpcclient/client.go @@ -1275,6 +1275,7 @@ func grpcClientConn(ctx context.Context) (context.Context, *grpc.ClientConn, err }), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithUnaryInterceptor(grpcerrors.UnaryClientInterceptor), + grpc.WithStreamInterceptor(grpcerrors.StreamClientInterceptor), grpc.WithInitialWindowSize(65535 * 32), grpc.WithInitialConnWindowSize(65535 * 16), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)), From 2264be062854d463886718394f9e0eda2d607d7f Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Wed, 7 Oct 2026 16:39:05 +0100 Subject: [PATCH 08/17] fix: atomic stats to stream --- executor/runcexecutor/monitor_stats.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/executor/runcexecutor/monitor_stats.go b/executor/runcexecutor/monitor_stats.go index 79b63d872..5697cec4f 100644 --- a/executor/runcexecutor/monitor_stats.go +++ b/executor/runcexecutor/monitor_stats.go @@ -37,11 +37,12 @@ func writeStatsToStream(w io.Writer, stats *runc.Stats) error { if err != nil { return errors.Wrap(err, "failed to encode runc stats") } - err = binary.Write(w, binary.LittleEndian, uint8(1)) // earthly stats stream protocol v1 - if err != nil { - return err - } - return writeUint32PrefixedBytes(w, statsJSON) + buf := make([]byte, 1+4+len(statsJSON)) + buf[0] = 1 // earthly stats stream protocol v1 + binary.LittleEndian.PutUint32(buf[1:5], uint32(len(statsJSON))) + copy(buf[5:], statsJSON) + _, err = w.Write(buf) + return err } func (w *runcExecutor) monitorContainerStats(ctx context.Context, id string, sampleFrequency time.Duration, statsWriter io.WriteCloser) { From edbfecd204c43e4069d204f20daf72f962ec330d Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Wed, 7 Oct 2026 17:00:00 +0100 Subject: [PATCH 09/17] test: atomic stats write --- executor/runcexecutor/monitor_stats_test.go | 149 ++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 executor/runcexecutor/monitor_stats_test.go diff --git a/executor/runcexecutor/monitor_stats_test.go b/executor/runcexecutor/monitor_stats_test.go new file mode 100644 index 000000000..559bdb08a --- /dev/null +++ b/executor/runcexecutor/monitor_stats_test.go @@ -0,0 +1,149 @@ +//go:build linux +// +build linux + +package runcexecutor + +import ( + "encoding/binary" + "encoding/json" + "errors" + "testing" + + runc "github.com/containerd/go-runc" +) + +type recordWriter struct { + writes [][]byte +} + +func (rw *recordWriter) Write(p []byte) (n int, err error) { + cp := make([]byte, len(p)) + copy(cp, p) + rw.writes = append(rw.writes, cp) + return len(p), nil +} + +type errWriter struct { + err error +} + +func (ew *errWriter) Write(p []byte) (n int, err error) { + return 0, ew.err +} + +func TestWriteStatsToStream_AtomicSingleWrite(t *testing.T) { + t.Parallel() + + rw := &recordWriter{} + stats := &runc.Stats{ + Cpu: runc.Cpu{ + Usage: runc.CpuUsage{ + Total: 123456, + }, + }, + } + + err := writeStatsToStream(rw, stats) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Must be a single atomic write so that downstream progress log stream + // does not fragment the frame across multiple client.VertexLog events. + if got := len(rw.writes); got != 1 { + t.Fatalf("got %d writes, want 1 atomic write", got) + } + + payload := rw.writes[0] + if len(payload) < 5 { + t.Fatalf("payload length %d too short, want at least 5 bytes", len(payload)) + } + + // Protocol version byte + if got, want := payload[0], uint8(1); got != want { + t.Errorf("version = %d, want %d", got, want) + } + + // 4-byte LittleEndian payload length + n := binary.LittleEndian.Uint32(payload[1:5]) + jsonBytes := payload[5:] + if got, want := uint32(len(jsonBytes)), n; got != want { + t.Errorf("json length = %d, want %d (from prefix)", got, want) + } + + // JSON payload matches stats + var decoded runc.Stats + err = json.Unmarshal(jsonBytes, &decoded) + if err != nil { + t.Fatalf("failed to unmarshal json payload: %v", err) + } + + if decoded.Cpu.Usage.Total != 123456 { + t.Errorf("decoded stats Total = %d, want 123456", decoded.Cpu.Usage.Total) + } +} + +func TestWriteStatsToStream_WriterError(t *testing.T) { + t.Parallel() + + wantErr := errors.New("simulated pipe write failure") + ew := &errWriter{err: wantErr} + stats := &runc.Stats{} + + err := writeStatsToStream(ew, stats) + if !errors.Is(err, wantErr) { + t.Fatalf("writeStatsToStream returned error %v, want %v", err, wantErr) + } +} + +func TestWriteStatsToStream_MultipleMetrics(t *testing.T) { + t.Parallel() + + rw := &recordWriter{} + stats := &runc.Stats{ + Cpu: runc.Cpu{ + Usage: runc.CpuUsage{ + Total: 987654, + }, + }, + Memory: runc.Memory{ + Usage: runc.MemoryEntry{ + Limit: 2048, + Usage: 1024, + }, + }, + Pids: runc.Pids{ + Current: 42, + Limit: 100, + }, + } + + err := writeStatsToStream(rw, stats) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if got := len(rw.writes); got != 1 { + t.Fatalf("got %d writes, want 1 atomic write", got) + } + + payload := rw.writes[0] + n := binary.LittleEndian.Uint32(payload[1:5]) + jsonBytes := payload[5:] + if got, want := uint32(len(jsonBytes)), n; got != want { + t.Errorf("json length = %d, want %d (from prefix)", got, want) + } + + var decoded runc.Stats + err = json.Unmarshal(jsonBytes, &decoded) + if err != nil { + t.Fatalf("failed to unmarshal json payload: %v", err) + } + + if decoded.Memory.Usage.Usage != 1024 { + t.Errorf("decoded memory usage = %d, want 1024", decoded.Memory.Usage.Usage) + } + if decoded.Pids.Current != 42 { + t.Errorf("decoded pids current = %d, want 42", decoded.Pids.Current) + } +} From ba959c9eee825f0d4bb20ff59a2f3c370077a07c Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Thu, 8 Oct 2026 09:48:23 +0100 Subject: [PATCH 10/17] fix: make lint --- api/services/registry/proxy_test.go | 29 ++++++++++++++++++++------ executor/runcexecutor/monitor_stats.go | 12 ----------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/api/services/registry/proxy_test.go b/api/services/registry/proxy_test.go index 2df1c7171..f8fffeef5 100644 --- a/api/services/registry/proxy_test.go +++ b/api/services/registry/proxy_test.go @@ -31,8 +31,8 @@ var errUnexpectedMessage = errors.New("stream carried a message that was not a B func tunnel(t *testing.T, reg *httptest.Server) (*http.Client, func() int) { t.Helper() - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(cancel) + ctx, cancel := context.WithCancelCause(context.Background()) + t.Cleanup(func() { cancel(errors.WithStack(context.Canceled)) }) srv := NewServer(reg.Listener.Addr().String()) @@ -301,7 +301,11 @@ func TestProxyServesAResponse(t *testing.T) { client, _ := tunnel(t, reg) - resp, err := client.Get("http://registry.invalid/v2/img/blobs/sha256:0") + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "http://registry.invalid/v2/img/blobs/sha256:0", nil) + if err != nil { + t.Fatalf("creating request: %v", err) + } + resp, err := client.Do(req) if err != nil { t.Fatalf("GET through the proxy: %v", err) } @@ -341,7 +345,11 @@ func TestProxyDoesNotTruncateAResponseThatStallsMidBody(t *testing.T) { client, _ := tunnel(t, reg) - resp, err := client.Get("http://registry.invalid/v2/img/blobs/sha256:0") + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "http://registry.invalid/v2/img/blobs/sha256:0", nil) + if err != nil { + t.Fatalf("creating request: %v", err) + } + resp, err := client.Do(req) if err != nil { t.Fatalf("GET through the proxy: %v", err) } @@ -375,7 +383,11 @@ func TestProxyReusesOneConnectionForTwoRequests(t *testing.T) { time.Sleep(200 * time.Millisecond) } - resp, err := client.Get("http://registry.invalid/v2/img/manifests/latest") + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "http://registry.invalid/v2/img/manifests/latest", nil) + if err != nil { + t.Fatalf("creating request %d: %v", i+1, err) + } + resp, err := client.Do(req) if err != nil { t.Fatalf("request %d through the proxy: %v", i+1, err) } @@ -422,7 +434,12 @@ func TestProxyPassesALargeRequestBodyThrough(t *testing.T) { client, _ := tunnel(t, reg) - resp, err := client.Post("http://registry.invalid/v2/img/blobs/uploads/", "application/octet-stream", bytes.NewReader(sent)) + req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, "http://registry.invalid/v2/img/blobs/uploads/", bytes.NewReader(sent)) + if err != nil { + t.Fatalf("creating request: %v", err) + } + req.Header.Set("Content-Type", "application/octet-stream") + resp, err := client.Do(req) if err != nil { t.Fatalf("POST through the proxy: %v", err) } diff --git a/executor/runcexecutor/monitor_stats.go b/executor/runcexecutor/monitor_stats.go index 5697cec4f..5bddcc67e 100644 --- a/executor/runcexecutor/monitor_stats.go +++ b/executor/runcexecutor/monitor_stats.go @@ -20,18 +20,6 @@ import ( // length of payload (stored as n) // n bytes (a json-encoded string of the go-runc Stats structure) -// writeUint32PrefixedBytes writes a uint32 representing the length of the b byte array, followed by the actual -// byte array. -func writeUint32PrefixedBytes(w io.Writer, b []byte) error { - n := len(b) - err := binary.Write(w, binary.LittleEndian, uint32(n)) - if err != nil { - return err - } - _, err = w.Write(b) - return err -} - func writeStatsToStream(w io.Writer, stats *runc.Stats) error { statsJSON, err := json.Marshal(stats) if err != nil { From 9840066566a188c915098bba73a1dce533a02c9e Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Thu, 8 Oct 2026 10:50:45 +0100 Subject: [PATCH 11/17] fix: failing test-windows-amd64 --- executor/runcexecutor/monitor_stats.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/executor/runcexecutor/monitor_stats.go b/executor/runcexecutor/monitor_stats.go index 5bddcc67e..72b190992 100644 --- a/executor/runcexecutor/monitor_stats.go +++ b/executor/runcexecutor/monitor_stats.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package runcexecutor import ( From e56d00a512c0b1b36f46c83bebd417efaf116f43 Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 9 Oct 2026 09:00:12 +0100 Subject: [PATCH 12/17] doc: duplicate export --- AGENTS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AGENTS.md b/AGENTS.md index dfc90352d..9c5e7cb39 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,3 +5,4 @@ This repository is a fork of [moby/buildkit](https://github.com/moby/buildkit). ## Guidelines - Any code changes must be kept to a minimum to reduce the potential for merge conflicts with upstream `moby/buildkit`. +- **Double Export & Output Duplication:** Do not patch BuildKit to deduplicate or suppress progress logs across concurrent solves or intermediate exports (`gatewayClient.Export`). BuildKit streams vertex output to all attached callers; preventing redundant solve requests belongs in EarthBuild (`earthfile2llb/converter.go`). From 59662da125f8f5a13afa5237b835c2935b85716f Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 9 Oct 2026 13:30:29 +0100 Subject: [PATCH 13/17] chore: tidy --- AGENTS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AGENTS.md b/AGENTS.md index 9c5e7cb39..a4f252c6c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,4 +5,5 @@ This repository is a fork of [moby/buildkit](https://github.com/moby/buildkit). ## Guidelines - Any code changes must be kept to a minimum to reduce the potential for merge conflicts with upstream `moby/buildkit`. +- **Upstream Fixes & Version Bumping:** If upstream `moby/buildkit` has already resolved an issue in a newer version, suggest bumping BuildKit instead of implementing a temporary local fix. - **Double Export & Output Duplication:** Do not patch BuildKit to deduplicate or suppress progress logs across concurrent solves or intermediate exports (`gatewayClient.Export`). BuildKit streams vertex output to all attached callers; preventing redundant solve requests belongs in EarthBuild (`earthfile2llb/converter.go`). From a653104a0ab9294fedfa56df1ab34ca150c566d2 Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 9 Oct 2026 14:08:46 +0100 Subject: [PATCH 14/17] chore(coderabbit): ignore vendor dir --- .coderabbit.yaml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .coderabbit.yaml diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 000000000..49e716e07 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,4 @@ +reviews: + path_filters: + - "!vendor/**" + - "!**/vendor/**" \ No newline at end of file From dc207726cf404807cb18a91e46b47fd591f6a4ed Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 23 Oct 2026 09:26:30 +0100 Subject: [PATCH 15/17] chore: merge origin/main --- client/solve.go | 12 +++- go.mod | 2 - go.sum | 4 +- session/filesync/diffcopy.go | 13 +++- session/filesync/filesync.go | 58 ++++++++++------ session/localhost/localhost.go | 2 +- .../localhostprovider/localhostprovider.go | 2 +- vendor/github.com/tonistiigi/fsutil/filter.go | 10 +-- .../github.com/tonistiigi/fsutil/receive.go | 69 +++++++------------ vendor/github.com/tonistiigi/fsutil/send.go | 34 +++------ .../tonistiigi/fsutil/verbose_callback.go | 15 ---- vendor/modules.txt | 3 +- 12 files changed, 97 insertions(+), 127 deletions(-) delete mode 100644 vendor/github.com/tonistiigi/fsutil/verbose_callback.go diff --git a/client/solve.go b/client/solve.go index da72ecdc5..81590fae7 100644 --- a/client/solve.go +++ b/client/solve.go @@ -57,11 +57,17 @@ type SolveOpt struct { type ExportEntry struct { Type string Attrs map[string]string - Output filesync.FileOutputFunc // for ExporterOCI and ExporterDocker + Output filesync.FileOutputFunc // for ExporterOCI, ExporterDocker and ExporterEarthly OutputDir string // for ExporterLocal OutputDirFunc func(map[string]string) (string, error) // for ExporterEarthly OutputPullCallback pullping.PullCallback // for ExporterEarthly - VerboseProgressCB fsutil.VerboseProgressCB + // OnReceiveProgress is called periodically as files/artifacts are received from the daemon + // via diffcopy (e.g. during artifact export in EarthBuild). It reports the cumulative bytes received + // and whether the transfer is complete (done=true), allowing the client to render progress bars + // and transfer metrics. + OnReceiveProgress func(bytes int, done bool) // for ExporterEarthly + // OnReceiveFile is called for each file received from the daemon during export + OnReceiveFile func(path string, size int64) // for ExporterEarthly } type CacheOptionsEntry struct { @@ -189,7 +195,7 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG if ex.OutputPullCallback != nil { s.Allow(pullping.NewPullPing(ex.OutputPullCallback)) } - s.Allow(filesync.NewFSSyncMultiTarget(ex.Output, ex.OutputDirFunc, ex.VerboseProgressCB)) + s.Allow(filesync.NewFSSyncMultiTarget(ex.Output, ex.OutputDirFunc, ex.OnReceiveProgress, ex.OnReceiveFile)) } else { syncTargets = append(syncTargets, filesync.WithFSSync(exID, ex.Output)) } diff --git a/go.mod b/go.mod index 2d4931137..b2d6b8d2f 100644 --- a/go.mod +++ b/go.mod @@ -182,5 +182,3 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect kernel.org/pub/linux/libs/security/libcap/psx v1.2.67 // indirect ) - -replace github.com/tonistiigi/fsutil => github.com/earthbuild/fsutil v0.0.0-20261002194825-890baaee2294 diff --git a/go.sum b/go.sum index 545c44553..fda322901 100644 --- a/go.sum +++ b/go.sum @@ -155,8 +155,6 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/earthbuild/fsutil v0.0.0-20261002194825-890baaee2294 h1:gFtQodZi786++bc4OPIeVKIwrQWdP0sJLGCHKWenQmo= -github.com/earthbuild/fsutil v0.0.0-20261002194825-890baaee2294/go.mod h1:vbbYqJlnswsbJqWUcJN8fKtBhnEgldDrcagTgnBVKKM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -416,6 +414,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tonistiigi/fsutil v0.0.0-20240424095704-91a3fc46842c h1:+6wg/4ORAbnSoGDzg2Q1i3CeMcT/jjhye/ZfnBHy7/M= +github.com/tonistiigi/fsutil v0.0.0-20240424095704-91a3fc46842c/go.mod h1:vbbYqJlnswsbJqWUcJN8fKtBhnEgldDrcagTgnBVKKM= github.com/tonistiigi/go-actions-cache v0.0.0-20240320205438-9794bdbb2fb4 h1:R0lM8Jo3aZL95yjQHWQti7nszllleKBxCs9uyFbykII= github.com/tonistiigi/go-actions-cache v0.0.0-20240320205438-9794bdbb2fb4/go.mod h1:anhKd3mnC1shAbQj1Q4IJ+w6xqezxnyDYlx/yKa7IXM= github.com/tonistiigi/go-archvariant v1.0.0 h1:5LC1eDWiBNflnTF1prCiX09yfNHIxDC/aukdhCdTyb0= diff --git a/session/filesync/diffcopy.go b/session/filesync/diffcopy.go index 46b29020e..20697bf06 100644 --- a/session/filesync/diffcopy.go +++ b/session/filesync/diffcopy.go @@ -22,7 +22,7 @@ type Stream interface { } func sendDiffCopy(stream Stream, fs fsutil.FS, progress progressCb) error { - return errors.WithStack(fsutil.Send(stream.Context(), stream, fs, progress, nil)) // earthly needs to pass nil + return errors.WithStack(fsutil.Send(stream.Context(), stream, fs, progress)) } func newStreamWriter(stream grpc.ClientStream) io.WriteCloser { @@ -114,11 +114,12 @@ func recvDiffCopy(ds grpc.ClientStream, dest string, cu CacheUpdater, progress p })) } -func syncTargetDiffCopy(ds grpc.ServerStream, dest string, verboseProgressCB fsutil.VerboseProgressCB) error { +func syncTargetDiffCopy(ds grpc.ServerStream, dest string, progress progressCb, onFile fileCb) error { if err := os.MkdirAll(dest, 0700); err != nil { return errors.Wrapf(err, "failed to create synctarget dest dir %s", dest) } modTime := time.Now().UnixNano() // earthly-specific + seen := make(map[string]struct{}) return errors.WithStack(fsutil.Receive(ds.Context(), ds, dest, fsutil.ReceiveOpt{ Merge: true, Filter: func() func(string, *fstypes.Stat) bool { @@ -130,10 +131,16 @@ func syncTargetDiffCopy(ds grpc.ServerStream, dest string, verboseProgressCB fsu if st.ModTime == 0 { st.ModTime = modTime } + if onFile != nil && !st.IsDir() { + if _, ok := seen[p]; !ok { + seen[p] = struct{}{} + onFile(p, st.GetSize_()) + } + } return true } }(), - VerboseProgressCb: verboseProgressCB, + ProgressCb: progress, })) } diff --git a/session/filesync/filesync.go b/session/filesync/filesync.go index aed7e87f4..1b52ffe2c 100644 --- a/session/filesync/filesync.go +++ b/session/filesync/filesync.go @@ -71,6 +71,7 @@ func (sp *fsSyncProvider) Register(server *grpc.Server) { func (sp *fsSyncProvider) DiffCopy(stream FileSync_DiffCopyServer) error { return sp.handle("diffcopy", stream) } + func (sp *fsSyncProvider) TarStream(stream FileSync_TarStreamServer) error { return sp.handle("tarstream", stream) } @@ -240,11 +241,12 @@ type FSSyncTarget interface { } type fsSyncTarget struct { - id int - outdir string - outdirFunc func(map[string]string) (string, error) // earthly - f FileOutputFunc - verboseProgressCB fsutil.VerboseProgressCB + id int + outdir string + outdirFunc func(map[string]string) (string, error) // earthly + f FileOutputFunc + progress progressCb + onFile fileCb } func (target *fsSyncTarget) target() *fsSyncTarget { @@ -266,21 +268,23 @@ func WithFSSyncDir(id int, outdir string) FSSyncTarget { } // NewFSSyncTargetDir allows writing into a directory -func NewFSSyncTargetDir(outdir string, verboseProgressCB fsutil.VerboseProgressCB) session.Attachable { +func NewFSSyncTargetDir(outdir string) session.Attachable { return NewFSSyncTarget(&fsSyncTarget{ - id: 0, - outdir: outdir, - verboseProgressCB: verboseProgressCB, + id: 0, + outdir: outdir, }) } +type fileCb func(string, int64) + // NewFSSyncTarget allows writing into an io.WriteCloser; it is earthly-specific -func NewFSSyncMultiTarget(f func(map[string]string) (io.WriteCloser, error), outdirFunc func(map[string]string) (string, error), verboseProgressCB fsutil.VerboseProgressCB) session.Attachable { +func NewFSSyncMultiTarget(f func(map[string]string) (io.WriteCloser, error), outdirFunc func(map[string]string) (string, error), progress progressCb, onFile fileCb) session.Attachable { return NewFSSyncTarget(&fsSyncTarget{ - id: 0, - f: f, - outdirFunc: outdirFunc, - verboseProgressCB: verboseProgressCB, + id: 0, + f: f, + outdirFunc: outdirFunc, + progress: progress, + onFile: onFile, }) } @@ -288,7 +292,8 @@ func NewFSSyncTarget(targets ...FSSyncTarget) session.Attachable { fs := make(map[int]FileOutputFunc) outdirs := make(map[int]string) outdirFuncs := make(map[int]func(map[string]string) (string, error)) - progressCBs := make(map[int]fsutil.VerboseProgressCB) + progressCBs := make(map[int]progressCb) + onFileCBs := make(map[int]fileCb) for _, t := range targets { t := t.target() if t.f != nil { @@ -300,8 +305,11 @@ func NewFSSyncTarget(targets ...FSSyncTarget) session.Attachable { if t.outdirFunc != nil { outdirFuncs[t.id] = t.outdirFunc } - if t.verboseProgressCB != nil { - progressCBs[t.id] = t.verboseProgressCB + if t.progress != nil { + progressCBs[t.id] = t.progress + } + if t.onFile != nil { + onFileCBs[t.id] = t.onFile } } return &fsSyncAttachable{ @@ -309,6 +317,7 @@ func NewFSSyncTarget(targets ...FSSyncTarget) session.Attachable { outdirs: outdirs, outdirFuncs: outdirFuncs, progressCBs: progressCBs, + onFileCBs: onFileCBs, } } @@ -316,7 +325,8 @@ type fsSyncAttachable struct { fs map[int]FileOutputFunc outdirs map[int]string outdirFuncs map[int]func(map[string]string) (string, error) - progressCBs map[int]fsutil.VerboseProgressCB + progressCBs map[int]progressCb + onFileCBs map[int]fileCb } func (sp *fsSyncAttachable) Register(server *grpc.Server) { @@ -341,12 +351,16 @@ func (sp *fsSyncAttachable) chooser(ctx context.Context) int { func (sp *fsSyncAttachable) DiffCopy(stream FileSend_DiffCopyServer) (err error) { id := sp.chooser(stream.Context()) - var verboseCB fsutil.VerboseProgressCB + var progressCB progressCb if sp.progressCBs != nil { - verboseCB = sp.progressCBs[id] + progressCB = sp.progressCBs[id] + } + var onFileCB fileCb + if sp.onFileCBs != nil { + onFileCB = sp.onFileCBs[id] } if outdir, ok := sp.outdirs[id]; ok { - return syncTargetDiffCopy(stream, outdir, verboseCB) + return syncTargetDiffCopy(stream, outdir, progressCB, onFileCB) } f, ok := sp.fs[id] if !ok { @@ -367,7 +381,7 @@ func (sp *fsSyncAttachable) DiffCopy(stream FileSend_DiffCopyServer) (err error) return err } if outdir != "" { - return syncTargetDiffCopy(stream, outdir, verboseCB) + return syncTargetDiffCopy(stream, outdir, progressCB, onFileCB) } } } diff --git a/session/localhost/localhost.go b/session/localhost/localhost.go index 14bdc3b44..30c97acaa 100644 --- a/session/localhost/localhost.go +++ b/session/localhost/localhost.go @@ -325,7 +325,7 @@ func localhostPutSendDir(stream Localhost_GetClient, src, dst string) error { return err } - err = fsutil.Send(stream.Context(), stream, fs, nil, nil) + err = fsutil.Send(stream.Context(), stream, fs, nil) if err != nil { return errors.Wrap(err, "fsutil.Send failed") } diff --git a/session/localhost/localhostprovider/localhostprovider.go b/session/localhost/localhostprovider/localhostprovider.go index 2517e0b3c..3dc642144 100644 --- a/session/localhost/localhostprovider/localhostprovider.go +++ b/session/localhost/localhostprovider/localhostprovider.go @@ -259,7 +259,7 @@ func sendDir(stream localhost.Localhost_GetServer, path string) error { if err != nil { return err } - err = fsutil.Send(stream.Context(), stream, fs, nil, nil) + err = fsutil.Send(stream.Context(), stream, fs, nil) if err != nil { return errors.Wrap(err, "fsutil.Send failed") } diff --git a/vendor/github.com/tonistiigi/fsutil/filter.go b/vendor/github.com/tonistiigi/fsutil/filter.go index 483980091..9cee8ad23 100644 --- a/vendor/github.com/tonistiigi/fsutil/filter.go +++ b/vendor/github.com/tonistiigi/fsutil/filter.go @@ -30,8 +30,7 @@ type FilterOpt struct { // Map is called for each path that is included in the result. // The function can modify the stat info for each element, while the result // of the function controls both how Walk continues. - Map MapFunc - VerboseProgressCB VerboseProgressCB // earthly-specific + Map MapFunc } type MapFunc func(string, *types.Stat) MapResult @@ -62,8 +61,7 @@ type filterFS struct { onlyPrefixIncludes bool onlyPrefixExcludeExceptions bool - mapFn MapFunc - verboseProgressCB VerboseProgressCB // earthly-specific + mapFn MapFunc } // NewFilterFS creates a new FS that filters the given FS using the given @@ -146,7 +144,6 @@ func NewFilterFS(fs FS, opt *FilterOpt) (FS, error) { onlyPrefixIncludes: onlyPrefixIncludes, onlyPrefixExcludeExceptions: onlyPrefixExcludeExceptions, mapFn: opt.Map, - verboseProgressCB: opt.VerboseProgressCB, // earthly-specific }, nil } @@ -269,9 +266,6 @@ func (fs *filterFS) Walk(ctx context.Context, target string, fn gofs.WalkDirFunc } if m { - if fs.verboseProgressCB != nil { // earthly-specific - fs.verboseProgressCB(path, StatusSkipped, 0) - } if isDir && fs.onlyPrefixExcludeExceptions { // Optimization: we can skip walking this dir if no // exceptions to exclude patterns could match anything diff --git a/vendor/github.com/tonistiigi/fsutil/receive.go b/vendor/github.com/tonistiigi/fsutil/receive.go index afb118bb7..6a82d205b 100644 --- a/vendor/github.com/tonistiigi/fsutil/receive.go +++ b/vendor/github.com/tonistiigi/fsutil/receive.go @@ -52,13 +52,12 @@ const ( ) type ReceiveOpt struct { - NotifyHashed ChangeFunc - ContentHasher ContentHasher - ProgressCb func(int, bool) - VerboseProgressCb VerboseProgressCB - Merge bool - Filter FilterFunc - Differ DiffType + NotifyHashed ChangeFunc + ContentHasher ContentHasher + ProgressCb func(int, bool) + Merge bool + Filter FilterFunc + Differ DiffType } func Receive(ctx context.Context, conn Stream, dest string, opt ReceiveOpt) error { @@ -66,35 +65,31 @@ func Receive(ctx context.Context, conn Stream, dest string, opt ReceiveOpt) erro defer cancel() r := &receiver{ - conn: &syncStream{Stream: conn}, - dest: dest, - files: make(map[string]uint32), - pipes: make(map[uint32]io.WriteCloser), - pipeNames: make(map[uint32]string), // earthly-specific - notifyHashed: opt.NotifyHashed, - contentHasher: opt.ContentHasher, - progressCb: opt.ProgressCb, - verboseProgressCb: opt.VerboseProgressCb, // earthly-specific - merge: opt.Merge, - filter: opt.Filter, - differ: opt.Differ, + conn: &syncStream{Stream: conn}, + dest: dest, + files: make(map[string]uint32), + pipes: make(map[uint32]io.WriteCloser), + notifyHashed: opt.NotifyHashed, + contentHasher: opt.ContentHasher, + progressCb: opt.ProgressCb, + merge: opt.Merge, + filter: opt.Filter, + differ: opt.Differ, } return r.run(ctx) } type receiver struct { - dest string - conn Stream - files map[string]uint32 - pipes map[uint32]io.WriteCloser - pipeNames map[uint32]string // earthly-specific - mu sync.RWMutex - muPipes sync.RWMutex - progressCb func(int, bool) - verboseProgressCb VerboseProgressCB // earthly-specific - merge bool - filter FilterFunc - differ DiffType + dest string + conn Stream + files map[string]uint32 + pipes map[uint32]io.WriteCloser + mu sync.RWMutex + muPipes sync.RWMutex + progressCb func(int, bool) + merge bool + filter FilterFunc + differ DiffType notifyHashed ChangeFunc contentHasher ContentHasher @@ -221,9 +216,6 @@ func (r *receiver) run(ctx context.Context) error { } break } - if r.verboseProgressCb != nil { - r.verboseProgressCb(p.Stat.Path, StatusStat, p.Size()) - } // normalize unix wire-specific paths to platform-specific paths path := filepath.FromSlash(p.Stat.Path) @@ -254,22 +246,15 @@ func (r *receiver) run(ctx context.Context) error { case types.PACKET_DATA: r.muPipes.Lock() pw, ok := r.pipes[p.ID] - pipeName := r.pipeNames[p.ID] r.muPipes.Unlock() if !ok { return errors.Errorf("invalid file request %d", p.ID) } if len(p.Data) == 0 { - if r.verboseProgressCb != nil { - r.verboseProgressCb(pipeName, StatusReceived, 0) - } if err := pw.Close(); err != nil { return err } } else { - if r.verboseProgressCb != nil { - r.verboseProgressCb(pipeName, StatusReceiving, len(p.Data)) - } if _, err := pw.Write(p.Data); err != nil { return err } @@ -303,7 +288,6 @@ func (r *receiver) asyncDataFunc(ctx context.Context, p string, wc io.WriteClose wwc := newWrappedWriteCloser(wc) r.muPipes.Lock() r.pipes[id] = wwc - r.pipeNames[id] = p r.muPipes.Unlock() if err := r.conn.SendMsg(&types.Packet{Type: types.PACKET_REQ, ID: id}); err != nil { return err @@ -314,7 +298,6 @@ func (r *receiver) asyncDataFunc(ctx context.Context, p string, wc io.WriteClose } r.muPipes.Lock() delete(r.pipes, id) - delete(r.pipeNames, id) r.muPipes.Unlock() return nil } diff --git a/vendor/github.com/tonistiigi/fsutil/send.go b/vendor/github.com/tonistiigi/fsutil/send.go index 8e6942215..e4a315638 100644 --- a/vendor/github.com/tonistiigi/fsutil/send.go +++ b/vendor/github.com/tonistiigi/fsutil/send.go @@ -26,14 +26,13 @@ type Stream interface { Context() context.Context } -func Send(ctx context.Context, conn Stream, fs FS, progressCb func(int, bool), verboseProgressCb VerboseProgressCB) error { +func Send(ctx context.Context, conn Stream, fs FS, progressCb func(int, bool)) error { s := &sender{ - conn: &syncStream{Stream: conn}, - fs: WithHardlinkReset(fs), - files: make(map[uint32]string), - progressCb: progressCb, - verboseProgressCb: verboseProgressCb, - sendpipeline: make(chan *sendHandle, 128), + conn: &syncStream{Stream: conn}, + fs: WithHardlinkReset(fs), + files: make(map[uint32]string), + progressCb: progressCb, + sendpipeline: make(chan *sendHandle, 128), } return s.run(ctx) } @@ -49,7 +48,6 @@ type sender struct { files map[uint32]string mu sync.RWMutex progressCb func(int, bool) - verboseProgressCb VerboseProgressCB progressCurrent int progressCurrentMu sync.Mutex sendpipeline chan *sendHandle @@ -114,9 +112,6 @@ func (s *sender) run(ctx context.Context) error { } func (s *sender) updateProgress(size int, last bool) { - s.mu.Lock() - defer s.mu.Unlock() - s.progressCurrent += size if s.progressCb != nil { s.progressCurrentMu.Lock() defer s.progressCurrentMu.Unlock() @@ -144,13 +139,9 @@ func (s *sender) sendFile(h *sendHandle) error { defer f.Close() buf := bufPool.Get().(*[]byte) defer bufPool.Put(buf) - fs := fileSender{sender: s, id: h.id} - if _, err := io.CopyBuffer(&fs, struct{ io.Reader }{f}, *buf); err != nil { + if _, err := io.CopyBuffer(&fileSender{sender: s, id: h.id}, struct{ io.Reader }{f}, *buf); err != nil { return err } - if s.verboseProgressCb != nil { - s.verboseProgressCb(h.path, StatusSent, fs.bytesWritten) - } } return s.conn.SendMsg(&types.Packet{ID: h.id, Type: types.PACKET_DATA}) } @@ -182,11 +173,6 @@ func (s *sender) walk(ctx context.Context) error { } i++ s.updateProgress(p.Size(), false) - - if s.verboseProgressCb != nil { - s.verboseProgressCb(path, StatusStat, p.Size()) - } - return errors.Wrapf(s.conn.SendMsg(p), "failed to send stat %s", path) }) if err != nil { @@ -202,9 +188,8 @@ func fileCanRequestData(m os.FileMode) bool { } type fileSender struct { - sender *sender - id uint32 - bytesWritten int + sender *sender + id uint32 } func (fs *fileSender) Write(dt []byte) (int, error) { @@ -216,7 +201,6 @@ func (fs *fileSender) Write(dt []byte) (int, error) { return 0, err } fs.sender.updateProgress(p.Size(), false) - fs.bytesWritten += len(dt) return len(dt), nil } diff --git a/vendor/github.com/tonistiigi/fsutil/verbose_callback.go b/vendor/github.com/tonistiigi/fsutil/verbose_callback.go deleted file mode 100644 index 8e8d24ffb..000000000 --- a/vendor/github.com/tonistiigi/fsutil/verbose_callback.go +++ /dev/null @@ -1,15 +0,0 @@ -package fsutil - -type VerboseProgressStatus int - -const ( - StatusStat VerboseProgressStatus = iota - StatusSkipped - StatusSending - StatusSent - StatusReceiving - StatusReceived - StatusFailed -) - -type VerboseProgressCB func(string, VerboseProgressStatus, int) diff --git a/vendor/modules.txt b/vendor/modules.txt index e59863d8f..af544c21e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -821,7 +821,7 @@ github.com/spdx/tools-golang/spdx/v2/v2_3 ## explicit; go 1.20 github.com/stretchr/testify/assert github.com/stretchr/testify/require -# github.com/tonistiigi/fsutil v0.0.0-20240424095704-91a3fc46842c => github.com/earthbuild/fsutil v0.0.0-20261002194825-890baaee2294 +# github.com/tonistiigi/fsutil v0.0.0-20240424095704-91a3fc46842c ## explicit; go 1.20 github.com/tonistiigi/fsutil github.com/tonistiigi/fsutil/copy @@ -1140,4 +1140,3 @@ kernel.org/pub/linux/libs/security/libcap/cap # kernel.org/pub/linux/libs/security/libcap/psx v1.2.67 ## explicit; go 1.11 kernel.org/pub/linux/libs/security/libcap/psx -# github.com/tonistiigi/fsutil => github.com/earthbuild/fsutil v0.0.0-20261002194825-890baaee2294 From 961ef78d50fb51d00033aed3f0d3da385c91a293 Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 23 Oct 2026 10:20:56 +0100 Subject: [PATCH 16/17] fix: code review --- AGENTS.md | 11 ++ solver/llbsolver/earthly_exporters_test.go | 118 ++++++++++++++++++ .../llbsolver/ops/earthly_exec_mounts_test.go | 47 +++++++ solver/llbsolver/ops/exec.go | 7 ++ solver/llbsolver/solver.go | 14 +-- 5 files changed, 190 insertions(+), 7 deletions(-) create mode 100644 solver/llbsolver/earthly_exporters_test.go create mode 100644 solver/llbsolver/ops/earthly_exec_mounts_test.go diff --git a/AGENTS.md b/AGENTS.md index a4f252c6c..926b10529 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,6 +2,17 @@ This repository is a fork of [moby/buildkit](https://github.com/moby/buildkit). Its primary use is by [earthbuild/earthbuild](https://github.com/earthbuild/earthbuild). +## Naming + +The project is being renamed from Earthly to EarthBuild. When writing new code, +comments, docs or commit messages: + +- Use `earth` for the CLI / build tool (not `earthly`). +- Use `EarthBuild` for the project name (not `Earthly`). +- Leave existing `earthly` identifiers alone where they are literal: Earthfile + target names (`+earthly-docker`) and published image/repo names. Those change + only as part of the rename itself. + ## Guidelines - Any code changes must be kept to a minimum to reduce the potential for merge conflicts with upstream `moby/buildkit`. diff --git a/solver/llbsolver/earthly_exporters_test.go b/solver/llbsolver/earthly_exporters_test.go new file mode 100644 index 000000000..e0568255e --- /dev/null +++ b/solver/llbsolver/earthly_exporters_test.go @@ -0,0 +1,118 @@ +package llbsolver + +import ( + "context" + "sync/atomic" + "testing" + + "github.com/moby/buildkit/cache" + "github.com/moby/buildkit/client" + "github.com/moby/buildkit/exporter" + "github.com/moby/buildkit/exporter/containerimage/exptypes" + "github.com/moby/buildkit/exporter/verifier" + "github.com/moby/buildkit/solver" + "github.com/moby/buildkit/solver/result" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// fakeExporterInstance is a minimal exporter.ExporterInstance that records +// whether Export was called. +type fakeExporterInstance struct { + typ string + exported atomic.Bool +} + +func (e *fakeExporterInstance) ID() int { return 0 } +func (e *fakeExporterInstance) Name() string { return "fake " + e.typ } +func (e *fakeExporterInstance) Config() *exporter.Config { return exporter.NewConfig() } +func (e *fakeExporterInstance) Type() string { return e.typ } +func (e *fakeExporterInstance) Attrs() map[string]string { return nil } +func (e *fakeExporterInstance) Export(_ context.Context, _ *exporter.Source, _ exptypes.InlineCache, _ string) (map[string]string, exporter.DescriptorReference, error) { + e.exported.Store(true) + return nil, nil, nil +} + +// earthly-specific: runExporters skips verifier.CheckInvalidPlatforms only +// when every exporter is the EarthBuild exporter. A non-EarthBuild exporter in +// the same solve must keep the upstream v0.14 result validation rather than +// be handed a multi-ref result without a platforms mapping. +func TestRunExportersValidatesNonEarthlyExporterAlongsideEarthly(t *testing.T) { + t.Parallel() + ctx := context.Background() + + tests := []struct { + name string + exporterTypes []string + wantErr string + wantExported bool + }{ + { + name: "no exporters", + exporterTypes: nil, + wantErr: "build result contains multiple refs without platforms mapping", + wantExported: false, + }, + { + name: "non-earthly exporter only", + exporterTypes: []string{client.ExporterImage}, + wantErr: "build result contains multiple refs without platforms mapping", + wantExported: false, + }, + { + name: "earthly exporter only", + exporterTypes: []string{client.ExporterEarthly}, + wantErr: "", + wantExported: true, + }, + { + name: "mixed earthly and non-earthly exporters", + exporterTypes: []string{client.ExporterEarthly, client.ExporterImage}, + wantErr: "build result contains multiple refs without platforms mapping", + wantExported: false, + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + jl := solver.NewSolver(solver.SolverOpt{}) + defer jl.Close() + + job, err := jl.NewJob("j0") + require.NoError(t, err) + defer job.Discard() + + // EarthBuild-shaped result: several named refs, no platforms mapping. + inp := &result.Result[cache.ImmutableRef]{ + Refs: map[string]cache.ImmutableRef{ + "output-0": nil, + "output-1": nil, + }, + } + require.NoError(t, verifier.CaptureFrontendOpts(map[string]string{}, inp)) + + exporters := make([]exporter.ExporterInstance, 0, len(tc.exporterTypes)) + fakes := make([]*fakeExporterInstance, 0, len(tc.exporterTypes)) + for _, typ := range tc.exporterTypes { + f := &fakeExporterInstance{typ: typ} + exporters = append(exporters, f) + fakes = append(fakes, f) + } + + s := &Solver{} + _, _, err = s.runExporters(ctx, exporters, nil, job, nil, inp) + if tc.wantErr != "" { + require.ErrorContains(t, err, tc.wantErr) + } else { + require.NoError(t, err) + } + + for _, f := range fakes { + assert.Equal(t, tc.wantExported, f.exported.Load(), "unexpected exported state for exporter %q", f.typ) + } + }) + } +} diff --git a/solver/llbsolver/ops/earthly_exec_mounts_test.go b/solver/llbsolver/ops/earthly_exec_mounts_test.go new file mode 100644 index 000000000..f037f2edc --- /dev/null +++ b/solver/llbsolver/ops/earthly_exec_mounts_test.go @@ -0,0 +1,47 @@ +package ops + +import ( + "context" + "testing" + + "github.com/moby/buildkit/session" + "github.com/moby/buildkit/solver/pb" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// earthly-specific: verify that special non-input mounts (secret, ssh, tmpfs, +// socket, and host-bind) do not register selectors or enable content-based +// hashing on the rootfs input even when their proto Input field defaults to 0. +func TestExecOpEarthlySpecialMountsNotContentHashed(t *testing.T) { + t.Parallel() + + op := &ExecOp{ + numInputs: 1, + op: &pb.ExecOp{ + Meta: &pb.Meta{Args: []string{"/bin/sh", "-c", "echo hi"}}, + Mounts: []*pb.Mount{ + {Input: 0, Dest: "/", Output: 0}, + {Input: pb.Empty, Selector: "/usr/bin/earth_debugger", Dest: "/usr/bin/earth_debugger", Output: 1, MountType: pb.MountType_HOST_BIND}, + {Input: 0, Selector: "/usr/bin/earth_debugger_ro", Dest: "/usr/bin/earth_debugger_ro", Output: pb.SkipOutput, MountType: pb.MountType_HOST_BIND}, + {Input: 0, Dest: "/run/secrets/earthly_debugger_settings", Output: 0, MountType: pb.MountType_SECRET, SecretOpt: &pb.SecretOpt{ID: "earthly_debugger_settings"}}, + {Input: 0, Dest: "/run/buildkit/ssh_agent.0", Output: 0, MountType: pb.MountType_SSH, SSHOpt: &pb.SSHOpt{ID: "default"}}, + {Input: 0, Dest: "/tmp/work", Output: pb.SkipOutput, MountType: pb.MountType_TMPFS, TmpfsOpt: &pb.TmpfsOpt{Size_: 1024}}, + {Input: 0, Dest: "/var/run/earthly_interactive", Output: 0, MountType: pb.MountType_SOCKET, SockOpt: &pb.SockOpt{ID: "earthly_interactive"}}, + {Input: 0, Dest: "/var/run/earthly_save", Output: 0, MountType: pb.MountType_SOCKET, SockOpt: &pb.SockOpt{ID: "earthly_save_file"}}, + }, + }, + } + + deps, err := op.getMountDeps() + require.NoError(t, err) + require.Len(t, deps, 1) + assert.False(t, deps[0].ContentBasedHash, "rootfs input must not be content-hashed") + assert.Equal(t, []string{"/"}, deps[0].Selectors, "only the rootfs mount should select from input 0") + + m, ok, err := op.CacheMap(context.Background(), session.NewGroup(t.Name()), 1) + require.NoError(t, err) + require.True(t, ok) + require.Len(t, m.Deps, 1) + assert.Nil(t, m.Deps[0].ComputeDigestFunc, "rootfs dep must not have a content-based (slow) cache key") +} diff --git a/solver/llbsolver/ops/exec.go b/solver/llbsolver/ops/exec.go index 927533584..4aed2f2ba 100644 --- a/solver/llbsolver/ops/exec.go +++ b/solver/llbsolver/ops/exec.go @@ -289,6 +289,13 @@ type dep struct { func (e *ExecOp) getMountDeps() ([]dep, error) { deps := make([]dep, e.numInputs) for _, m := range e.op.Mounts { + switch m.MountType { + case pb.MountType_SECRET, pb.MountType_SSH, pb.MountType_TMPFS: + continue + case pb.MountType_SOCKET, pb.MountType_HOST_BIND: // earth-specific: socket and host-bind mounts have no input vertex + continue + } + if m.Input == pb.Empty { continue } diff --git a/solver/llbsolver/solver.go b/solver/llbsolver/solver.go index 17054a6c9..c767740e1 100644 --- a/solver/llbsolver/solver.go +++ b/solver/llbsolver/solver.go @@ -739,19 +739,19 @@ func runInlineCacheExporter(ctx context.Context, e exporter.ExporterInstance, in } func (s *Solver) runExporters(ctx context.Context, exporters []exporter.ExporterInstance, inlineCacheExporter inlineCacheExporter, job *solver.Job, cached *result.Result[solver.CachedResult], inp *result.Result[cache.ImmutableRef]) (exporterResponse map[string]string, descrefs []exporter.DescriptorReference, err error) { - var isEarthBuild bool - - // EarthBuild uses res.Refs as a dictionary of named build outputs, not target platforms. - // Platform verification is handled per-image inside the Earthly exporter. + // earthly-specific: EarthBuild uses inp.Refs for named outputs without an + // ExporterPlatformsKey mapping, which CheckInvalidPlatforms rejects. Skip + // the check only when every exporter is client.ExporterEarthly. + onlyEarthBuild := len(exporters) > 0 for _, exp := range exporters { - if exp.Type() == client.ExporterEarthly { - isEarthBuild = true + if exp.Type() != client.ExporterEarthly { + onlyEarthBuild = false break } } var warnings []client.VertexWarning - if !isEarthBuild { + if !onlyEarthBuild { warnings, err = verifier.CheckInvalidPlatforms(ctx, inp) if err != nil { return nil, nil, err From 2fc50e525c1e6d754af943c19e9bcbacef70e499 Mon Sep 17 00:00:00 2001 From: Janis Horsts Date: Fri, 23 Oct 2026 10:57:37 +0100 Subject: [PATCH 17/17] fix: make lint --- .coderabbit.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 49e716e07..f19d29d51 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -1,4 +1,4 @@ reviews: path_filters: - "!vendor/**" - - "!**/vendor/**" \ No newline at end of file + - "!**/vendor/**"