Compare commits

..

74 Commits

Author SHA1 Message Date
Tõnis Tiigi
1dc5f0751b Merge pull request #2983 from tonistiigi/update-buildkit-v0.20.0-rc1
vendor: update buildkit to v0.20.0-rc1
2025-02-11 16:20:02 -08:00
Tonis Tiigi
7ba4da0800 gha: send v2 url as url_v2
Some repositories already have v2 enabled and that
causes errors avainst older BuildKit. To avoid that we
need to send both URLs as separate keys.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2025-02-11 15:49:29 -08:00
Tonis Tiigi
a64e628774 .github: test github runtime envs
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2025-02-11 15:41:15 -08:00
Tonis Tiigi
1c4b1a376c show CDI devices in builder inspection
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2025-02-11 14:52:33 -08:00
Tonis Tiigi
e1f690abfc allow passing github cache v2 urls from env
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2025-02-11 14:52:33 -08:00
Tonis Tiigi
03569c2188 vendor: update buildkit to v0.20.0-rc1
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2025-02-11 14:52:19 -08:00
Tõnis Tiigi
350d3f0f4b Merge pull request #2904 from tonistiigi/history-command-trace
Add history trace command
2025-02-11 12:40:10 -08:00
CrazyMax
dc27815236 ci: fix git config for unit tests
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-02-11 11:40:04 -08:00
Tonis Tiigi
1089ff7341 history: add comparison support to trace
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2025-02-11 11:40:04 -08:00
Tonis Tiigi
7433d37183 history: add loadTrace function and support for loading Nth trace
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2025-02-11 11:40:04 -08:00
Tonis Tiigi
f9a76355b5 history: add UI view to traces
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2025-02-11 11:40:01 -08:00
Tonis Tiigi
cfeea34b2d add history trace command
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2025-02-11 11:38:23 -08:00
Tõnis Tiigi
ba2d3692a6 Merge pull request #2982 from crazy-max/revert-docker-28-vendor
Revert "vendor: docker, docker/cli v28.0.0-rc.1"
2025-02-11 11:37:32 -08:00
Tõnis Tiigi
853b593a4d Merge pull request #2981 from crazy-max/hack-mount-docker-cfg
hack: mount docker config on gha
2025-02-11 10:36:45 -08:00
CrazyMax
efb300e613 chore: fix vendoring
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-02-11 19:17:35 +01:00
CrazyMax
cee7b344da Revert "vendor: github.com/docker/docker/v28.0.0-rc.1"
This reverts commit b195b80ddf.

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-02-11 18:14:49 +01:00
CrazyMax
67dbde6970 Revert "vendor: github.com/docker/cli/v28.0.0-rc.1"
This reverts commit 7216086b8c.

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-02-11 18:14:49 +01:00
CrazyMax
295653dabb hack: mount docker config on gha
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-02-11 17:32:50 +01:00
CrazyMax
f5802119c5 Merge pull request #2978 from jsternberg/rangefunc-go1.22-revert
buildflags: make work on go 1.22 by reverting rangefunc usage
2025-02-11 10:47:01 +01:00
CrazyMax
40b9ac1ec5 Merge pull request #2979 from tonistiigi/update-buildkit-0e3037c0182e
vendor: update buildkit to 0e3037c0182e
2025-02-11 10:29:51 +01:00
Tonis Tiigi
f11496448a vendor: update buildkit to 0e3037c0182e
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2025-02-10 16:48:59 -08:00
Tõnis Tiigi
c8c9c72ca6 Merge pull request #2964 from crazy-max/history-inspect-json
history: inspect json and go template format
2025-02-10 16:30:42 -08:00
Tõnis Tiigi
9fe8139022 Merge pull request #2976 from crazy-max/ci-fix-vagrant
ci: install latest vagrant
2025-02-10 16:16:15 -08:00
CrazyMax
b3e8c62635 ci: install latest vagrant
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-02-10 20:54:44 +01:00
Tõnis Tiigi
b8e9c28315 Merge pull request #2970 from crazy-max/fix-ls-json
ls: fix duplicated builders for json format
2025-02-10 09:28:17 -08:00
Jonathan A. Sternberg
3ae9970da5 buildflags: make work on go 1.22 by reverting rangefunc usage
Reverts the usage of rangefunc and attempts to keep the foundation of it
in for when we move to go 1.23. We have downstream dependencies that
aren't ready to move to go 1.23. We can likely move after go 1.24 is
released.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2025-02-10 11:03:46 -06:00
CrazyMax
1d219100fc Merge pull request #2868 from thaJeztah/bump_engine
vendor: docker, docker/cli v28.0.0-rc.1
2025-02-10 17:22:31 +01:00
CrazyMax
464f9278d1 history: fix default format for inspect command
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-02-10 11:30:59 +01:00
Sebastiaan van Stijn
7216086b8c vendor: github.com/docker/cli/v28.0.0-rc.1
full diff: https://github.com/docker/cli/compare/v27.5.1..v28.0.0-rc.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-10 11:07:38 +01:00
Sebastiaan van Stijn
b195b80ddf vendor: github.com/docker/docker/v28.0.0-rc.1
full diff: https://github.com/docker/docker/compare/v27.5.1..v28.0.0-rc.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-10 11:07:35 +01:00
Sebastiaan van Stijn
70a5e266d1 vendor: github.com/moby/term v0.5.2
full diff:

- https://github.com/moby/term/compare/v0.5.0...v0.5.2
- d185dfc1b5...faa5f7b017

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-10 11:06:24 +01:00
Sebastiaan van Stijn
689bea7963 vendor: golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f
full diff: 701f63a606...2d47ceb269

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-10 11:06:22 +01:00
Sebastiaan van Stijn
5176c38115 vendor: golang.org/x/mod v0.22.0
full diff: https://github.com/golang/mod/compare/v0.21.0...v0.22.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-10 11:05:52 +01:00
Sebastiaan van Stijn
ec440c4574 vendor: golang.org/x/sys v0.29.0
full diff: https://github.com/golang/sys/compare/v0.28.0...v0.29.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-10 11:05:51 +01:00
CrazyMax
0a4eb7ec76 Merge pull request #2971 from thaJeztah/test_engine_28
Dockerfile: update to docker v28.0.0-rc.1
2025-02-10 11:03:38 +01:00
Sebastiaan van Stijn
f710c93157 vendor: github.com/docker/cli v27.5.1
no changes in vendored code

full diff: https://github.com/docker/cli/compare/v27.5.0...v27.5.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-09 13:53:05 +01:00
Sebastiaan van Stijn
d1a0a1497c vendor: github.com/docker/docker v27.5.1
no changes in vendored code

full diff: https://github.com/docker/docker/compare/v27.5.0...v27.5.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-09 13:53:05 +01:00
Sebastiaan van Stijn
c880ecd513 Dockerfile: update to docker v28.0.0-rc.1
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-09 13:50:14 +01:00
Tõnis Tiigi
d557da1935 Merge pull request #2957 from ndeloof/prompt-rawjson
don't warn user about missing --allows when running with progress=rawjson
2025-02-07 16:34:10 -08:00
CrazyMax
417af36abc history: support go template format for inspect
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-02-07 12:09:31 +01:00
CrazyMax
e236b86297 history: set materials and attachments to json output for inspect
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-02-07 12:09:31 +01:00
CrazyMax
633e8a0881 history: add error sources and stack to json output for inspect
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-02-07 11:37:46 +01:00
CrazyMax
5e1ea62f92 ls: fix duplicated builders for json format
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-02-07 10:23:55 +01:00
Tõnis Tiigi
4b90b84995 Merge pull request #2965 from jsternberg/handle-unknown-values
buildflags: handle unknown values from cty
2025-02-06 10:06:49 -08:00
Jonathan A. Sternberg
abc85c38f8 buildflags: handle unknown values from cty
Update the buildflags cty code to handle unknown values. When hcl
decodes a value with an invalid variable name, it appends a diagnostic
for the error and then returns an unknown value so it can continue
processing the file and finding more errors.

The iteration code has now been changed to use a rangefunc from go 1.23
and it skips empty or unknown values. Empty values are valid when they
are skipped and unknown values will have a diagnostic for itself.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2025-02-06 09:45:18 -06:00
CrazyMax
ccca7c795a history: json format support for inspect command
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-02-06 16:25:49 +01:00
CrazyMax
04aab6958c history: set num steps, name, default platform and error logs to inspect
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-02-06 16:12:37 +01:00
Tonis Tiigi
9d640f0e33 history: add formatting support to inspect
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2025-02-06 10:45:27 +01:00
CrazyMax
b76fdcaf8d Merge pull request #2963 from thaJeztah/consistent_alias
use a consistent alias for the docker client package
2025-02-03 13:39:27 +01:00
Sebastiaan van Stijn
d693e18c04 use a consistent alias for the docker client package
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-03 11:36:52 +01:00
CrazyMax
b066ee1110 Merge pull request #2961 from thaJeztah/driver_use_errdefs
driver/docker-container: remove uses of dockerclient.IsErrNotFound
2025-02-03 09:41:24 +01:00
CrazyMax
cf8bf9e104 Merge pull request #2950 from thaJeztah/fix_usage_and_completion
fix: strip path from usage output and shell-completion scripts
2025-02-02 01:11:29 +01:00
Sebastiaan van Stijn
3bd54b19aa driver/docker-container: remove uses of dockerclient.IsErrNotFound
It's a wrapper around errdefs.IsNotFound, which is already used, so we
can skip the wrapper.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-01 15:22:33 +01:00
Tõnis Tiigi
934841f329 Merge pull request #2958 from crazy-max/fix-debug-invoke
debug: fix invoke on error
2025-01-31 10:17:08 -08:00
CrazyMax
b2ababc7b6 debug: fix invoke on error
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-01-31 10:45:34 +01:00
Nicolas De Loof
0ccdb7e248 don't warn user about missing --allows when running with progress=rawjson
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-01-31 08:49:36 +01:00
CrazyMax
cacb4fb9b3 Merge pull request #2953 from dvdksn/docs-bake-composable-attrs
docs: update bake reference to use composable attrs
2025-01-29 10:44:05 +01:00
David Karlsson
df80bd72c6 docs: update bake reference to use composable attrs
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2025-01-29 09:55:45 +01:00
Sebastiaan van Stijn
bb4bef2f04 fix: strip path from usage output and shell-completion scripts
Before this patch, both "usage" and shell-completion scripts would preserve
the path of the invoked command, which was especially problematic for the
completion-scripts, because Cobra's completion depends on Command.Name()
for this (see [1], [2]);

    ./bin/build/buildx --help | head -n 5
    Extended build capabilities with BuildKit

    Usage:
      ./bin/build/buildx
      ./bin/build/buildx [command]

    ./bin/build/buildx completion bash | head -n 3
    # bash completion V2 for ./bin/build/buildx                   -*- shell-script -*-

    __./bin/build/buildx_debug()

This would also be problematic if the path contained a space, for example;

    ln -s $(pwd)/bin/build $(pwd)/bin/Program\ Files

    ./bin/Program\ Files/buildx completion bash | head -n 3
    # bash completion V2 for ./bin/Program                        -*- shell-script -*-

    __./bin/Program_debug()

With this patch, the path is stripped to prevent this issue;

    ./bin/build/buildx --help | head -n 5
    Extended build capabilities with BuildKit

    Usage:
      buildx
      buildx [command]

    ./bin/build/buildx completion bash | head -n 3
    # bash completion V2 for buildx                               -*- shell-script -*-

    __buildx_debug()

    ./bin/Program\ Files/buildx completion bash | head -n 3
    # bash completion V2 for buildx                               -*- shell-script -*-

    __buildx_debug()

It's worth noting that this patch only fixes these basic issues. Other cases
are not yet addressed, and may need fixes in Cobra because (especially for
the completion scripts) it should likely not conflate "Name" with "executable".

For example, command.Name() does not handle situations where the executable
itself has a space in its name:

    ln -s $(pwd)/bin/build/buildx $(pwd)/bin/build/hello\ world

    ./bin/build/hello\ world completion bash | head -n 3
    # bash completion V2 for hello                                -*- shell-script -*-

    __hello_debug()

Other, less problematic, issues to address are case-insensitive filesystems,
where the binary can be invoked with any case;

    ./bin/build/bUiLdX --help | head -n 5
    Extended build capabilities with BuildKit

    Usage:
      bUiLdX
      bUiLdX [command]

    ./bin/build/bUiLdX completion bash | head -n 3
    # bash completion V2 for bUiLdX                               -*- shell-script -*-

    __bUiLdX_debug()

[1]: https://github.com/spf13/cobra/blob/v1.8.1/bash_completionsV2.go#L24-L39
[2]: https://github.com/spf13/cobra/blob/v1.8.1/command.go#L1502-L1510

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-01-25 14:25:43 +01:00
Tõnis Tiigi
a11507344a Merge pull request #2932 from crazy-max/buildkit-0.19.0
vendor: update buildkit to v0.19.0
2025-01-22 12:57:37 -08:00
Tõnis Tiigi
17af006857 Merge pull request #2944 from jsternberg/cache-ref-only-format-fix
buildflags: fix ref only format for command line and bake
2025-01-22 12:57:02 -08:00
Jonathan A. Sternberg
11c84973ef buildflags: fix ref only format for command line and bake
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2025-01-22 13:18:38 -06:00
Tõnis Tiigi
cc4a291f6a Merge pull request #2941 from crazy-max/ci-fix-docs-upstream
ci: use main branch for docs upstream validation workflow
2025-01-22 10:36:56 -08:00
CrazyMax
aa1fbc0421 ci: use main branch for docs upstream validation workflow
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-01-22 19:11:26 +01:00
Tõnis Tiigi
b2bbb337e4 Merge pull request #2835 from dvdksn/bake-v019-entitlements
docs: bake v0.19 entitlements
2025-01-22 09:48:38 -08:00
David Karlsson
012df71b63 docs: add docs for bake --allow
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2025-01-22 18:25:32 +01:00
David Karlsson
a26bb271ab docs(bake): improve docs on "call" and "description" in bake file
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2025-01-22 18:23:18 +01:00
CrazyMax
3e0682f039 Merge pull request #2937 from jsternberg/attests-json-marshal
buildflags: marshal attestations into json with extra attributes correctly
2025-01-22 09:16:54 +01:00
Jonathan A. Sternberg
3aed658dc4 buildflags: marshal attestations into json with extra attributes correctly
`MarshalJSON` would not include the extra attributes because it iterated
over the target map rather than the source map.

Also fixes JSON unmarshaling for SSH and secrets. The intention was to
unmarshal into the struct, but `UnmarshalText` takes priority over the
default struct unmarshaling so it didn't work as intended.

Tests have been added for all marshaling and unmarshaling methods.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2025-01-21 15:05:23 -06:00
CrazyMax
b4a0dee723 Merge pull request #2935 from crazy-max/ci-update-buildkit
ci: update buildkit to 0.19.0
2025-01-21 13:50:26 +01:00
CrazyMax
6904512813 ci: update buildkit to 0.19.0
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-01-21 10:31:14 +01:00
CrazyMax
d41e335466 Merge pull request #2934 from crazy-max/update-buildkit-dockerfile
dockerfile: update buildkit to 0.19.0
2025-01-21 10:17:21 +01:00
CrazyMax
0954dcb5fd dockerfile: update buildkit to 0.19.0
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-01-20 20:41:12 +01:00
CrazyMax
38f64bf709 vendor: update buildkit to v0.19.0
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-01-20 18:55:10 +01:00
174 changed files with 41293 additions and 3190 deletions

View File

@@ -54,7 +54,7 @@ jobs:
- master - master
- latest - latest
- buildx-stable-1 - buildx-stable-1
- v0.19.0-rc2 - v0.19.0
- v0.18.2 - v0.18.2
- v0.17.2 - v0.17.2
worker: worker:
@@ -174,6 +174,11 @@ jobs:
env: env:
SKIP_INTEGRATION_TESTS: 1 SKIP_INTEGRATION_TESTS: 1
steps: steps:
-
name: Setup Git config
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -264,8 +269,10 @@ jobs:
name: Install vagrant name: Install vagrant
run: | run: |
set -x set -x
wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt-get update sudo apt-get update
sudo apt-get install -y libvirt-daemon libvirt-daemon-system vagrant vagrant-libvirt ruby-libvirt sudo apt-get install -y libvirt-dev libvirt-daemon libvirt-daemon-system vagrant vagrant-libvirt ruby-libvirt
sudo systemctl enable --now libvirtd sudo systemctl enable --now libvirtd
sudo chmod a+rw /var/run/libvirt/libvirt-sock sudo chmod a+rw /var/run/libvirt/libvirt-sock
vagrant plugin install vagrant-libvirt vagrant plugin install vagrant-libvirt

View File

@@ -215,6 +215,9 @@ jobs:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
-
name: Expose GitHub Runtime
uses: crazy-max/ghaction-github-runtime@v3
- -
name: Environment variables name: Environment variables
if: matrix.envs != '' if: matrix.envs != ''

View File

@@ -43,6 +43,9 @@ linters-settings:
# buildkit errdefs package (or vice-versa). # buildkit errdefs package (or vice-versa).
- pkg: "github.com/containerd/errdefs" - pkg: "github.com/containerd/errdefs"
alias: "cerrdefs" alias: "cerrdefs"
# Use a consistent alias to prevent confusion with "github.com/moby/buildkit/client"
- pkg: "github.com/docker/docker/client"
alias: "dockerclient"
- pkg: "github.com/opencontainers/image-spec/specs-go/v1" - pkg: "github.com/opencontainers/image-spec/specs-go/v1"
alias: "ocispecs" alias: "ocispecs"
- pkg: "github.com/opencontainers/go-digest" - pkg: "github.com/opencontainers/go-digest"

View File

@@ -5,12 +5,12 @@ ARG ALPINE_VERSION=3.21
ARG XX_VERSION=1.6.1 ARG XX_VERSION=1.6.1
# for testing # for testing
ARG DOCKER_VERSION=27.5.0 ARG DOCKER_VERSION=28.0.0-rc.1
ARG DOCKER_VERSION_ALT_26=26.1.3 ARG DOCKER_VERSION_ALT_26=26.1.3
ARG DOCKER_CLI_VERSION=${DOCKER_VERSION} ARG DOCKER_CLI_VERSION=${DOCKER_VERSION}
ARG GOTESTSUM_VERSION=v1.12.0 ARG GOTESTSUM_VERSION=v1.12.0
ARG REGISTRY_VERSION=2.8.3 ARG REGISTRY_VERSION=2.8.3
ARG BUILDKIT_VERSION=v0.19.0-rc2 ARG BUILDKIT_VERSION=v0.19.0
ARG UNDOCK_VERSION=0.9.0 ARG UNDOCK_VERSION=0.9.0
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx

View File

@@ -1130,7 +1130,9 @@ func (t *Target) GetName(ectx *hcl.EvalContext, block *hcl.Block, loadDeps func(
func TargetsToBuildOpt(m map[string]*Target, inp *Input) (map[string]build.Options, error) { func TargetsToBuildOpt(m map[string]*Target, inp *Input) (map[string]build.Options, error) {
// make sure local credentials are loaded multiple times for different targets // make sure local credentials are loaded multiple times for different targets
dockerConfig := config.LoadDefaultConfigFile(os.Stderr) dockerConfig := config.LoadDefaultConfigFile(os.Stderr)
authProvider := authprovider.NewDockerAuthProvider(dockerConfig, nil) authProvider := authprovider.NewDockerAuthProvider(authprovider.DockerAuthProviderConfig{
ConfigFile: dockerConfig,
})
m2 := make(map[string]build.Options, len(m)) m2 := make(map[string]build.Options, len(m))
for k, v := range m { for k, v := range m {

View File

@@ -2,8 +2,10 @@ package bake
import ( import (
"reflect" "reflect"
"regexp"
"testing" "testing"
hcl "github.com/hashicorp/hcl/v2"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -647,7 +649,7 @@ func TestHCLAttrsCapsuleType(t *testing.T) {
require.Equal(t, []string{"default", "key=path/to/key"}, stringify(c.Targets[0].SSH)) require.Equal(t, []string{"default", "key=path/to/key"}, stringify(c.Targets[0].SSH))
} }
func TestHCLAttrsCapsuleTypeVars(t *testing.T) { func TestHCLAttrsCapsuleType_ObjectVars(t *testing.T) {
dt := []byte(` dt := []byte(`
variable "foo" { variable "foo" {
default = "bar" default = "bar"
@@ -716,6 +718,52 @@ func TestHCLAttrsCapsuleTypeVars(t *testing.T) {
require.Equal(t, []string{"id=oci,src=/local/secret"}, stringify(web.Secrets)) require.Equal(t, []string{"id=oci,src=/local/secret"}, stringify(web.Secrets))
} }
func TestHCLAttrsCapsuleType_MissingVars(t *testing.T) {
dt := []byte(`
target "app" {
attest = [
"type=sbom,disabled=${SBOM}",
]
cache-from = [
{ type = "registry", ref = "user/app:${FOO1}" },
"type=local,src=path/to/cache:${FOO2}",
]
cache-to = [
{ type = "local", dest = "path/to/${BAR}" },
]
output = [
{ type = "oci", dest = "../${OUTPUT}.tar" },
]
secret = [
{ id = "mysecret", src = "/local/${SECRET}" },
]
ssh = [
{ id = "key", paths = ["path/to/${SSH_KEY}"] },
]
}
`)
var diags hcl.Diagnostics
_, err := ParseFile(dt, "docker-bake.hcl")
require.ErrorAs(t, err, &diags)
re := regexp.MustCompile(`There is no variable named "([\w\d_]+)"`)
var actual []string
for _, diag := range diags {
if m := re.FindStringSubmatch(diag.Error()); m != nil {
actual = append(actual, m[1])
}
}
require.ElementsMatch(t,
[]string{"SBOM", "FOO1", "FOO2", "BAR", "OUTPUT", "SECRET", "SSH_KEY"},
actual)
}
func TestHCLMultiFileAttrs(t *testing.T) { func TestHCLMultiFileAttrs(t *testing.T) {
dt := []byte(` dt := []byte(`
variable "FOO" { variable "FOO" {

View File

@@ -36,6 +36,7 @@ type Node struct {
Platforms []ocispecs.Platform Platforms []ocispecs.Platform
GCPolicy []client.PruneInfo GCPolicy []client.PruneInfo
Labels map[string]string Labels map[string]string
CDIDevices []client.CDIDevice
} }
// Nodes returns nodes for this builder. // Nodes returns nodes for this builder.
@@ -259,6 +260,7 @@ func (n *Node) loadData(ctx context.Context, clientOpt ...client.ClientOpt) erro
n.GCPolicy = w.GCPolicy n.GCPolicy = w.GCPolicy
n.Labels = w.Labels n.Labels = w.Labels
} }
n.CDIDevices = w.CDIDevices
} }
sort.Strings(n.IDs) sort.Strings(n.IDs)
n.Platforms = platformutil.Dedupe(n.Platforms) n.Platforms = platformutil.Dedupe(n.Platforms)

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"os" "os"
"path/filepath"
"github.com/docker/buildx/commands" "github.com/docker/buildx/commands"
controllererrors "github.com/docker/buildx/controller/errdefs" controllererrors "github.com/docker/buildx/controller/errdefs"
@@ -41,7 +42,8 @@ func runStandalone(cmd *command.DockerCli) error {
} }
defer flushMetrics(cmd) defer flushMetrics(cmd)
rootCmd := commands.NewRootCmd(os.Args[0], false, cmd) executable := os.Args[0]
rootCmd := commands.NewRootCmd(filepath.Base(executable), false, cmd)
return rootCmd.Execute() return rootCmd.Execute()
} }

View File

@@ -271,9 +271,11 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
if err != nil { if err != nil {
return err return err
} }
if progressMode != progressui.RawJSONMode {
if err := exp.Prompt(ctx, url != "", &syncWriter{w: dockerCli.Err(), wait: printer.Wait}); err != nil { if err := exp.Prompt(ctx, url != "", &syncWriter{w: dockerCli.Err(), wait: printer.Wait}); err != nil {
return err return err
} }
}
if printer.IsDone() { if printer.IsDone() {
// init new printer as old one was stopped to show the prompt // init new printer as old one was stopped to show the prompt
if err := makePrinter(); err != nil { if err := makePrinter(); err != nil {

View File

@@ -466,7 +466,7 @@ func runControllerBuild(ctx context.Context, dockerCli command.Cli, opts *contro
if err != nil { if err != nil {
var be *controllererrors.BuildError var be *controllererrors.BuildError
if errors.As(err, &be) { if errors.As(err, &be) {
ref = be.Ref ref = be.SessionID
retErr = err retErr = err
// We can proceed to monitor // We can proceed to monitor
} else { } else {

View File

@@ -13,6 +13,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"text/tabwriter" "text/tabwriter"
"text/template"
"time" "time"
"github.com/containerd/containerd/v2/core/content" "github.com/containerd/containerd/v2/core/content"
@@ -25,6 +26,7 @@ import (
"github.com/docker/buildx/util/confutil" "github.com/docker/buildx/util/confutil"
"github.com/docker/buildx/util/desktop" "github.com/docker/buildx/util/desktop"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/cli/cli/debug" "github.com/docker/cli/cli/debug"
slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common"
slsa02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" slsa02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2"
@@ -45,9 +47,114 @@ import (
proto "google.golang.org/protobuf/proto" proto "google.golang.org/protobuf/proto"
) )
type statusT string
const (
statusComplete statusT = "completed"
statusRunning statusT = "running"
statusError statusT = "failed"
statusCanceled statusT = "canceled"
)
type inspectOptions struct { type inspectOptions struct {
builder string builder string
ref string ref string
format string
}
type inspectOutput struct {
Name string `json:",omitempty"`
Ref string
Context string `json:",omitempty"`
Dockerfile string `json:",omitempty"`
VCSRepository string `json:",omitempty"`
VCSRevision string `json:",omitempty"`
Target string `json:",omitempty"`
Platform []string `json:",omitempty"`
KeepGitDir bool `json:",omitempty"`
NamedContexts []keyValueOutput `json:",omitempty"`
StartedAt *time.Time `json:",omitempty"`
CompletedAt *time.Time `json:",omitempty"`
Duration time.Duration `json:",omitempty"`
Status statusT `json:",omitempty"`
Error *errorOutput `json:",omitempty"`
NumCompletedSteps int32
NumTotalSteps int32
NumCachedSteps int32
BuildArgs []keyValueOutput `json:",omitempty"`
Labels []keyValueOutput `json:",omitempty"`
Config configOutput `json:",omitempty"`
Materials []materialOutput `json:",omitempty"`
Attachments []attachmentOutput `json:",omitempty"`
Errors []string `json:",omitempty"`
}
type configOutput struct {
Network string `json:",omitempty"`
ExtraHosts []string `json:",omitempty"`
Hostname string `json:",omitempty"`
CgroupParent string `json:",omitempty"`
ImageResolveMode string `json:",omitempty"`
MultiPlatform bool `json:",omitempty"`
NoCache bool `json:",omitempty"`
NoCacheFilter []string `json:",omitempty"`
ShmSize string `json:",omitempty"`
Ulimit string `json:",omitempty"`
CacheMountNS string `json:",omitempty"`
DockerfileCheckConfig string `json:",omitempty"`
SourceDateEpoch string `json:",omitempty"`
SandboxHostname string `json:",omitempty"`
RestRaw []keyValueOutput `json:",omitempty"`
}
type materialOutput struct {
URI string `json:",omitempty"`
Digests []string `json:",omitempty"`
}
type attachmentOutput struct {
Digest string `json:",omitempty"`
Platform string `json:",omitempty"`
Type string `json:",omitempty"`
}
type errorOutput struct {
Code int `json:",omitempty"`
Message string `json:",omitempty"`
Name string `json:",omitempty"`
Logs []string `json:",omitempty"`
Sources []byte `json:",omitempty"`
Stack []byte `json:",omitempty"`
}
type keyValueOutput struct {
Name string `json:",omitempty"`
Value string `json:",omitempty"`
}
func readAttr[T any](attrs map[string]string, k string, dest *T, f func(v string) (T, bool)) {
if sv, ok := attrs[k]; ok {
if f != nil {
v, ok := f(sv)
if ok {
*dest = v
}
}
if d, ok := any(dest).(*string); ok {
*d = sv
}
}
delete(attrs, k)
} }
func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) error { func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) error {
@@ -86,28 +193,36 @@ func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions)
rec := &recs[0] rec := &recs[0]
c, err := rec.node.Driver.Client(ctx)
if err != nil {
return err
}
store := proxy.NewContentStore(c.ContentClient())
var defaultPlatform string
workers, err := c.ListWorkers(ctx)
if err != nil {
return errors.Wrap(err, "failed to list workers")
}
workers0:
for _, w := range workers {
for _, p := range w.Platforms {
defaultPlatform = platforms.FormatAll(platforms.Normalize(p))
break workers0
}
}
ls, err := localstate.New(confutil.NewConfig(dockerCli)) ls, err := localstate.New(confutil.NewConfig(dockerCli))
if err != nil { if err != nil {
return err return err
} }
st, _ := ls.ReadRef(rec.node.Builder, rec.node.Name, rec.Ref) st, _ := ls.ReadRef(rec.node.Builder, rec.node.Name, rec.Ref)
tw := tabwriter.NewWriter(dockerCli.Out(), 1, 8, 1, '\t', 0)
attrs := rec.FrontendAttrs attrs := rec.FrontendAttrs
delete(attrs, "frontend.caps") delete(attrs, "frontend.caps")
writeAttr := func(k, name string, f func(v string) (string, bool)) { var out inspectOutput
if v, ok := attrs[k]; ok {
if f != nil {
v, ok = f(v)
}
if ok {
fmt.Fprintf(tw, "%s:\t%s\n", name, v)
}
}
delete(attrs, k)
}
var context string var context string
var dockerfile string var dockerfile string
@@ -146,131 +261,171 @@ func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions)
} }
delete(attrs, "filename") delete(attrs, "filename")
if context != "" { out.Name = buildName(rec.FrontendAttrs, st)
fmt.Fprintf(tw, "Context:\t%s\n", context) out.Ref = rec.Ref
}
if dockerfile != "" { out.Context = context
fmt.Fprintf(tw, "Dockerfile:\t%s\n", dockerfile) out.Dockerfile = dockerfile
}
if _, ok := attrs["context"]; !ok { if _, ok := attrs["context"]; !ok {
if src, ok := attrs["vcs:source"]; ok { if src, ok := attrs["vcs:source"]; ok {
fmt.Fprintf(tw, "VCS Repository:\t%s\n", src) out.VCSRepository = src
} }
if rev, ok := attrs["vcs:revision"]; ok { if rev, ok := attrs["vcs:revision"]; ok {
fmt.Fprintf(tw, "VCS Revision:\t%s\n", rev) out.VCSRevision = rev
} }
} }
writeAttr("target", "Target", nil) readAttr(attrs, "target", &out.Target, nil)
writeAttr("platform", "Platform", func(v string) (string, bool) {
return tryParseValue(v, func(v string) (string, error) { readAttr(attrs, "platform", &out.Platform, func(v string) ([]string, bool) {
return tryParseValue(v, &out.Errors, func(v string) ([]string, error) {
var pp []string var pp []string
for _, v := range strings.Split(v, ",") { for _, v := range strings.Split(v, ",") {
p, err := platforms.Parse(v) p, err := platforms.Parse(v)
if err != nil { if err != nil {
return "", err return nil, err
} }
pp = append(pp, platforms.FormatAll(platforms.Normalize(p))) pp = append(pp, platforms.FormatAll(platforms.Normalize(p)))
} }
return strings.Join(pp, ", "), nil if len(pp) == 0 {
}), true pp = append(pp, defaultPlatform)
})
writeAttr("build-arg:BUILDKIT_CONTEXT_KEEP_GIT_DIR", "Keep Git Dir", func(v string) (string, bool) {
return tryParseValue(v, func(v string) (string, error) {
b, err := strconv.ParseBool(v)
if err != nil {
return "", err
} }
return strconv.FormatBool(b), nil return pp, nil
}), true })
}) })
tw.Flush() readAttr(attrs, "build-arg:BUILDKIT_CONTEXT_KEEP_GIT_DIR", &out.KeepGitDir, func(v string) (bool, bool) {
return tryParseValue(v, &out.Errors, strconv.ParseBool)
})
fmt.Fprintln(dockerCli.Out()) out.NamedContexts = readKeyValues(attrs, "context:")
printTable(dockerCli.Out(), attrs, "context:", "Named Context") if rec.CreatedAt != nil {
tm := rec.CreatedAt.AsTime().Local()
out.StartedAt = &tm
}
out.Status = statusRunning
tw = tabwriter.NewWriter(dockerCli.Out(), 1, 8, 1, '\t', 0)
fmt.Fprintf(tw, "Started:\t%s\n", rec.CreatedAt.AsTime().Local().Format("2006-01-02 15:04:05"))
var duration time.Duration
var statusStr string
if rec.CompletedAt != nil { if rec.CompletedAt != nil {
duration = rec.CompletedAt.AsTime().Sub(rec.CreatedAt.AsTime()) tm := rec.CompletedAt.AsTime().Local()
} else { out.CompletedAt = &tm
duration = rec.currentTimestamp.Sub(rec.CreatedAt.AsTime()) out.Status = statusComplete
statusStr = " (running)"
} }
fmt.Fprintf(tw, "Duration:\t%s%s\n", formatDuration(duration), statusStr)
if rec.Error != nil || rec.ExternalError != nil {
out.Error = &errorOutput{}
if rec.Error != nil { if rec.Error != nil {
if codes.Code(rec.Error.Code) == codes.Canceled { if codes.Code(rec.Error.Code) == codes.Canceled {
fmt.Fprintf(tw, "Status:\tCanceled\n") out.Status = statusCanceled
} else { } else {
fmt.Fprintf(tw, "Error:\t%s %s\n", codes.Code(rec.Error.Code).String(), rec.Error.Message) out.Status = statusError
}
out.Error.Code = int(codes.Code(rec.Error.Code))
out.Error.Message = rec.Error.Message
}
if rec.ExternalError != nil {
dt, err := content.ReadBlob(ctx, store, ociDesc(rec.ExternalError))
if err != nil {
return errors.Wrapf(err, "failed to read external error %s", rec.ExternalError.Digest)
}
var st spb.Status
if err := proto.Unmarshal(dt, &st); err != nil {
return errors.Wrapf(err, "failed to unmarshal external error %s", rec.ExternalError.Digest)
}
retErr := grpcerrors.FromGRPC(status.ErrorProto(&st))
var errsources bytes.Buffer
for _, s := range errdefs.Sources(retErr) {
s.Print(&errsources)
errsources.WriteString("\n")
}
out.Error.Sources = errsources.Bytes()
var ve *errdefs.VertexError
if errors.As(retErr, &ve) {
dgst, err := digest.Parse(ve.Vertex.Digest)
if err != nil {
return errors.Wrapf(err, "failed to parse vertex digest %s", ve.Vertex.Digest)
}
name, logs, err := loadVertexLogs(ctx, c, rec.Ref, dgst, 16)
if err != nil {
return errors.Wrapf(err, "failed to load vertex logs %s", dgst)
}
out.Error.Name = name
out.Error.Logs = logs
}
out.Error.Stack = []byte(fmt.Sprintf("%+v", stack.Formatter(retErr)))
} }
} }
fmt.Fprintf(tw, "Build Steps:\t%d/%d (%.0f%% cached)\n", rec.NumCompletedSteps, rec.NumTotalSteps, float64(rec.NumCachedSteps)/float64(rec.NumTotalSteps)*100)
tw.Flush()
fmt.Fprintln(dockerCli.Out()) if out.StartedAt != nil {
if out.CompletedAt != nil {
out.Duration = out.CompletedAt.Sub(*out.StartedAt)
} else {
out.Duration = rec.currentTimestamp.Sub(*out.StartedAt)
}
}
tw = tabwriter.NewWriter(dockerCli.Out(), 1, 8, 1, '\t', 0) out.NumCompletedSteps = rec.NumCompletedSteps
out.NumTotalSteps = rec.NumTotalSteps
out.NumCachedSteps = rec.NumCachedSteps
writeAttr("force-network-mode", "Network", nil) out.BuildArgs = readKeyValues(attrs, "build-arg:")
writeAttr("hostname", "Hostname", nil) out.Labels = readKeyValues(attrs, "label:")
writeAttr("add-hosts", "Extra Hosts", func(v string) (string, bool) {
return tryParseValue(v, func(v string) (string, error) { readAttr(attrs, "force-network-mode", &out.Config.Network, nil)
readAttr(attrs, "hostname", &out.Config.Hostname, nil)
readAttr(attrs, "cgroup-parent", &out.Config.CgroupParent, nil)
readAttr(attrs, "image-resolve-mode", &out.Config.ImageResolveMode, nil)
readAttr(attrs, "build-arg:BUILDKIT_MULTI_PLATFORM", &out.Config.MultiPlatform, func(v string) (bool, bool) {
return tryParseValue(v, &out.Errors, strconv.ParseBool)
})
readAttr(attrs, "multi-platform", &out.Config.MultiPlatform, func(v string) (bool, bool) {
return tryParseValue(v, &out.Errors, strconv.ParseBool)
})
readAttr(attrs, "no-cache", &out.Config.NoCache, func(v string) (bool, bool) {
if v == "" {
return true, true
}
return false, false
})
readAttr(attrs, "no-cache", &out.Config.NoCacheFilter, func(v string) ([]string, bool) {
if v == "" {
return nil, false
}
return strings.Split(v, ","), true
})
readAttr(attrs, "add-hosts", &out.Config.ExtraHosts, func(v string) ([]string, bool) {
return tryParseValue(v, &out.Errors, func(v string) ([]string, error) {
fields, err := csvvalue.Fields(v, nil) fields, err := csvvalue.Fields(v, nil)
if err != nil { if err != nil {
return "", err return nil, err
} }
return strings.Join(fields, ", "), nil return fields, nil
}), true
}) })
writeAttr("cgroup-parent", "Cgroup Parent", nil)
writeAttr("image-resolve-mode", "Image Resolve Mode", nil)
writeAttr("multi-platform", "Force Multi-Platform", nil)
writeAttr("build-arg:BUILDKIT_MULTI_PLATFORM", "Force Multi-Platform", nil)
writeAttr("no-cache", "Disable Cache", func(v string) (string, bool) {
if v == "" {
return "true", true
}
return v, true
}) })
writeAttr("shm-size", "Shm Size", nil)
writeAttr("ulimit", "Resource Limits", nil)
writeAttr("build-arg:BUILDKIT_CACHE_MOUNT_NS", "Cache Mount Namespace", nil)
writeAttr("build-arg:BUILDKIT_DOCKERFILE_CHECK", "Dockerfile Check Config", nil)
writeAttr("build-arg:SOURCE_DATE_EPOCH", "Source Date Epoch", nil)
writeAttr("build-arg:SANDBOX_HOSTNAME", "Sandbox Hostname", nil)
var unusedAttrs []string readAttr(attrs, "shm-size", &out.Config.ShmSize, nil)
readAttr(attrs, "ulimit", &out.Config.Ulimit, nil)
readAttr(attrs, "build-arg:BUILDKIT_CACHE_MOUNT_NS", &out.Config.CacheMountNS, nil)
readAttr(attrs, "build-arg:BUILDKIT_DOCKERFILE_CHECK", &out.Config.DockerfileCheckConfig, nil)
readAttr(attrs, "build-arg:SOURCE_DATE_EPOCH", &out.Config.SourceDateEpoch, nil)
readAttr(attrs, "build-arg:SANDBOX_HOSTNAME", &out.Config.SandboxHostname, nil)
var unusedAttrs []keyValueOutput
for k := range attrs { for k := range attrs {
if strings.HasPrefix(k, "vcs:") || strings.HasPrefix(k, "build-arg:") || strings.HasPrefix(k, "label:") || strings.HasPrefix(k, "context:") || strings.HasPrefix(k, "attest:") { if strings.HasPrefix(k, "vcs:") || strings.HasPrefix(k, "build-arg:") || strings.HasPrefix(k, "label:") || strings.HasPrefix(k, "context:") || strings.HasPrefix(k, "attest:") {
continue continue
} }
unusedAttrs = append(unusedAttrs, k) unusedAttrs = append(unusedAttrs, keyValueOutput{
Name: k,
Value: attrs[k],
})
} }
slices.Sort(unusedAttrs) slices.SortFunc(unusedAttrs, func(a, b keyValueOutput) int {
return cmp.Compare(a.Name, b.Name)
for _, k := range unusedAttrs { })
fmt.Fprintf(tw, "%s:\t%s\n", k, attrs[k]) out.Config.RestRaw = unusedAttrs
}
tw.Flush()
fmt.Fprintln(dockerCli.Out())
printTable(dockerCli.Out(), attrs, "build-arg:", "Build Arg")
printTable(dockerCli.Out(), attrs, "label:", "Label")
c, err := rec.node.Driver.Client(ctx)
if err != nil {
return err
}
store := proxy.NewContentStore(c.ContentClient())
attachments, err := allAttachments(ctx, store, *rec) attachments, err := allAttachments(ctx, store, *rec)
if err != nil { if err != nil {
@@ -282,83 +437,211 @@ func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions)
}) })
if provIndex != -1 { if provIndex != -1 {
prov := attachments[provIndex] prov := attachments[provIndex]
dt, err := content.ReadBlob(ctx, store, prov.descr) dt, err := content.ReadBlob(ctx, store, prov.descr)
if err != nil { if err != nil {
return errors.Errorf("failed to read provenance %s: %v", prov.descr.Digest, err) return errors.Errorf("failed to read provenance %s: %v", prov.descr.Digest, err)
} }
var pred provenancetypes.ProvenancePredicate var pred provenancetypes.ProvenancePredicate
if err := json.Unmarshal(dt, &pred); err != nil { if err := json.Unmarshal(dt, &pred); err != nil {
return errors.Errorf("failed to unmarshal provenance %s: %v", prov.descr.Digest, err) return errors.Errorf("failed to unmarshal provenance %s: %v", prov.descr.Digest, err)
} }
fmt.Fprintln(dockerCli.Out(), "Materials:")
tw = tabwriter.NewWriter(dockerCli.Out(), 1, 8, 1, '\t', 0)
fmt.Fprintf(tw, "URI\tDIGEST\n")
for _, m := range pred.Materials { for _, m := range pred.Materials {
fmt.Fprintf(tw, "%s\t%s\n", m.URI, strings.Join(digestSetToDigests(m.Digest), ", ")) out.Materials = append(out.Materials, materialOutput{
URI: m.URI,
Digests: digestSetToDigests(m.Digest),
})
} }
tw.Flush()
fmt.Fprintln(dockerCli.Out())
} }
if len(attachments) > 0 { if len(attachments) > 0 {
fmt.Fprintf(tw, "Attachments:\n")
tw = tabwriter.NewWriter(dockerCli.Out(), 1, 8, 1, '\t', 0)
fmt.Fprintf(tw, "DIGEST\tPLATFORM\tTYPE\n")
for _, a := range attachments { for _, a := range attachments {
p := "" p := ""
if a.platform != nil { if a.platform != nil {
p = platforms.FormatAll(*a.platform) p = platforms.FormatAll(*a.platform)
} }
fmt.Fprintf(tw, "%s\t%s\t%s\n", a.descr.Digest, p, descrType(a.descr)) out.Attachments = append(out.Attachments, attachmentOutput{
Digest: a.descr.Digest.String(),
Platform: p,
Type: descrType(a.descr),
})
}
}
if opts.format == formatter.JSONFormatKey {
enc := json.NewEncoder(dockerCli.Out())
enc.SetIndent("", " ")
return enc.Encode(out)
} else if opts.format != formatter.PrettyFormatKey {
tmpl, err := template.New("inspect").Parse(opts.format)
if err != nil {
return errors.Wrapf(err, "failed to parse format template")
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, out); err != nil {
return errors.Wrapf(err, "failed to execute format template")
}
fmt.Fprintln(dockerCli.Out(), buf.String())
return nil
}
tw := tabwriter.NewWriter(dockerCli.Out(), 1, 8, 1, '\t', 0)
if out.Name != "" {
fmt.Fprintf(tw, "Name:\t%s\n", out.Name)
}
if opts.ref == "" && out.Ref != "" {
fmt.Fprintf(tw, "Ref:\t%s\n", out.Ref)
}
if out.Context != "" {
fmt.Fprintf(tw, "Context:\t%s\n", out.Context)
}
if out.Dockerfile != "" {
fmt.Fprintf(tw, "Dockerfile:\t%s\n", out.Dockerfile)
}
if out.VCSRepository != "" {
fmt.Fprintf(tw, "VCS Repository:\t%s\n", out.VCSRepository)
}
if out.VCSRevision != "" {
fmt.Fprintf(tw, "VCS Revision:\t%s\n", out.VCSRevision)
}
if out.Target != "" {
fmt.Fprintf(tw, "Target:\t%s\n", out.Target)
}
if len(out.Platform) > 0 {
fmt.Fprintf(tw, "Platforms:\t%s\n", strings.Join(out.Platform, ", "))
}
if out.KeepGitDir {
fmt.Fprintf(tw, "Keep Git Dir:\t%s\n", strconv.FormatBool(out.KeepGitDir))
}
tw.Flush()
fmt.Fprintln(dockerCli.Out())
printTable(dockerCli.Out(), out.NamedContexts, "Named Context")
tw = tabwriter.NewWriter(dockerCli.Out(), 1, 8, 1, '\t', 0)
fmt.Fprintf(tw, "Started:\t%s\n", out.StartedAt.Format("2006-01-02 15:04:05"))
var statusStr string
if out.Status == statusRunning {
statusStr = " (running)"
}
fmt.Fprintf(tw, "Duration:\t%s%s\n", formatDuration(out.Duration), statusStr)
if out.Status == statusError {
fmt.Fprintf(tw, "Error:\t%s %s\n", codes.Code(rec.Error.Code).String(), rec.Error.Message)
} else if out.Status == statusCanceled {
fmt.Fprintf(tw, "Status:\tCanceled\n")
}
fmt.Fprintf(tw, "Build Steps:\t%d/%d (%.0f%% cached)\n", out.NumCompletedSteps, out.NumTotalSteps, float64(out.NumCachedSteps)/float64(out.NumTotalSteps)*100)
tw.Flush()
fmt.Fprintln(dockerCli.Out())
tw = tabwriter.NewWriter(dockerCli.Out(), 1, 8, 1, '\t', 0)
if out.Config.Network != "" {
fmt.Fprintf(tw, "Network:\t%s\n", out.Config.Network)
}
if out.Config.Hostname != "" {
fmt.Fprintf(tw, "Hostname:\t%s\n", out.Config.Hostname)
}
if len(out.Config.ExtraHosts) > 0 {
fmt.Fprintf(tw, "Extra Hosts:\t%s\n", strings.Join(out.Config.ExtraHosts, ", "))
}
if out.Config.CgroupParent != "" {
fmt.Fprintf(tw, "Cgroup Parent:\t%s\n", out.Config.CgroupParent)
}
if out.Config.ImageResolveMode != "" {
fmt.Fprintf(tw, "Image Resolve Mode:\t%s\n", out.Config.ImageResolveMode)
}
if out.Config.MultiPlatform {
fmt.Fprintf(tw, "Multi-Platform:\t%s\n", strconv.FormatBool(out.Config.MultiPlatform))
}
if out.Config.NoCache {
fmt.Fprintf(tw, "No Cache:\t%s\n", strconv.FormatBool(out.Config.NoCache))
}
if len(out.Config.NoCacheFilter) > 0 {
fmt.Fprintf(tw, "No Cache Filter:\t%s\n", strings.Join(out.Config.NoCacheFilter, ", "))
}
if out.Config.ShmSize != "" {
fmt.Fprintf(tw, "Shm Size:\t%s\n", out.Config.ShmSize)
}
if out.Config.Ulimit != "" {
fmt.Fprintf(tw, "Resource Limits:\t%s\n", out.Config.Ulimit)
}
if out.Config.CacheMountNS != "" {
fmt.Fprintf(tw, "Cache Mount Namespace:\t%s\n", out.Config.CacheMountNS)
}
if out.Config.DockerfileCheckConfig != "" {
fmt.Fprintf(tw, "Dockerfile Check Config:\t%s\n", out.Config.DockerfileCheckConfig)
}
if out.Config.SourceDateEpoch != "" {
fmt.Fprintf(tw, "Source Date Epoch:\t%s\n", out.Config.SourceDateEpoch)
}
if out.Config.SandboxHostname != "" {
fmt.Fprintf(tw, "Sandbox Hostname:\t%s\n", out.Config.SandboxHostname)
}
for _, kv := range out.Config.RestRaw {
fmt.Fprintf(tw, "%s:\t%s\n", kv.Name, kv.Value)
}
tw.Flush()
fmt.Fprintln(dockerCli.Out())
printTable(dockerCli.Out(), out.BuildArgs, "Build Arg")
printTable(dockerCli.Out(), out.Labels, "Label")
if len(out.Materials) > 0 {
fmt.Fprintln(dockerCli.Out(), "Materials:")
tw = tabwriter.NewWriter(dockerCli.Out(), 1, 8, 1, '\t', 0)
fmt.Fprintf(tw, "URI\tDIGEST\n")
for _, m := range out.Materials {
fmt.Fprintf(tw, "%s\t%s\n", m.URI, strings.Join(m.Digests, ", "))
} }
tw.Flush() tw.Flush()
fmt.Fprintln(dockerCli.Out()) fmt.Fprintln(dockerCli.Out())
} }
if rec.ExternalError != nil { if len(out.Attachments) > 0 {
dt, err := content.ReadBlob(ctx, store, ociDesc(rec.ExternalError)) fmt.Fprintf(tw, "Attachments:\n")
if err != nil { tw = tabwriter.NewWriter(dockerCli.Out(), 1, 8, 1, '\t', 0)
return errors.Wrapf(err, "failed to read external error %s", rec.ExternalError.Digest) fmt.Fprintf(tw, "DIGEST\tPLATFORM\tTYPE\n")
} for _, a := range out.Attachments {
var st spb.Status fmt.Fprintf(tw, "%s\t%s\t%s\n", a.Digest, a.Platform, a.Type)
if err := proto.Unmarshal(dt, &st); err != nil {
return errors.Wrapf(err, "failed to unmarshal external error %s", rec.ExternalError.Digest)
}
retErr := grpcerrors.FromGRPC(status.ErrorProto(&st))
for _, s := range errdefs.Sources(retErr) {
s.Print(dockerCli.Out())
} }
tw.Flush()
fmt.Fprintln(dockerCli.Out()) fmt.Fprintln(dockerCli.Out())
}
var ve *errdefs.VertexError if out.Error != nil {
if errors.As(retErr, &ve) { if out.Error.Sources != nil {
dgst, err := digest.Parse(ve.Vertex.Digest) fmt.Fprint(dockerCli.Out(), string(out.Error.Sources))
if err != nil {
return errors.Wrapf(err, "failed to parse vertex digest %s", ve.Vertex.Digest)
} }
name, logs, err := loadVertexLogs(ctx, c, rec.Ref, dgst, 16) if len(out.Error.Logs) > 0 {
if err != nil {
return errors.Wrapf(err, "failed to load vertex logs %s", dgst)
}
if len(logs) > 0 {
fmt.Fprintln(dockerCli.Out(), "Logs:") fmt.Fprintln(dockerCli.Out(), "Logs:")
fmt.Fprintf(dockerCli.Out(), "> => %s:\n", name) fmt.Fprintf(dockerCli.Out(), "> => %s:\n", out.Error.Name)
for _, l := range logs { for _, l := range out.Error.Logs {
fmt.Fprintln(dockerCli.Out(), "> "+l) fmt.Fprintln(dockerCli.Out(), "> "+l)
} }
fmt.Fprintln(dockerCli.Out()) fmt.Fprintln(dockerCli.Out())
} }
} if len(out.Error.Stack) > 0 {
if debug.IsEnabled() { if debug.IsEnabled() {
fmt.Fprintf(dockerCli.Out(), "\n%+v\n", stack.Formatter(retErr)) fmt.Fprintf(dockerCli.Out(), "\n%s\n", out.Error.Stack)
} else if len(stack.Traces(retErr)) > 0 { } else {
fmt.Fprintf(dockerCli.Out(), "Enable --debug to see stack traces for error\n") fmt.Fprintf(dockerCli.Out(), "Enable --debug to see stack traces for error\n")
} }
} }
}
fmt.Fprintf(dockerCli.Out(), "Print build logs: docker buildx history logs %s\n", rec.Ref) fmt.Fprintf(dockerCli.Out(), "Print build logs: docker buildx history logs %s\n", rec.Ref)
@@ -388,7 +671,8 @@ func inspectCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
attachmentCmd(dockerCli, rootOpts), attachmentCmd(dockerCli, rootOpts),
) )
// flags := cmd.Flags() flags := cmd.Flags()
flags.StringVar(&options.format, "format", formatter.PrettyFormatKey, "Format the output")
return cmd return cmd
} }
@@ -565,36 +849,48 @@ func descrType(desc ocispecs.Descriptor) string {
return desc.MediaType return desc.MediaType
} }
func tryParseValue(s string, f func(string) (string, error)) string { func tryParseValue[T any](s string, errs *[]string, f func(string) (T, error)) (T, bool) {
v, err := f(s) v, err := f(s)
if err != nil { if err != nil {
return fmt.Sprintf("%s (%v)", s, err) errStr := fmt.Sprintf("failed to parse %s: (%v)", s, err)
*errs = append(*errs, errStr)
} }
return v return v, true
} }
func printTable(w io.Writer, attrs map[string]string, prefix, title string) { func printTable(w io.Writer, kvs []keyValueOutput, title string) {
var keys []string if len(kvs) == 0 {
for k := range attrs {
if strings.HasPrefix(k, prefix) {
keys = append(keys, strings.TrimPrefix(k, prefix))
}
}
slices.Sort(keys)
if len(keys) == 0 {
return return
} }
tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0) tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
fmt.Fprintf(tw, "%s\tVALUE\n", strings.ToUpper(title)) fmt.Fprintf(tw, "%s\tVALUE\n", strings.ToUpper(title))
for _, k := range keys { for _, k := range kvs {
fmt.Fprintf(tw, "%s\t%s\n", k, attrs[prefix+k]) fmt.Fprintf(tw, "%s\t%s\n", k.Name, k.Value)
} }
tw.Flush() tw.Flush()
fmt.Fprintln(w) fmt.Fprintln(w)
} }
func readKeyValues(attrs map[string]string, prefix string) []keyValueOutput {
var out []keyValueOutput
for k, v := range attrs {
if strings.HasPrefix(k, prefix) {
out = append(out, keyValueOutput{
Name: strings.TrimPrefix(k, prefix),
Value: v,
})
}
}
if len(out) == 0 {
return nil
}
slices.SortFunc(out, func(a, b keyValueOutput) int {
return cmp.Compare(a.Name, b.Name)
})
return out
}
func digestSetToDigests(ds slsa.DigestSet) []string { func digestSetToDigests(ds slsa.DigestSet) []string {
var out []string var out []string
for k, v := range ds { for k, v := range ds {

View File

@@ -24,6 +24,7 @@ func RootCmd(rootcmd *cobra.Command, dockerCli command.Cli, opts RootOptions) *c
logsCmd(dockerCli, opts), logsCmd(dockerCli, opts),
inspectCmd(dockerCli, opts), inspectCmd(dockerCli, opts),
openCmd(dockerCli, opts), openCmd(dockerCli, opts),
traceCmd(dockerCli, opts),
) )
return cmd return cmd

260
commands/history/trace.go Normal file
View File

@@ -0,0 +1,260 @@
package history
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net"
"os"
"slices"
"strconv"
"strings"
"time"
"github.com/containerd/console"
"github.com/containerd/containerd/v2/core/content/proxy"
"github.com/docker/buildx/builder"
"github.com/docker/buildx/util/cobrautil/completion"
"github.com/docker/buildx/util/otelutil"
"github.com/docker/buildx/util/otelutil/jaeger"
"github.com/docker/cli/cli/command"
controlapi "github.com/moby/buildkit/api/services/control"
"github.com/opencontainers/go-digest"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/browser"
"github.com/pkg/errors"
"github.com/spf13/cobra"
jaegerui "github.com/tonistiigi/jaeger-ui-rest"
)
type traceOptions struct {
builder string
ref string
addr string
compare string
}
func loadTrace(ctx context.Context, ref string, nodes []builder.Node) (string, []byte, error) {
var offset *int
if strings.HasPrefix(ref, "^") {
off, err := strconv.Atoi(ref[1:])
if err != nil {
return "", nil, errors.Wrapf(err, "invalid offset %q", ref)
}
offset = &off
ref = ""
}
recs, err := queryRecords(ctx, ref, nodes)
if err != nil {
return "", nil, err
}
var rec *historyRecord
if ref == "" {
slices.SortFunc(recs, func(a, b historyRecord) int {
return b.CreatedAt.AsTime().Compare(a.CreatedAt.AsTime())
})
for _, r := range recs {
if r.CompletedAt != nil {
if offset != nil {
if *offset > 0 {
*offset--
continue
}
}
rec = &r
break
}
}
if offset != nil && *offset > 0 {
return "", nil, errors.Errorf("no completed build found with offset %d", *offset)
}
} else {
rec = &recs[0]
}
if rec == nil {
if ref == "" {
return "", nil, errors.New("no records found")
}
return "", nil, errors.Errorf("no record found for ref %q", ref)
}
if rec.CompletedAt == nil {
return "", nil, errors.Errorf("build %q is not completed, only completed builds can be traced", rec.Ref)
}
if rec.Trace == nil {
// build is complete but no trace yet. try to finalize the trace
time.Sleep(1 * time.Second) // give some extra time for last parts of trace to be written
c, err := rec.node.Driver.Client(ctx)
if err != nil {
return "", nil, err
}
_, err = c.ControlClient().UpdateBuildHistory(ctx, &controlapi.UpdateBuildHistoryRequest{
Ref: rec.Ref,
Finalize: true,
})
if err != nil {
return "", nil, err
}
recs, err := queryRecords(ctx, rec.Ref, []builder.Node{*rec.node})
if err != nil {
return "", nil, err
}
if len(recs) == 0 {
return "", nil, errors.Errorf("build record %q was deleted", rec.Ref)
}
rec = &recs[0]
if rec.Trace == nil {
return "", nil, errors.Errorf("build record %q is missing a trace", rec.Ref)
}
}
c, err := rec.node.Driver.Client(ctx)
if err != nil {
return "", nil, err
}
store := proxy.NewContentStore(c.ContentClient())
ra, err := store.ReaderAt(ctx, ocispecs.Descriptor{
Digest: digest.Digest(rec.Trace.Digest),
MediaType: rec.Trace.MediaType,
Size: rec.Trace.Size,
})
if err != nil {
return "", nil, err
}
spans, err := otelutil.ParseSpanStubs(io.NewSectionReader(ra, 0, ra.Size()))
if err != nil {
return "", nil, err
}
wrapper := struct {
Data []jaeger.Trace `json:"data"`
}{
Data: spans.JaegerData().Data,
}
if len(wrapper.Data) == 0 {
return "", nil, errors.New("no trace data")
}
buf := &bytes.Buffer{}
enc := json.NewEncoder(buf)
enc.SetIndent("", " ")
if err := enc.Encode(wrapper); err != nil {
return "", nil, err
}
return string(wrapper.Data[0].TraceID), buf.Bytes(), nil
}
func runTrace(ctx context.Context, dockerCli command.Cli, opts traceOptions) error {
b, err := builder.New(dockerCli, builder.WithName(opts.builder))
if err != nil {
return err
}
nodes, err := b.LoadNodes(ctx)
if err != nil {
return err
}
for _, node := range nodes {
if node.Err != nil {
return node.Err
}
}
traceID, data, err := loadTrace(ctx, opts.ref, nodes)
if err != nil {
return err
}
srv := jaegerui.NewServer(jaegerui.Config{})
if err := srv.AddTrace(traceID, bytes.NewReader(data)); err != nil {
return err
}
url := "/trace/" + traceID
if opts.compare != "" {
traceIDcomp, data, err := loadTrace(ctx, opts.compare, nodes)
if err != nil {
return errors.Wrapf(err, "failed to load trace for %s", opts.compare)
}
if err := srv.AddTrace(traceIDcomp, bytes.NewReader(data)); err != nil {
return err
}
url = "/trace/" + traceIDcomp + "..." + traceID
}
var term bool
if _, err := console.ConsoleFromFile(os.Stdout); err == nil {
term = true
}
if !term && opts.compare == "" {
fmt.Fprintln(dockerCli.Out(), string(data))
return nil
}
ln, err := net.Listen("tcp", opts.addr)
if err != nil {
return err
}
go func() {
time.Sleep(100 * time.Millisecond)
browser.OpenURL(url)
}()
url = "http://" + ln.Addr().String() + url
fmt.Fprintf(dockerCli.Err(), "Trace available at %s\n", url)
go func() {
<-ctx.Done()
ln.Close()
}()
err = srv.Serve(ln)
if err != nil {
select {
case <-ctx.Done():
return nil
default:
}
}
return err
}
func traceCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
var options traceOptions
cmd := &cobra.Command{
Use: "trace [OPTIONS] [REF]",
Short: "Show the OpenTelemetry trace of a build record",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
options.ref = args[0]
}
options.builder = *rootOpts.Builder
return runTrace(cmd.Context(), dockerCli, options)
},
ValidArgsFunction: completion.Disable,
}
flags := cmd.Flags()
flags.StringVar(&options.addr, "addr", "127.0.0.1:0", "Address to bind the UI server")
flags.StringVar(&options.compare, "compare", "", "Compare with another build reference")
return cmd
}

View File

@@ -115,6 +115,25 @@ func runInspect(ctx context.Context, dockerCli command.Cli, in inspectOptions) e
fmt.Fprintf(w, "\t%s:\t%s\n", k, v) fmt.Fprintf(w, "\t%s:\t%s\n", k, v)
} }
} }
if len(nodes[i].CDIDevices) > 0 {
fmt.Fprintf(w, "Devices:\n")
for _, dev := range nodes[i].CDIDevices {
fmt.Fprintf(w, "\tName:\t%s\n", dev.Name)
if dev.OnDemand {
fmt.Fprintf(w, "\tOn-Demand:\t%v\n", dev.OnDemand)
} else {
fmt.Fprintf(w, "\tAutomatically allowed:\t%v\n", dev.AutoAllow)
}
if len(dev.Annotations) > 0 {
fmt.Fprintf(w, "\tAnnotations:\n")
for k, v := range dev.Annotations {
fmt.Fprintf(w, "\t\t%s:\t%s\n", k, v)
}
}
}
}
for ri, rule := range nodes[i].GCPolicy { for ri, rule := range nodes[i].GCPolicy {
fmt.Fprintf(w, "GC Policy rule#%d:\n", ri) fmt.Fprintf(w, "GC Policy rule#%d:\n", ri)
fmt.Fprintf(w, "\tAll:\t%v\n", rule.All) fmt.Fprintf(w, "\tAll:\t%v\n", rule.All)

View File

@@ -159,6 +159,9 @@ func lsPrint(dockerCli command.Cli, current *store.NodeGroup, builders []*builde
} }
continue continue
} }
if ctx.Format.IsJSON() {
continue
}
for _, n := range b.Nodes() { for _, n := range b.Nodes() {
if n.Err != nil { if n.Err != nil {
if ctx.Format.IsTable() { if ctx.Format.IsTable() {

View File

@@ -75,7 +75,9 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in *controllerapi.Buil
opts.Platforms = platforms opts.Platforms = platforms
dockerConfig := dockerCli.ConfigFile() dockerConfig := dockerCli.ConfigFile()
opts.Session = append(opts.Session, authprovider.NewDockerAuthProvider(dockerConfig, nil)) opts.Session = append(opts.Session, authprovider.NewDockerAuthProvider(authprovider.DockerAuthProviderConfig{
ConfigFile: dockerConfig,
}))
secrets, err := controllerapi.CreateSecrets(in.Secrets) secrets, err := controllerapi.CreateSecrets(in.Secrets)
if err != nil { if err != nil {

View File

@@ -285,19 +285,11 @@ The key takes a list of annotations, in the format of `KEY=VALUE`.
```hcl ```hcl
target "default" { target "default" {
output = ["type=image,name=foo"] output = [{ type = "image", name = "foo" }]
annotations = ["org.opencontainers.image.authors=dvdksn"] annotations = ["org.opencontainers.image.authors=dvdksn"]
} }
``` ```
is the same as
```hcl
target "default" {
output = ["type=image,name=foo,annotation.org.opencontainers.image.authors=dvdksn"]
}
```
By default, the annotation is added to image manifests. You can configure the By default, the annotation is added to image manifests. You can configure the
level of the annotations by adding a prefix to the annotation, containing a level of the annotations by adding a prefix to the annotation, containing a
comma-separated list of all the levels that you want to annotate. The following comma-separated list of all the levels that you want to annotate. The following
@@ -305,7 +297,7 @@ example adds annotations to both the image index and manifests.
```hcl ```hcl
target "default" { target "default" {
output = ["type=image,name=foo"] output = [{ type = "image", name = "foo" }]
annotations = ["index,manifest:org.opencontainers.image.authors=dvdksn"] annotations = ["index,manifest:org.opencontainers.image.authors=dvdksn"]
} }
``` ```
@@ -321,8 +313,13 @@ This attribute accepts the long-form CSV version of attestation parameters.
```hcl ```hcl
target "default" { target "default" {
attest = [ attest = [
"type=provenance,mode=min", {
"type=sbom" type = "provenance",
mode = "max",
},
{
type = "sbom",
}
] ]
} }
``` ```
@@ -338,8 +335,15 @@ This takes a list value, so you can specify multiple cache sources.
```hcl ```hcl
target "app" { target "app" {
cache-from = [ cache-from = [
"type=s3,region=eu-west-1,bucket=mybucket", {
"user/repo:cache", type = "s3",
region = "eu-west-1",
bucket = "mybucket"
},
{
type = "registry",
ref = "user/repo:cache"
}
] ]
} }
``` ```
@@ -355,8 +359,14 @@ This takes a list value, so you can specify multiple cache export targets.
```hcl ```hcl
target "app" { target "app" {
cache-to = [ cache-to = [
"type=s3,region=eu-west-1,bucket=mybucket", {
"type=inline" type = "s3",
region = "eu-west-1",
bucket = "mybucket"
},
{
type = "inline",
}
] ]
} }
``` ```
@@ -863,7 +873,7 @@ The following example configures the target to use a cache-only output,
```hcl ```hcl
target "default" { target "default" {
output = ["type=cacheonly"] output = [{ type = "cacheonly" }]
} }
``` ```
@@ -903,8 +913,8 @@ variable "HOME" {
target "default" { target "default" {
secret = [ secret = [
"type=env,id=KUBECONFIG", { type = "env", id = "KUBECONFIG" },
"type=file,id=aws,src=${HOME}/.aws/credentials" { type = "file", id = "aws", src = "${HOME}/.aws/credentials" },
] ]
} }
``` ```
@@ -948,7 +958,7 @@ This can be useful if you need to access private repositories during a build.
```hcl ```hcl
target "default" { target "default" {
ssh = ["default"] ssh = [{ id = "default" }]
} }
``` ```

View File

@@ -6,12 +6,13 @@ Commands to work on build records
### Subcommands ### Subcommands
| Name | Description | | Name | Description |
|:---------------------------------------|:-------------------------------| |:---------------------------------------|:-----------------------------------------------|
| [`inspect`](buildx_history_inspect.md) | Inspect a build | | [`inspect`](buildx_history_inspect.md) | Inspect a build |
| [`logs`](buildx_history_logs.md) | Print the logs of a build | | [`logs`](buildx_history_logs.md) | Print the logs of a build |
| [`ls`](buildx_history_ls.md) | List build records | | [`ls`](buildx_history_ls.md) | List build records |
| [`open`](buildx_history_open.md) | Open a build in Docker Desktop | | [`open`](buildx_history_open.md) | Open a build in Docker Desktop |
| [`rm`](buildx_history_rm.md) | Remove build records | | [`rm`](buildx_history_rm.md) | Remove build records |
| [`trace`](buildx_history_trace.md) | Show the OpenTelemetry trace of a build record |
### Options ### Options

View File

@@ -13,10 +13,105 @@ Inspect a build
### Options ### Options
| Name | Type | Default | Description | | Name | Type | Default | Description |
|:----------------|:---------|:--------|:-----------------------------------------| |:----------------------|:---------|:---------|:-----------------------------------------|
| `--builder` | `string` | | Override the configured builder instance | | `--builder` | `string` | | Override the configured builder instance |
| `-D`, `--debug` | `bool` | | Enable debug logging | | `-D`, `--debug` | `bool` | | Enable debug logging |
| [`--format`](#format) | `string` | `pretty` | Format the output |
<!---MARKER_GEN_END--> <!---MARKER_GEN_END-->
## Examples
### <a name="format"></a> Format the output (--format)
The formatting options (`--format`) pretty-prints the output to `pretty` (default),
`json` or using a Go template.
```console
$ docker buildx history inspect
Name: buildx (binaries)
Context: .
Dockerfile: Dockerfile
VCS Repository: https://github.com/crazy-max/buildx.git
VCS Revision: f15eaa1ee324ffbbab29605600d27a84cab86361
Target: binaries
Platforms: linux/amd64
Keep Git Dir: true
Started: 2025-02-07 11:56:24
Duration: 1m 1s
Build Steps: 16/16 (25% cached)
Image Resolve Mode: local
Materials:
URI DIGEST
pkg:docker/docker/dockerfile@1 sha256:93bfd3b68c109427185cd78b4779fc82b484b0b7618e36d0f104d4d801e66d25
pkg:docker/golang@1.23-alpine3.21?platform=linux%2Famd64 sha256:2c49857f2295e89b23b28386e57e018a86620a8fede5003900f2d138ba9c4037
pkg:docker/tonistiigi/xx@1.6.1?platform=linux%2Famd64 sha256:923441d7c25f1e2eb5789f82d987693c47b8ed987c4ab3b075d6ed2b5d6779a3
Attachments:
DIGEST PLATFORM TYPE
sha256:217329d2af959d4f02e3a96dcbe62bf100cab1feb8006a047ddfe51a5397f7e3 https://slsa.dev/provenance/v0.2
Print build logs: docker buildx history logs g9808bwrjrlkbhdamxklx660b
```
```console
$ docker buildx history inspect --format json
{
"Name": "buildx (binaries)",
"Ref": "5w7vkqfi0rf59hw4hnmn627r9",
"Context": ".",
"Dockerfile": "Dockerfile",
"VCSRepository": "https://github.com/crazy-max/buildx.git",
"VCSRevision": "f15eaa1ee324ffbbab29605600d27a84cab86361",
"Target": "binaries",
"Platform": [
"linux/amd64"
],
"KeepGitDir": true,
"StartedAt": "2025-02-07T12:01:05.75807272+01:00",
"CompletedAt": "2025-02-07T12:02:07.991778875+01:00",
"Duration": 62233706155,
"Status": "completed",
"NumCompletedSteps": 16,
"NumTotalSteps": 16,
"NumCachedSteps": 4,
"Config": {
"ImageResolveMode": "local"
},
"Materials": [
{
"URI": "pkg:docker/docker/dockerfile@1",
"Digests": [
"sha256:93bfd3b68c109427185cd78b4779fc82b484b0b7618e36d0f104d4d801e66d25"
]
},
{
"URI": "pkg:docker/golang@1.23-alpine3.21?platform=linux%2Famd64",
"Digests": [
"sha256:2c49857f2295e89b23b28386e57e018a86620a8fede5003900f2d138ba9c4037"
]
},
{
"URI": "pkg:docker/tonistiigi/xx@1.6.1?platform=linux%2Famd64",
"Digests": [
"sha256:923441d7c25f1e2eb5789f82d987693c47b8ed987c4ab3b075d6ed2b5d6779a3"
]
}
],
"Attachments": [
{
"Digest": "sha256:450fdd2e6b868fecd69e9891c2c404ba461aa38a47663b4805edeb8d2baf80b1",
"Type": "https://slsa.dev/provenance/v0.2"
}
]
}
```
```console
$ docker buildx history inspect --format "{{.Name}}: {{.VCSRepository}} ({{.VCSRevision}})"
buildx (binaries): https://github.com/crazy-max/buildx.git (f15eaa1ee324ffbbab29605600d27a84cab86361)
```

View File

@@ -0,0 +1,17 @@
# docker buildx history trace
<!---MARKER_GEN_START-->
Show the OpenTelemetry trace of a build record
### Options
| Name | Type | Default | Description |
|:----------------|:---------|:--------------|:-----------------------------------------|
| `--addr` | `string` | `127.0.0.1:0` | Address to bind the UI server |
| `--builder` | `string` | | Override the configured builder instance |
| `--compare` | `string` | | Compare with another build reference |
| `-D`, `--debug` | `bool` | | Enable debug logging |
<!---MARKER_GEN_END-->

View File

@@ -23,7 +23,6 @@ import (
"github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/system" "github.com/docker/docker/api/types/system"
dockerclient "github.com/docker/docker/client"
"github.com/docker/docker/errdefs" "github.com/docker/docker/errdefs"
dockerarchive "github.com/docker/docker/pkg/archive" dockerarchive "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
@@ -70,7 +69,7 @@ func (d *Driver) Bootstrap(ctx context.Context, l progress.Logger) error {
return progress.Wrap("[internal] booting buildkit", l, func(sub progress.SubLogger) error { return progress.Wrap("[internal] booting buildkit", l, func(sub progress.SubLogger) error {
_, err := d.DockerAPI.ContainerInspect(ctx, d.Name) _, err := d.DockerAPI.ContainerInspect(ctx, d.Name)
if err != nil { if err != nil {
if dockerclient.IsErrNotFound(err) { if errdefs.IsNotFound(err) {
return d.create(ctx, sub) return d.create(ctx, sub)
} }
return err return err
@@ -306,7 +305,7 @@ func (d *Driver) start(ctx context.Context) error {
func (d *Driver) Info(ctx context.Context) (*driver.Info, error) { func (d *Driver) Info(ctx context.Context) (*driver.Info, error) {
ctn, err := d.DockerAPI.ContainerInspect(ctx, d.Name) ctn, err := d.DockerAPI.ContainerInspect(ctx, d.Name)
if err != nil { if err != nil {
if dockerclient.IsErrNotFound(err) { if errdefs.IsNotFound(err) {
return &driver.Info{ return &driver.Info{
Status: driver.Inactive, Status: driver.Inactive,
}, nil }, nil

24
go.mod
View File

@@ -17,9 +17,9 @@ require (
github.com/creack/pty v1.1.24 github.com/creack/pty v1.1.24
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
github.com/distribution/reference v0.6.0 github.com/distribution/reference v0.6.0
github.com/docker/cli v27.5.0+incompatible github.com/docker/cli v27.5.1+incompatible
github.com/docker/cli-docs-tool v0.9.0 github.com/docker/cli-docs-tool v0.9.0
github.com/docker/docker v27.5.0+incompatible github.com/docker/docker v27.5.1+incompatible
github.com/docker/go-units v0.5.0 github.com/docker/go-units v0.5.0
github.com/gofrs/flock v0.12.1 github.com/gofrs/flock v0.12.1
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
@@ -29,7 +29,7 @@ require (
github.com/hashicorp/hcl/v2 v2.23.0 github.com/hashicorp/hcl/v2 v2.23.0
github.com/in-toto/in-toto-golang v0.5.0 github.com/in-toto/in-toto-golang v0.5.0
github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/moby/buildkit v0.19.0 github.com/moby/buildkit v0.20.0-rc1
github.com/moby/sys/mountinfo v0.7.2 github.com/moby/sys/mountinfo v0.7.2
github.com/moby/sys/signal v0.7.1 github.com/moby/sys/signal v0.7.1
github.com/morikuni/aec v1.0.0 github.com/morikuni/aec v1.0.0
@@ -46,19 +46,21 @@ require (
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4
github.com/tonistiigi/jaeger-ui-rest v0.0.0-20250211190051-7d4944a45bb6
github.com/zclconf/go-cty v1.16.0 github.com/zclconf/go-cty v1.16.0
go.opentelemetry.io/otel v1.31.0 go.opentelemetry.io/otel v1.31.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.31.0
go.opentelemetry.io/otel/metric v1.31.0 go.opentelemetry.io/otel/metric v1.31.0
go.opentelemetry.io/otel/sdk v1.31.0 go.opentelemetry.io/otel/sdk v1.31.0
go.opentelemetry.io/otel/trace v1.31.0 go.opentelemetry.io/otel/trace v1.31.0
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f
golang.org/x/mod v0.21.0 golang.org/x/mod v0.22.0
golang.org/x/sync v0.10.0 golang.org/x/sync v0.10.0
golang.org/x/sys v0.28.0 golang.org/x/sys v0.29.0
golang.org/x/term v0.27.0 golang.org/x/term v0.27.0
golang.org/x/text v0.21.0 golang.org/x/text v0.21.0
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38
google.golang.org/grpc v1.68.1 google.golang.org/grpc v1.69.4
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1
google.golang.org/protobuf v1.35.2 google.golang.org/protobuf v1.35.2
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
@@ -69,7 +71,7 @@ require (
require ( require (
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d // indirect github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d // indirect
github.com/agext/levenshtein v1.2.3 // indirect github.com/agext/levenshtein v1.2.3 // indirect
github.com/apparentlymart/go-cidr v1.0.1 // indirect github.com/apparentlymart/go-cidr v1.0.1 // indirect
@@ -136,7 +138,7 @@ require (
github.com/moby/sys/sequential v0.6.0 // indirect github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/sys/user v0.3.0 // indirect github.com/moby/sys/user v0.3.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.0 // indirect github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
@@ -172,8 +174,8 @@ require (
golang.org/x/net v0.33.0 // indirect golang.org/x/net v0.33.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/time v0.6.0 // indirect golang.org/x/time v0.6.0 // indirect
golang.org/x/tools v0.25.0 // indirect golang.org/x/tools v0.27.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect

52
go.sum
View File

@@ -2,8 +2,8 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8af
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2 h1:dIScnXFlF784X79oi7MzVT6GWqr/W1uUt0pB5CsDs9M= github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2 h1:dIScnXFlF784X79oi7MzVT6GWqr/W1uUt0pB5CsDs9M=
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2/go.mod h1:gCLVsLfv1egrcZu+GoJATN5ts75F2s62ih/457eWzOw= github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2/go.mod h1:gCLVsLfv1egrcZu+GoJATN5ts75F2s62ih/457eWzOw=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
@@ -79,8 +79,8 @@ github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUo
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
github.com/compose-spec/compose-go/v2 v2.4.7 h1:WNpz5bIbKG+G+w9pfu72B1ZXr+Og9jez8TMEo8ecXPk= github.com/compose-spec/compose-go/v2 v2.4.7 h1:WNpz5bIbKG+G+w9pfu72B1ZXr+Og9jez8TMEo8ecXPk=
github.com/compose-spec/compose-go/v2 v2.4.7/go.mod h1:lFN0DrMxIncJGYAXTfWuajfwj5haBJqrBkarHcnjJKc= github.com/compose-spec/compose-go/v2 v2.4.7/go.mod h1:lFN0DrMxIncJGYAXTfWuajfwj5haBJqrBkarHcnjJKc=
github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0= github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo=
github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0= github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro=
github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
github.com/containerd/containerd/api v1.8.0 h1:hVTNJKR8fMc/2Tiw60ZRijntNMd1U+JVMyTRdsD2bS0= github.com/containerd/containerd/api v1.8.0 h1:hVTNJKR8fMc/2Tiw60ZRijntNMd1U+JVMyTRdsD2bS0=
@@ -122,15 +122,15 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v27.5.0+incompatible h1:aMphQkcGtpHixwwhAXJT1rrK/detk2JIvDaFkLctbGM= github.com/docker/cli v27.5.1+incompatible h1:JB9cieUT9YNiMITtIsguaN55PLOHhBSz3LKVc6cqWaY=
github.com/docker/cli v27.5.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v27.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli-docs-tool v0.9.0 h1:CVwQbE+ZziwlPqrJ7LRyUF6GvCA+6gj7MTCsayaK9t0= github.com/docker/cli-docs-tool v0.9.0 h1:CVwQbE+ZziwlPqrJ7LRyUF6GvCA+6gj7MTCsayaK9t0=
github.com/docker/cli-docs-tool v0.9.0/go.mod h1:ClrwlNW+UioiRyH9GiAOe1o3J/TsY3Tr1ipoypjAUtc= github.com/docker/cli-docs-tool v0.9.0/go.mod h1:ClrwlNW+UioiRyH9GiAOe1o3J/TsY3Tr1ipoypjAUtc=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v27.5.0+incompatible h1:um++2NcQtGRTz5eEgO6aJimo6/JxrTXC941hd05JO6U= github.com/docker/docker v27.5.1+incompatible h1:4PYU5dnBYqRQi0294d1FBECqT9ECWeQAIfE8q4YnPY8=
github.com/docker/docker v27.5.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v27.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0= github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
@@ -297,8 +297,8 @@ github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/z
github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/buildkit v0.19.0 h1:w9G1p7sArvCGNkpWstAqJfRQTXBKukMyMK1bsah1HNo= github.com/moby/buildkit v0.20.0-rc1 h1:aRO8ApLVz7EuzCVPUFmXiU5nwQkYDUPty9InUp0HJes=
github.com/moby/buildkit v0.19.0/go.mod h1:WiHBFTgWV8eB1AmPxIWsAlKjUACAwm3X/14xOV4VWew= github.com/moby/buildkit v0.20.0-rc1/go.mod h1:mtRqVBkksyvFm+ljU1u+cigDh36TdFvlEGfz/XbYTiI=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
@@ -317,8 +317,8 @@ github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -447,6 +447,8 @@ github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a h1:EfGw4G0x/8qXW
github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a/go.mod h1:Dl/9oEjK7IqnjAm21Okx/XIxUCFJzvh+XdVHUlBwXTw= github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a/go.mod h1:Dl/9oEjK7IqnjAm21Okx/XIxUCFJzvh+XdVHUlBwXTw=
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 h1:7I5c2Ig/5FgqkYOh/N87NzoyI9U15qUPXhDD8uCupv8= github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 h1:7I5c2Ig/5FgqkYOh/N87NzoyI9U15qUPXhDD8uCupv8=
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4/go.mod h1:278M4p8WsNh3n4a1eqiFcV2FGk7wE5fwUpUom9mK9lE= github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4/go.mod h1:278M4p8WsNh3n4a1eqiFcV2FGk7wE5fwUpUom9mK9lE=
github.com/tonistiigi/jaeger-ui-rest v0.0.0-20250211190051-7d4944a45bb6 h1:RT/a0RvdX84iwtOrUK45+wjcNpaG+hS7n7XFYqj4axg=
github.com/tonistiigi/jaeger-ui-rest v0.0.0-20250211190051-7d4944a45bb6/go.mod h1:3Ez1Paeg+0Ghu3KwpEGC1HgZ4CHDlg+Ez/5Baeomk54=
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea h1:SXhTLE6pb6eld/v/cCndK0AMpt1wiVFb/YYmqB3/QG0= github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea h1:SXhTLE6pb6eld/v/cCndK0AMpt1wiVFb/YYmqB3/QG0=
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea/go.mod h1:WPnis/6cRcDZSUvVmezrxJPkiO87ThFYsoUiMwWNDJk= github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea/go.mod h1:WPnis/6cRcDZSUvVmezrxJPkiO87ThFYsoUiMwWNDJk=
github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab h1:H6aJ0yKQ0gF49Qb2z5hI1UHxSQt4JMyxebFR15KnApw= github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab h1:H6aJ0yKQ0gF49Qb2z5hI1UHxSQt4JMyxebFR15KnApw=
@@ -490,6 +492,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0 h1:FFeLy
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0/go.mod h1:TMu73/k1CP8nBUpDLc71Wj/Kf7ZS9FK5b53VapRsP9o= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0/go.mod h1:TMu73/k1CP8nBUpDLc71Wj/Kf7ZS9FK5b53VapRsP9o=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 h1:lUsI2TYsQw2r1IASwoROaCnjdj2cvC2+Jbxvk6nHnWU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 h1:lUsI2TYsQw2r1IASwoROaCnjdj2cvC2+Jbxvk6nHnWU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0/go.mod h1:2HpZxxQurfGxJlJDblybejHB6RX6pmExPNe517hREw4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0/go.mod h1:2HpZxxQurfGxJlJDblybejHB6RX6pmExPNe517hREw4=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.31.0 h1:UGZ1QwZWY67Z6BmckTU+9Rxn04m2bD3gD6Mk0OIOCPk=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.31.0/go.mod h1:fcwWuDuaObkkChiDlhEpSq9+X1C0omv+s5mBtToAQ64=
go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
@@ -512,12 +516,12 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -549,8 +553,8 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
@@ -565,20 +569,20 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg= google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 h1:2oV8dfuIkM1Ti7DwXc0BJfnwr9csz4TDXI9EmiI+Rbw=
google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M= google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38/go.mod h1:vuAjtvlwkDKF6L1GQ0SokiRLCGFfeBUXWr/aFFkHACc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI= google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0= google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw= google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=

View File

@@ -7,7 +7,7 @@ ARG XX_VERSION=1.6.1
ARG GOLANGCI_LINT_VERSION=1.62.0 ARG GOLANGCI_LINT_VERSION=1.62.0
ARG GOPLS_VERSION=v0.26.0 ARG GOPLS_VERSION=v0.26.0
# disabled: deprecated unusedvariable simplifyrange # disabled: deprecated unusedvariable simplifyrange
ARG GOPLS_ANALYZERS="embeddirective fillreturns infertypeargs nonewvars norangeoverfunc noresultvalues simplifycompositelit simplifyslice undeclaredname unusedparams useany" ARG GOPLS_ANALYZERS="embeddirective fillreturns infertypeargs nonewvars noresultvalues simplifycompositelit simplifyslice undeclaredname unusedparams useany"
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx

View File

@@ -2,6 +2,8 @@
set -eu -o pipefail set -eu -o pipefail
: "${GITHUB_ACTIONS=}"
: "${BUILDX_CMD=docker buildx}" : "${BUILDX_CMD=docker buildx}"
: "${TEST_COVERAGE=}" : "${TEST_COVERAGE=}"
@@ -37,7 +39,15 @@ if [ "$TEST_COVERAGE" = "1" ]; then
export GO_TEST_COVERPROFILE="/testreports/coverage-report$TEST_REPORT_SUFFIX.txt" export GO_TEST_COVERPROFILE="/testreports/coverage-report$TEST_REPORT_SUFFIX.txt"
fi fi
cid=$(docker create --rm --privileged \ dockerConfigMount=""
if [ "$GITHUB_ACTIONS" = "true" ]; then
dockerConfigPath="$HOME/.docker/config.json"
if [ -f "$dockerConfigPath" ]; then
dockerConfigMount="-v $dockerConfigPath:/root/.docker/config.json:ro"
fi
fi
cid=$(docker create --rm --privileged $dockerConfigMount \
-v /tmp $testReportsVol \ -v /tmp $testReportsVol \
--volumes-from=$cacheVolume \ --volumes-from=$cacheVolume \
-e GITHUB_REF \ -e GITHUB_REF \

View File

@@ -66,7 +66,7 @@ func (cm *ReloadCmd) Exec(ctx context.Context, args []string) error {
if err != nil { if err != nil {
var be *controllererrors.BuildError var be *controllererrors.BuildError
if errors.As(err, &be) { if errors.As(err, &be) {
ref = be.Ref ref = be.SessionID
resultUpdated = true resultUpdated = true
} else { } else {
fmt.Printf("failed to reload: %v\n", err) fmt.Printf("failed to reload: %v\n", err)

View File

@@ -22,18 +22,19 @@ func (e *Attests) FromCtyValue(in cty.Value, p cty.Path) error {
return p.NewErrorf("%s", convert.MismatchMessage(got, want)) return p.NewErrorf("%s", convert.MismatchMessage(got, want))
} }
func (e *Attests) fromCtyValue(in cty.Value, p cty.Path) error { func (e *Attests) fromCtyValue(in cty.Value, p cty.Path) (retErr error) {
*e = make([]*Attest, 0, in.LengthInt()) *e = make([]*Attest, 0, in.LengthInt())
for elem := in.ElementIterator(); elem.Next(); {
_, value := elem.Element()
yield := func(value cty.Value) bool {
entry := &Attest{} entry := &Attest{}
if err := entry.FromCtyValue(value, p); err != nil { if retErr = entry.FromCtyValue(value, p); retErr != nil {
return err return false
} }
*e = append(*e, entry) *e = append(*e, entry)
return true
} }
return nil eachElement(in)(yield)
return retErr
} }
func (e Attests) ToCtyValue() cty.Value { func (e Attests) ToCtyValue() cty.Value {
@@ -64,6 +65,10 @@ func (e *Attest) FromCtyValue(in cty.Value, p cty.Path) error {
e.Attrs = map[string]string{} e.Attrs = map[string]string{}
for it := conv.ElementIterator(); it.Next(); { for it := conv.ElementIterator(); it.Next(); {
k, v := it.Element() k, v := it.Element()
if !v.IsKnown() {
continue
}
switch key := k.AsString(); key { switch key := k.AsString(); key {
case "type": case "type":
e.Type = v.AsString() e.Type = v.AsString()

View File

@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"maps" "maps"
"os" "os"
"strconv"
"strings" "strings"
awsconfig "github.com/aws/aws-sdk-go-v2/config" awsconfig "github.com/aws/aws-sdk-go-v2/config"
@@ -204,17 +205,31 @@ func addGithubToken(ci *controllerapi.CacheOptionsEntry) {
if ci.Type != "gha" { if ci.Type != "gha" {
return return
} }
version, ok := ci.Attrs["version"]
if !ok {
if v, ok := os.LookupEnv("ACTIONS_CACHE_SERVICE_V2"); ok {
if b, err := strconv.ParseBool(v); err == nil && b {
version = "2"
}
}
}
if _, ok := ci.Attrs["token"]; !ok { if _, ok := ci.Attrs["token"]; !ok {
if v, ok := os.LookupEnv("ACTIONS_RUNTIME_TOKEN"); ok { if v, ok := os.LookupEnv("ACTIONS_RUNTIME_TOKEN"); ok {
ci.Attrs["token"] = v ci.Attrs["token"] = v
} }
} }
if _, ok := ci.Attrs["url"]; !ok { if _, ok := ci.Attrs["url"]; !ok {
if version == "2" {
if v, ok := os.LookupEnv("ACTIONS_RESULTS_URL"); ok {
ci.Attrs["url_v2"] = v
}
} else {
if v, ok := os.LookupEnv("ACTIONS_CACHE_URL"); ok { if v, ok := os.LookupEnv("ACTIONS_CACHE_URL"); ok {
ci.Attrs["url"] = v ci.Attrs["url"] = v
} }
} }
} }
}
func addAwsCredentials(ci *controllerapi.CacheOptionsEntry) { func addAwsCredentials(ci *controllerapi.CacheOptionsEntry) {
if ci.Type != "s3" { if ci.Type != "s3" {

View File

@@ -21,32 +21,30 @@ func (o *CacheOptions) FromCtyValue(in cty.Value, p cty.Path) error {
return p.NewErrorf("%s", convert.MismatchMessage(got, want)) return p.NewErrorf("%s", convert.MismatchMessage(got, want))
} }
func (o *CacheOptions) fromCtyValue(in cty.Value, p cty.Path) error { func (o *CacheOptions) fromCtyValue(in cty.Value, p cty.Path) (retErr error) {
*o = make([]*CacheOptionsEntry, 0, in.LengthInt()) *o = make([]*CacheOptionsEntry, 0, in.LengthInt())
for elem := in.ElementIterator(); elem.Next(); {
_, value := elem.Element()
if isEmpty(value) {
continue
}
yield := func(value cty.Value) bool {
// Special handling for a string type to handle ref only format. // Special handling for a string type to handle ref only format.
if value.Type() == cty.String { if value.Type() == cty.String {
entries, err := ParseCacheEntry([]string{value.AsString()}) var entries CacheOptions
if err != nil { entries, retErr = ParseCacheEntry([]string{value.AsString()})
return err if retErr != nil {
return false
} }
*o = append(*o, entries...) *o = append(*o, entries...)
continue return true
} }
entry := &CacheOptionsEntry{} entry := &CacheOptionsEntry{}
if err := entry.FromCtyValue(value, p); err != nil { if retErr = entry.FromCtyValue(value, p); retErr != nil {
return err return false
} }
*o = append(*o, entry) *o = append(*o, entry)
return true
} }
return nil eachElement(in)(yield)
return retErr
} }
func (o CacheOptions) ToCtyValue() cty.Value { func (o CacheOptions) ToCtyValue() cty.Value {

View File

@@ -21,22 +21,19 @@ func (e *Exports) FromCtyValue(in cty.Value, p cty.Path) error {
return p.NewErrorf("%s", convert.MismatchMessage(got, want)) return p.NewErrorf("%s", convert.MismatchMessage(got, want))
} }
func (e *Exports) fromCtyValue(in cty.Value, p cty.Path) error { func (e *Exports) fromCtyValue(in cty.Value, p cty.Path) (retErr error) {
*e = make([]*ExportEntry, 0, in.LengthInt()) *e = make([]*ExportEntry, 0, in.LengthInt())
for elem := in.ElementIterator(); elem.Next(); {
_, value := elem.Element()
if isEmpty(value) {
continue
}
yield := func(value cty.Value) bool {
entry := &ExportEntry{} entry := &ExportEntry{}
if err := entry.FromCtyValue(value, p); err != nil { if retErr = entry.FromCtyValue(value, p); retErr != nil {
return err return false
} }
*e = append(*e, entry) *e = append(*e, entry)
return true
} }
return nil eachElement(in)(yield)
return retErr
} }
func (e Exports) ToCtyValue() cty.Value { func (e Exports) ToCtyValue() cty.Value {

View File

@@ -28,22 +28,19 @@ func (s *Secrets) FromCtyValue(in cty.Value, p cty.Path) error {
return p.NewErrorf("%s", convert.MismatchMessage(got, want)) return p.NewErrorf("%s", convert.MismatchMessage(got, want))
} }
func (s *Secrets) fromCtyValue(in cty.Value, p cty.Path) error { func (s *Secrets) fromCtyValue(in cty.Value, p cty.Path) (retErr error) {
*s = make([]*Secret, 0, in.LengthInt()) *s = make([]*Secret, 0, in.LengthInt())
for elem := in.ElementIterator(); elem.Next(); {
_, value := elem.Element()
if isEmpty(value) {
continue
}
yield := func(value cty.Value) bool {
entry := &Secret{} entry := &Secret{}
if err := entry.FromCtyValue(value, p); err != nil { if retErr = entry.FromCtyValue(value, p); retErr != nil {
return err return false
} }
*s = append(*s, entry) *s = append(*s, entry)
return true
} }
return nil eachElement(in)(yield)
return retErr
} }
func (s Secrets) ToCtyValue() cty.Value { func (s Secrets) ToCtyValue() cty.Value {
@@ -71,13 +68,13 @@ func (e *Secret) FromCtyValue(in cty.Value, p cty.Path) error {
return err return err
} }
if id := conv.GetAttr("id"); !id.IsNull() { if id := conv.GetAttr("id"); !id.IsNull() && id.IsKnown() {
e.ID = id.AsString() e.ID = id.AsString()
} }
if src := conv.GetAttr("src"); !src.IsNull() { if src := conv.GetAttr("src"); !src.IsNull() && src.IsKnown() {
e.FilePath = src.AsString() e.FilePath = src.AsString()
} }
if env := conv.GetAttr("env"); !env.IsNull() { if env := conv.GetAttr("env"); !env.IsNull() && env.IsKnown() {
e.Env = env.AsString() e.Env = env.AsString()
} }
return nil return nil

View File

@@ -28,22 +28,19 @@ func (s *SSHKeys) FromCtyValue(in cty.Value, p cty.Path) error {
return p.NewErrorf("%s", convert.MismatchMessage(got, want)) return p.NewErrorf("%s", convert.MismatchMessage(got, want))
} }
func (s *SSHKeys) fromCtyValue(in cty.Value, p cty.Path) error { func (s *SSHKeys) fromCtyValue(in cty.Value, p cty.Path) (retErr error) {
*s = make([]*SSH, 0, in.LengthInt()) *s = make([]*SSH, 0, in.LengthInt())
for elem := in.ElementIterator(); elem.Next(); {
_, value := elem.Element()
if isEmpty(value) {
continue
}
yield := func(value cty.Value) bool {
entry := &SSH{} entry := &SSH{}
if err := entry.FromCtyValue(value, p); err != nil { if retErr = entry.FromCtyValue(value, p); retErr != nil {
return err return false
} }
*s = append(*s, entry) *s = append(*s, entry)
return true
} }
return nil eachElement(in)(yield)
return retErr
} }
func (s SSHKeys) ToCtyValue() cty.Value { func (s SSHKeys) ToCtyValue() cty.Value {
@@ -71,10 +68,10 @@ func (e *SSH) FromCtyValue(in cty.Value, p cty.Path) error {
return err return err
} }
if id := conv.GetAttr("id"); !id.IsNull() { if id := conv.GetAttr("id"); !id.IsNull() && id.IsKnown() {
e.ID = id.AsString() e.ID = id.AsString()
} }
if paths := conv.GetAttr("paths"); !paths.IsNull() { if paths := conv.GetAttr("paths"); !paths.IsNull() && paths.IsKnown() {
if err := gocty.FromCtyValue(paths, &e.Paths); err != nil { if err := gocty.FromCtyValue(paths, &e.Paths); err != nil {
return err return err
} }

View File

@@ -34,7 +34,7 @@ func removeDupes[E comparable[E]](s []E) []E {
} }
func getAndDelete(m map[string]cty.Value, attr string, gv interface{}) error { func getAndDelete(m map[string]cty.Value, attr string, gv interface{}) error {
if v, ok := m[attr]; ok { if v, ok := m[attr]; ok && v.IsKnown() {
delete(m, attr) delete(m, attr)
return gocty.FromCtyValue(v, gv) return gocty.FromCtyValue(v, gv)
} }
@@ -44,11 +44,33 @@ func getAndDelete(m map[string]cty.Value, attr string, gv interface{}) error {
func asMap(m map[string]cty.Value) map[string]string { func asMap(m map[string]cty.Value) map[string]string {
out := make(map[string]string, len(m)) out := make(map[string]string, len(m))
for k, v := range m { for k, v := range m {
if v.IsKnown() {
out[k] = v.AsString() out[k] = v.AsString()
} }
}
return out return out
} }
func isEmpty(v cty.Value) bool { func isEmptyOrUnknown(v cty.Value) bool {
return v.Type() == cty.String && v.AsString() == "" return !v.IsKnown() || (v.Type() == cty.String && v.AsString() == "")
}
// Seq is a temporary definition of iter.Seq until we are able to migrate
// to using go1.23 as our minimum version. This can be removed when go1.24
// is released and usages can be changed to use rangefunc.
type Seq[V any] func(yield func(V) bool)
func eachElement(in cty.Value) Seq[cty.Value] {
return func(yield func(v cty.Value) bool) {
for elem := in.ElementIterator(); elem.Next(); {
_, value := elem.Element()
if isEmptyOrUnknown(value) {
continue
}
if !yield(value) {
return
}
}
}
} }

View File

@@ -3,12 +3,12 @@ package dockerutil
import ( import (
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/context/docker" "github.com/docker/cli/cli/context/docker"
"github.com/docker/docker/client" dockerclient "github.com/docker/docker/client"
) )
// ClientAPI represents an active docker API object. // ClientAPI represents an active docker API object.
type ClientAPI struct { type ClientAPI struct {
client.APIClient dockerclient.APIClient
} }
func NewClientAPI(cli command.Cli, ep string) (*ClientAPI, error) { func NewClientAPI(cli command.Cli, ep string) (*ClientAPI, error) {
@@ -36,7 +36,7 @@ func NewClientAPI(cli command.Cli, ep string) (*ClientAPI, error) {
return nil, err return nil, err
} }
ca.APIClient, err = client.NewClientWithOpts(clientOpts...) ca.APIClient, err = dockerclient.NewClientWithOpts(clientOpts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -7,7 +7,7 @@ import (
"github.com/docker/buildx/util/progress" "github.com/docker/buildx/util/progress"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/docker/client" dockerclient "github.com/docker/docker/client"
) )
// Client represents an active docker object. // Client represents an active docker object.
@@ -24,7 +24,7 @@ func NewClient(cli command.Cli) *Client {
} }
// API returns a new docker API client. // API returns a new docker API client.
func (c *Client) API(name string) (client.APIClient, error) { func (c *Client) API(name string) (dockerclient.APIClient, error) {
if name == "" { if name == "" {
name = c.cli.CurrentContext() name = c.cli.CurrentContext()
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

45
util/otelutil/jaeger.go Normal file
View File

@@ -0,0 +1,45 @@
package otelutil
import (
"fmt"
"github.com/docker/buildx/util/otelutil/jaeger"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk/resource"
)
type JaegerData struct {
Data []jaeger.Trace `json:"data"`
}
// JaegerData return Jaeger data compatible with ui import feature.
// https://github.com/jaegertracing/jaeger-ui/issues/381#issuecomment-494150826
func (s Spans) JaegerData() JaegerData {
roSpans := s.ReadOnlySpans()
// fetch default service.name from default resource for backup
var defaultServiceName string
defaultResource := resource.Default()
if value, exists := defaultResource.Set().Value(attribute.Key("service.name")); exists {
defaultServiceName = value.AsString()
}
data := jaeger.Trace{
TraceID: jaeger.TraceID(roSpans[0].SpanContext().TraceID().String()),
Processes: make(map[jaeger.ProcessID]jaeger.Process),
Spans: []jaeger.Span{},
}
for i := range roSpans {
ss := roSpans[i]
pid := jaeger.ProcessID(fmt.Sprintf("p%d", i))
data.Processes[pid] = jaeger.ResourceToProcess(ss.Resource(), defaultServiceName)
span := jaeger.ConvertSpan(ss)
span.Process = nil
span.ProcessID = pid
data.Spans = append(data.Spans, span)
}
return JaegerData{
Data: []jaeger.Trace{data},
}
}

View File

@@ -0,0 +1,224 @@
package jaeger
import (
"encoding/json"
"time"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/sdk/resource"
tracesdk "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
)
const (
keyInstrumentationLibraryName = "otel.library.name"
keyInstrumentationLibraryVersion = "otel.library.version"
keyError = "error"
keySpanKind = "span.kind"
keyStatusCode = "otel.status_code"
keyStatusMessage = "otel.status_description"
keyDroppedAttributeCount = "otel.event.dropped_attributes_count"
keyEventName = "event"
)
func ResourceToProcess(res *resource.Resource, defaultServiceName string) Process {
var process Process
var serviceName attribute.KeyValue
if res != nil {
for iter := res.Iter(); iter.Next(); {
if iter.Attribute().Key == attribute.Key("service.name") {
serviceName = iter.Attribute()
// Don't convert service.name into tag.
continue
}
if tag := keyValueToJaegerTag(iter.Attribute()); tag != nil {
process.Tags = append(process.Tags, *tag)
}
}
}
// If no service.name is contained in a Span's Resource,
// that field MUST be populated from the default Resource.
if serviceName.Value.AsString() == "" {
serviceName = attribute.Key("service.version").String(defaultServiceName)
}
process.ServiceName = serviceName.Value.AsString()
return process
}
func ConvertSpan(ss tracesdk.ReadOnlySpan) Span {
attr := ss.Attributes()
tags := make([]KeyValue, 0, len(attr))
for _, kv := range attr {
tag := keyValueToJaegerTag(kv)
if tag != nil {
tags = append(tags, *tag)
}
}
if is := ss.InstrumentationScope(); is.Name != "" {
tags = append(tags, getStringTag(keyInstrumentationLibraryName, is.Name))
if is.Version != "" {
tags = append(tags, getStringTag(keyInstrumentationLibraryVersion, is.Version))
}
}
if ss.SpanKind() != trace.SpanKindInternal {
tags = append(tags,
getStringTag(keySpanKind, ss.SpanKind().String()),
)
}
if ss.Status().Code != codes.Unset {
switch ss.Status().Code {
case codes.Ok:
tags = append(tags, getStringTag(keyStatusCode, "OK"))
case codes.Error:
tags = append(tags, getBoolTag(keyError, true))
tags = append(tags, getStringTag(keyStatusCode, "ERROR"))
}
if ss.Status().Description != "" {
tags = append(tags, getStringTag(keyStatusMessage, ss.Status().Description))
}
}
var logs []Log
for _, a := range ss.Events() {
nTags := len(a.Attributes)
if a.Name != "" {
nTags++
}
if a.DroppedAttributeCount != 0 {
nTags++
}
fields := make([]KeyValue, 0, nTags)
if a.Name != "" {
// If an event contains an attribute with the same key, it needs
// to be given precedence and overwrite this.
fields = append(fields, getStringTag(keyEventName, a.Name))
}
for _, kv := range a.Attributes {
tag := keyValueToJaegerTag(kv)
if tag != nil {
fields = append(fields, *tag)
}
}
if a.DroppedAttributeCount != 0 {
fields = append(fields, getInt64Tag(keyDroppedAttributeCount, int64(a.DroppedAttributeCount)))
}
logs = append(logs, Log{
Timestamp: timeAsEpochMicroseconds(a.Time),
Fields: fields,
})
}
var refs []Reference
for _, link := range ss.Links() {
refs = append(refs, Reference{
RefType: FollowsFrom,
TraceID: TraceID(link.SpanContext.TraceID().String()),
SpanID: SpanID(link.SpanContext.SpanID().String()),
})
}
refs = append(refs, Reference{
RefType: ChildOf,
TraceID: TraceID(ss.Parent().TraceID().String()),
SpanID: SpanID(ss.Parent().SpanID().String()),
})
return Span{
TraceID: TraceID(ss.SpanContext().TraceID().String()),
SpanID: SpanID(ss.SpanContext().SpanID().String()),
Flags: uint32(ss.SpanContext().TraceFlags()),
OperationName: ss.Name(),
References: refs,
StartTime: timeAsEpochMicroseconds(ss.StartTime()),
Duration: durationAsMicroseconds(ss.EndTime().Sub(ss.StartTime())),
Tags: tags,
Logs: logs,
}
}
func keyValueToJaegerTag(keyValue attribute.KeyValue) *KeyValue {
var tag *KeyValue
switch keyValue.Value.Type() {
case attribute.STRING:
s := keyValue.Value.AsString()
tag = &KeyValue{
Key: string(keyValue.Key),
Type: StringType,
Value: s,
}
case attribute.BOOL:
b := keyValue.Value.AsBool()
tag = &KeyValue{
Key: string(keyValue.Key),
Type: BoolType,
Value: b,
}
case attribute.INT64:
i := keyValue.Value.AsInt64()
tag = &KeyValue{
Key: string(keyValue.Key),
Type: Int64Type,
Value: i,
}
case attribute.FLOAT64:
f := keyValue.Value.AsFloat64()
tag = &KeyValue{
Key: string(keyValue.Key),
Type: Float64Type,
Value: f,
}
case attribute.BOOLSLICE,
attribute.INT64SLICE,
attribute.FLOAT64SLICE,
attribute.STRINGSLICE:
data, _ := json.Marshal(keyValue.Value.AsInterface())
a := (string)(data)
tag = &KeyValue{
Key: string(keyValue.Key),
Type: StringType,
Value: a,
}
}
return tag
}
func getInt64Tag(k string, i int64) KeyValue {
return KeyValue{
Key: k,
Type: Int64Type,
Value: i,
}
}
func getStringTag(k, s string) KeyValue {
return KeyValue{
Key: k,
Type: StringType,
Value: s,
}
}
func getBoolTag(k string, b bool) KeyValue {
return KeyValue{
Key: k,
Type: BoolType,
Value: b,
}
}
// timeAsEpochMicroseconds converts time.Time to microseconds since epoch,
// which is the format the StartTime field is stored in the Span.
func timeAsEpochMicroseconds(t time.Time) uint64 {
return uint64(t.UnixNano() / 1000)
}
// durationAsMicroseconds converts time.Duration to microseconds,
// which is the format the Duration field is stored in the Span.
func durationAsMicroseconds(d time.Duration) uint64 {
return uint64(d.Nanoseconds() / 1000)
}

View File

@@ -0,0 +1,102 @@
package jaeger
// ReferenceType is the reference type of one span to another
type ReferenceType string
// TraceID is the shared trace ID of all spans in the trace.
type TraceID string
// SpanID is the id of a span
type SpanID string
// ProcessID is a hashed value of the Process struct that is unique within the trace.
type ProcessID string
// ValueType is the type of a value stored in KeyValue struct.
type ValueType string
const (
// ChildOf means a span is the child of another span
ChildOf ReferenceType = "CHILD_OF"
// FollowsFrom means a span follows from another span
FollowsFrom ReferenceType = "FOLLOWS_FROM"
// StringType indicates a string value stored in KeyValue
StringType ValueType = "string"
// BoolType indicates a Boolean value stored in KeyValue
BoolType ValueType = "bool"
// Int64Type indicates a 64bit signed integer value stored in KeyValue
Int64Type ValueType = "int64"
// Float64Type indicates a 64bit float value stored in KeyValue
Float64Type ValueType = "float64"
// BinaryType indicates an arbitrary byte array stored in KeyValue
BinaryType ValueType = "binary"
)
// Trace is a list of spans
type Trace struct {
TraceID TraceID `json:"traceID"`
Spans []Span `json:"spans"`
Processes map[ProcessID]Process `json:"processes"`
Warnings []string `json:"warnings"`
}
// Span is a span denoting a piece of work in some infrastructure
// When converting to UI model, ParentSpanID and Process should be dereferenced into
// References and ProcessID, respectively.
// When converting to ES model, ProcessID and Warnings should be omitted. Even if
// included, ES with dynamic settings off will automatically ignore unneeded fields.
type Span struct {
TraceID TraceID `json:"traceID"`
SpanID SpanID `json:"spanID"`
ParentSpanID SpanID `json:"parentSpanID,omitempty"` // deprecated
Flags uint32 `json:"flags,omitempty"`
OperationName string `json:"operationName"`
References []Reference `json:"references"`
StartTime uint64 `json:"startTime"` // microseconds since Unix epoch
Duration uint64 `json:"duration"` // microseconds
Tags []KeyValue `json:"tags"`
Logs []Log `json:"logs"`
ProcessID ProcessID `json:"processID,omitempty"`
Process *Process `json:"process,omitempty"`
Warnings []string `json:"warnings"`
}
// Reference is a reference from one span to another
type Reference struct {
RefType ReferenceType `json:"refType"`
TraceID TraceID `json:"traceID"`
SpanID SpanID `json:"spanID"`
}
// Process is the process emitting a set of spans
type Process struct {
ServiceName string `json:"serviceName"`
Tags []KeyValue `json:"tags"`
}
// Log is a log emitted in a span
type Log struct {
Timestamp uint64 `json:"timestamp"`
Fields []KeyValue `json:"fields"`
}
// KeyValue is a key-value pair with typed value.
type KeyValue struct {
Key string `json:"key"`
Type ValueType `json:"type,omitempty"`
Value interface{} `json:"value"`
}
// DependencyLink shows dependencies between services
type DependencyLink struct {
Parent string `json:"parent"`
Child string `json:"child"`
CallCount uint64 `json:"callCount"`
}
// Operation defines the data in the operation response when query operation by service and span kind
type Operation struct {
Name string `json:"name"`
SpanKind string `json:"spanKind"`
}

View File

@@ -0,0 +1,27 @@
package otelutil
import (
"bytes"
"encoding/json"
"os"
"testing"
"github.com/stretchr/testify/require"
)
const jaegerFixture = "./fixtures/jaeger.json"
func TestJaegerData(t *testing.T) {
dt, err := os.ReadFile(bktracesFixture)
require.NoError(t, err)
spanStubs, err := ParseSpanStubs(bytes.NewReader(dt))
require.NoError(t, err)
trace := spanStubs.JaegerData()
dtJaegerTrace, err := json.MarshalIndent(trace, "", " ")
require.NoError(t, err)
dtJaeger, err := os.ReadFile(jaegerFixture)
require.NoError(t, err)
require.Equal(t, string(dtJaeger), string(dtJaegerTrace))
}

491
util/otelutil/span.go Normal file
View File

@@ -0,0 +1,491 @@
package otelutil
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"reflect"
"time"
"github.com/pkg/errors"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk/instrumentation"
"go.opentelemetry.io/otel/sdk/resource"
tracesdk "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
)
// Span is a type similar to otel's SpanStub, but with the correct types needed
// for handle marshaling and unmarshalling.
type Span struct {
// Name is the name of a specific span
Name string
// SpanContext is the unique SpanContext that identifies the span
SpanContext trace.SpanContext
// Parten is the unique SpanContext that identifies the parent of the span.
// If the span has no parent, this span context will be invalid.
Parent trace.SpanContext
// SpanKind is the role the span plays in a Trace
SpanKind trace.SpanKind
// StartTime is the time the span started recording
StartTime time.Time
// EndTime returns the time the span stopped recording
EndTime time.Time
// Attributes are the defining attributes of a span
Attributes []attribute.KeyValue
// Events are all the events that occurred within the span
Events []tracesdk.Event
// Links are all the links the span has to other spans
Links []tracesdk.Link
// Status is that span status
Status tracesdk.Status
// DroppedAttributes is the number of attributes dropped by the span due to
// a limit being reached
DroppedAttributes int
// DroppedEvents is the number of attributes dropped by the span due to a
// limit being reached
DroppedEvents int
// DroppedLinks is the number of links dropped by the span due to a limit
// being reached
DroppedLinks int
// ChildSpanCount is the count of spans that consider the span a direct
// parent
ChildSpanCount int
// Resource is the information about the entity that produced the span
// We have to change this type from the otel type to make this struct
// marshallable
Resource []attribute.KeyValue
// InstrumentationLibrary is information about the library that produced
// the span
//nolint:staticcheck
InstrumentationLibrary instrumentation.Library
}
type Spans []Span
// Len return the length of the Spans.
func (s Spans) Len() int {
return len(s)
}
// ReadOnlySpans return a list of tracesdk.ReadOnlySpan from span stubs.
func (s Spans) ReadOnlySpans() []tracesdk.ReadOnlySpan {
roSpans := make([]tracesdk.ReadOnlySpan, len(s))
for i := range s {
roSpans[i] = s[i].Snapshot()
}
return roSpans
}
// ParseSpanStubs parses BuildKit trace data into a list of SpanStubs.
func ParseSpanStubs(rdr io.Reader) (Spans, error) {
var spanStubs []Span
decoder := json.NewDecoder(rdr)
for {
var span Span
if err := decoder.Decode(&span); err == io.EOF {
break
} else if err != nil {
return nil, errors.Wrapf(err, "error decoding JSON")
}
spanStubs = append(spanStubs, span)
}
return spanStubs, nil
}
// spanData is data that we need to unmarshal in custom ways.
type spanData struct {
Name string
SpanContext spanContext
Parent spanContext
SpanKind trace.SpanKind
StartTime time.Time
EndTime time.Time
Attributes []keyValue
Events []event
Links []link
Status tracesdk.Status
DroppedAttributes int
DroppedEvents int
DroppedLinks int
ChildSpanCount int
Resource []keyValue // change this type from the otel type to make this struct marshallable
//nolint:staticcheck
InstrumentationLibrary instrumentation.Library
}
// spanContext is a custom type used to unmarshal otel SpanContext correctly.
type spanContext struct {
TraceID string
SpanID string
TraceFlags string
TraceState string // TODO: implement, currently dropped
Remote bool
}
// event is a custom type used to unmarshal otel Event correctly.
type event struct {
Name string
Attributes []keyValue
DroppedAttributeCount int
Time time.Time
}
// link is a custom type used to unmarshal otel Link correctly.
type link struct {
SpanContext spanContext
Attributes []keyValue
DroppedAttributeCount int
}
// keyValue is a custom type used to unmarshal otel KeyValue correctly.
type keyValue struct {
Key string
Value value
}
// value is a custom type used to unmarshal otel Value correctly.
type value struct {
Type string
Value interface{}
}
// UnmarshalJSON implements json.Unmarshaler for Span which allows correctly
// retrieving attribute.KeyValue values.
func (s *Span) UnmarshalJSON(data []byte) error {
var sd spanData
if err := json.NewDecoder(bytes.NewReader(data)).Decode(&sd); err != nil {
return errors.Wrap(err, "unable to decode to spanData")
}
s.Name = sd.Name
s.SpanKind = sd.SpanKind
s.StartTime = sd.StartTime
s.EndTime = sd.EndTime
s.Status = sd.Status
s.DroppedAttributes = sd.DroppedAttributes
s.DroppedEvents = sd.DroppedEvents
s.DroppedLinks = sd.DroppedLinks
s.ChildSpanCount = sd.ChildSpanCount
s.InstrumentationLibrary = sd.InstrumentationLibrary
spanCtx, err := sd.SpanContext.asTraceSpanContext()
if err != nil {
return errors.Wrap(err, "unable to decode spanCtx")
}
s.SpanContext = spanCtx
parent, err := sd.Parent.asTraceSpanContext()
if err != nil {
return errors.Wrap(err, "unable to decode parent")
}
s.Parent = parent
var attributes []attribute.KeyValue
for _, a := range sd.Attributes {
kv, err := a.asAttributeKeyValue()
if err != nil {
return errors.Wrapf(err, "unable to decode attribute (%s)", a.Key)
}
attributes = append(attributes, kv)
}
s.Attributes = attributes
var events []tracesdk.Event
for _, e := range sd.Events {
var eventAttributes []attribute.KeyValue
for _, a := range e.Attributes {
kv, err := a.asAttributeKeyValue()
if err != nil {
return errors.Wrapf(err, "unable to decode event attribute (%s)", a.Key)
}
eventAttributes = append(eventAttributes, kv)
}
events = append(events, tracesdk.Event{
Name: e.Name,
Attributes: eventAttributes,
DroppedAttributeCount: e.DroppedAttributeCount,
Time: e.Time,
})
}
s.Events = events
var links []tracesdk.Link
for _, l := range sd.Links {
linkSpanCtx, err := l.SpanContext.asTraceSpanContext()
if err != nil {
return errors.Wrap(err, "unable to decode linkSpanCtx")
}
var linkAttributes []attribute.KeyValue
for _, a := range l.Attributes {
kv, err := a.asAttributeKeyValue()
if err != nil {
return errors.Wrapf(err, "unable to decode link attribute (%s)", a.Key)
}
linkAttributes = append(linkAttributes, kv)
}
links = append(links, tracesdk.Link{
SpanContext: linkSpanCtx,
Attributes: linkAttributes,
DroppedAttributeCount: l.DroppedAttributeCount,
})
}
s.Links = links
var resources []attribute.KeyValue
for _, r := range sd.Resource {
kv, err := r.asAttributeKeyValue()
if err != nil {
return errors.Wrapf(err, "unable to decode resource (%s)", r.Key)
}
resources = append(resources, kv)
}
s.Resource = resources
return nil
}
// asTraceSpanContext converts the internal spanContext representation to an
// otel one.
func (sc *spanContext) asTraceSpanContext() (trace.SpanContext, error) {
traceID, err := traceIDFromHex(sc.TraceID)
if err != nil {
return trace.SpanContext{}, errors.Wrap(err, "unable to parse trace id")
}
spanID, err := spanIDFromHex(sc.SpanID)
if err != nil {
return trace.SpanContext{}, errors.Wrap(err, "unable to parse span id")
}
traceFlags := trace.TraceFlags(0x00)
if sc.TraceFlags == "01" {
traceFlags = trace.TraceFlags(0x01)
}
config := trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: traceFlags,
Remote: sc.Remote,
}
return trace.NewSpanContext(config), nil
}
// asAttributeKeyValue converts the internal keyValue representation to an
// otel one.
func (kv *keyValue) asAttributeKeyValue() (attribute.KeyValue, error) {
// value types get encoded as string
switch kv.Value.Type {
case attribute.INVALID.String():
return attribute.KeyValue{}, errors.New("invalid value type")
case attribute.BOOL.String():
return attribute.Bool(kv.Key, kv.Value.Value.(bool)), nil
case attribute.INT64.String():
// value could be int64 or float64, so handle both cases (float64 comes
// from json unmarshal)
var v int64
switch i := kv.Value.Value.(type) {
case int64:
v = i
case float64:
v = int64(i)
}
return attribute.Int64(kv.Key, v), nil
case attribute.FLOAT64.String():
return attribute.Float64(kv.Key, kv.Value.Value.(float64)), nil
case attribute.STRING.String():
return attribute.String(kv.Key, kv.Value.Value.(string)), nil
case attribute.BOOLSLICE.String():
return attribute.BoolSlice(kv.Key, kv.Value.Value.([]bool)), nil
case attribute.INT64SLICE.String():
// handle both float64 and int64 (float64 comes from json unmarshal)
var v []int64
switch sli := kv.Value.Value.(type) {
case []int64:
v = sli
case []float64:
for i := range sli {
v = append(v, int64(sli[i]))
}
}
return attribute.Int64Slice(kv.Key, v), nil
case attribute.FLOAT64SLICE.String():
return attribute.Float64Slice(kv.Key, kv.Value.Value.([]float64)), nil
case attribute.STRINGSLICE.String():
var strSli []string
// sometimes we can get an []interface{} instead of a []string, so
// always cast to []string if that happens.
switch sli := kv.Value.Value.(type) {
case []string:
strSli = sli
case []interface{}:
for i := range sli {
var v string
// best case we have a string, otherwise, cast it using
// fmt.Sprintf
if str, ok := sli[i].(string); ok {
v = str
} else {
v = fmt.Sprintf("%v", sli[i])
}
// add the string to the slice
strSli = append(strSli, v)
}
default:
return attribute.KeyValue{}, errors.Errorf("got unsupported type %q for %s", reflect.ValueOf(kv.Value.Value).Kind(), attribute.STRINGSLICE.String())
}
return attribute.StringSlice(kv.Key, strSli), nil
default:
return attribute.KeyValue{}, errors.Errorf("unknown value type %s", kv.Value.Type)
}
}
// traceIDFromHex returns a TraceID from a hex string if it is compliant with
// the W3C trace-context specification and removes the validity check.
// https://www.w3.org/TR/trace-context/#trace-id
func traceIDFromHex(h string) (trace.TraceID, error) {
t := trace.TraceID{}
if len(h) != 32 {
return t, errors.New("unable to parse trace id")
}
if err := decodeHex(h, t[:]); err != nil {
return t, err
}
return t, nil
}
// spanIDFromHex returns a SpanID from a hex string if it is compliant with the
// W3C trace-context specification and removes the validity check.
// https://www.w3.org/TR/trace-context/#parent-id
func spanIDFromHex(h string) (trace.SpanID, error) {
s := trace.SpanID{}
if len(h) != 16 {
return s, errors.New("unable to parse span id of length: %d")
}
if err := decodeHex(h, s[:]); err != nil {
return s, err
}
return s, nil
}
// decodeHex decodes hex in a manner compliant with otel.
func decodeHex(h string, b []byte) error {
for _, r := range h {
switch {
case 'a' <= r && r <= 'f':
continue
case '0' <= r && r <= '9':
continue
default:
return errors.New("unable to parse hex id")
}
}
decoded, err := hex.DecodeString(h)
if err != nil {
return err
}
copy(b, decoded)
return nil
}
// Snapshot turns a Span into a ReadOnlySpan which is exportable by otel.
func (s *Span) Snapshot() tracesdk.ReadOnlySpan {
return spanSnapshot{
name: s.Name,
spanContext: s.SpanContext,
parent: s.Parent,
spanKind: s.SpanKind,
startTime: s.StartTime,
endTime: s.EndTime,
attributes: s.Attributes,
events: s.Events,
links: s.Links,
status: s.Status,
droppedAttributes: s.DroppedAttributes,
droppedEvents: s.DroppedEvents,
droppedLinks: s.DroppedLinks,
childSpanCount: s.ChildSpanCount,
resource: resource.NewSchemaless(s.Resource...),
instrumentationScope: s.InstrumentationLibrary,
}
}
// spanSnapshot is a helper type for transforming a Span into a ReadOnlySpan.
type spanSnapshot struct {
// Embed the interface to implement the private method.
tracesdk.ReadOnlySpan
name string
spanContext trace.SpanContext
parent trace.SpanContext
spanKind trace.SpanKind
startTime time.Time
endTime time.Time
attributes []attribute.KeyValue
events []tracesdk.Event
links []tracesdk.Link
status tracesdk.Status
droppedAttributes int
droppedEvents int
droppedLinks int
childSpanCount int
resource *resource.Resource
instrumentationScope instrumentation.Scope
}
// Name returns the Name of the snapshot
func (s spanSnapshot) Name() string { return s.name }
// SpanContext returns the SpanContext of the snapshot
func (s spanSnapshot) SpanContext() trace.SpanContext { return s.spanContext }
// Parent returns the Parent of the snapshot
func (s spanSnapshot) Parent() trace.SpanContext { return s.parent }
// SpanKind returns the SpanKind of the snapshot
func (s spanSnapshot) SpanKind() trace.SpanKind { return s.spanKind }
// StartTime returns the StartTime of the snapshot
func (s spanSnapshot) StartTime() time.Time { return s.startTime }
// EndTime returns the EndTime of the snapshot
func (s spanSnapshot) EndTime() time.Time { return s.endTime }
// Attributes returns the Attributes of the snapshot
func (s spanSnapshot) Attributes() []attribute.KeyValue { return s.attributes }
// Links returns the Links of the snapshot
func (s spanSnapshot) Links() []tracesdk.Link { return s.links }
// Events return the Events of the snapshot
func (s spanSnapshot) Events() []tracesdk.Event { return s.events }
// Status returns the Status of the snapshot
func (s spanSnapshot) Status() tracesdk.Status { return s.status }
// DroppedAttributes returns the DroppedAttributes of the snapshot
func (s spanSnapshot) DroppedAttributes() int { return s.droppedAttributes }
// DroppedLinks returns the DroppedLinks of the snapshot
func (s spanSnapshot) DroppedLinks() int { return s.droppedLinks }
// DroppedEvents returns the DroppedEvents of the snapshot
func (s spanSnapshot) DroppedEvents() int { return s.droppedEvents }
// ChildSpanCount returns the ChildSpanCount of the snapshot
func (s spanSnapshot) ChildSpanCount() int { return s.childSpanCount }
// Resource returns the Resource of the snapshot
func (s spanSnapshot) Resource() *resource.Resource { return s.resource }
// InstrumentationScope returns the InstrumentationScope of the snapshot
func (s spanSnapshot) InstrumentationScope() instrumentation.Scope {
return s.instrumentationScope
}
// InstrumentationLibrary returns the InstrumentationLibrary of the snapshot
//
//nolint:staticcheck
func (s spanSnapshot) InstrumentationLibrary() instrumentation.Library {
return s.instrumentationScope
}

159
util/otelutil/span_test.go Normal file
View File

@@ -0,0 +1,159 @@
package otelutil
import (
"bytes"
"context"
"encoding/json"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
)
// curl -s --unix-socket /tmp/docker-desktop-build-dev.sock http://localhost/blobs/default/default?digest=sha256:3103104e9fa908087bd47572da6ad9a5a7bf973608f736536d18d635a7da0140 -X GET > ./fixtures/bktraces.json
const bktracesFixture = "./fixtures/bktraces.json"
const otlpFixture = "./fixtures/otlp.json"
func TestParseSpanStubs(t *testing.T) {
dt, err := os.ReadFile(bktracesFixture)
require.NoError(t, err)
spanStubs, err := ParseSpanStubs(bytes.NewReader(dt))
require.NoError(t, err)
require.Equal(t, 73, len(spanStubs))
dtSpanStubs, err := json.MarshalIndent(spanStubs, "", " ")
require.NoError(t, err)
dtotel, err := os.ReadFile(otlpFixture)
require.NoError(t, err)
require.Equal(t, string(dtotel), string(dtSpanStubs))
exp, err := stdouttrace.New(stdouttrace.WithPrettyPrint())
require.NoError(t, err)
require.NoError(t, exp.ExportSpans(context.Background(), spanStubs.ReadOnlySpans()))
}
func TestAsAttributeKeyValue(t *testing.T) {
type args struct {
Type string
value any
}
tests := []struct {
name string
args args
want attribute.KeyValue
}{
{
name: "string",
args: args{
Type: attribute.STRING.String(),
value: "value",
},
want: attribute.String("key", "value"),
},
{
name: "int64 (int64)",
args: args{
Type: attribute.INT64.String(),
value: int64(1),
},
want: attribute.Int64("key", 1),
},
{
name: "int64 (float64)",
args: args{
Type: attribute.INT64.String(),
value: float64(1.0),
},
want: attribute.Int64("key", 1),
},
{
name: "bool",
args: args{
Type: attribute.BOOL.String(),
value: true,
},
want: attribute.Bool("key", true),
},
{
name: "float64",
args: args{
Type: attribute.FLOAT64.String(),
value: float64(1.0),
},
want: attribute.Float64("key", 1.0),
},
{
name: "float64slice",
args: args{
Type: attribute.FLOAT64SLICE.String(),
value: []float64{1.0, 2.0},
},
want: attribute.Float64Slice("key", []float64{1.0, 2.0}),
},
{
name: "int64slice (int64)",
args: args{
Type: attribute.INT64SLICE.String(),
value: []int64{1, 2},
},
want: attribute.Int64Slice("key", []int64{1, 2}),
},
{
name: "int64slice (float64)",
args: args{
Type: attribute.INT64SLICE.String(),
value: []float64{1.0, 2.0},
},
want: attribute.Int64Slice("key", []int64{1, 2}),
},
{
name: "boolslice",
args: args{
Type: attribute.BOOLSLICE.String(),
value: []bool{true, false},
},
want: attribute.BoolSlice("key", []bool{true, false}),
},
{
name: "stringslice (strings)",
args: args{
Type: attribute.STRINGSLICE.String(),
value: []string{"value1", "value2"},
},
want: attribute.StringSlice("key", []string{"value1", "value2"}),
},
{
name: "stringslice (interface of string)",
args: args{
Type: attribute.STRINGSLICE.String(),
value: []interface{}{"value1", "value2"},
},
want: attribute.StringSlice("key", []string{"value1", "value2"}),
},
{
name: "stringslice (interface mixed)",
args: args{
Type: attribute.STRINGSLICE.String(),
value: []interface{}{"value1", 2},
},
want: attribute.StringSlice("key", []string{"value1", "2"}),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
kv := keyValue{
Key: "key",
Value: value{Type: tt.args.Type, Value: tt.args.value},
}
attr, err := kv.asAttributeKeyValue()
require.NoError(t, err, "failed to convert key value to attribute key value")
assert.Equal(t, tt.want, attr, "attribute key value mismatch")
})
}
}

41
vendor/github.com/Azure/go-ansiterm/SECURITY.md generated vendored Normal file
View File

@@ -0,0 +1,41 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.8 BLOCK -->
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
## Preferred Languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
<!-- END MICROSOFT SECURITY.MD BLOCK -->

View File

@@ -11,21 +11,13 @@ func (oscState oscStringState) Handle(b byte) (s state, e error) {
return nextState, err return nextState, err
} }
switch { // There are several control characters and sequences which can
case isOscStringTerminator(b): // terminate an OSC string. Most of them are handled by the baseState
// handler. The ANSI_BEL character is a special case which behaves as a
// terminator only for an OSC string.
if b == ANSI_BEL {
return oscState.parser.ground, nil return oscState.parser.ground, nil
} }
return oscState, nil return oscState, nil
} }
// See below for OSC string terminators for linux
// http://man7.org/linux/man-pages/man4/console_codes.4.html
func isOscStringTerminator(b byte) bool {
if b == ANSI_BEL || b == 0x5C {
return true
}
return false
}

View File

@@ -1420,6 +1420,8 @@ type BuildHistoryRequest struct {
ActiveOnly bool `protobuf:"varint,1,opt,name=ActiveOnly,proto3" json:"ActiveOnly,omitempty"` ActiveOnly bool `protobuf:"varint,1,opt,name=ActiveOnly,proto3" json:"ActiveOnly,omitempty"`
Ref string `protobuf:"bytes,2,opt,name=Ref,proto3" json:"Ref,omitempty"` Ref string `protobuf:"bytes,2,opt,name=Ref,proto3" json:"Ref,omitempty"`
EarlyExit bool `protobuf:"varint,3,opt,name=EarlyExit,proto3" json:"EarlyExit,omitempty"` EarlyExit bool `protobuf:"varint,3,opt,name=EarlyExit,proto3" json:"EarlyExit,omitempty"`
Filter []string `protobuf:"bytes,4,rep,name=Filter,proto3" json:"Filter,omitempty"`
Limit int32 `protobuf:"varint,5,opt,name=Limit,proto3" json:"Limit,omitempty"`
} }
func (x *BuildHistoryRequest) Reset() { func (x *BuildHistoryRequest) Reset() {
@@ -1473,6 +1475,20 @@ func (x *BuildHistoryRequest) GetEarlyExit() bool {
return false return false
} }
func (x *BuildHistoryRequest) GetFilter() []string {
if x != nil {
return x.Filter
}
return nil
}
func (x *BuildHistoryRequest) GetLimit() int32 {
if x != nil {
return x.Limit
}
return 0
}
type BuildHistoryEvent struct { type BuildHistoryEvent struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -2274,211 +2290,214 @@ var file_github_com_moby_buildkit_api_services_control_control_proto_rawDesc = [
0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e,
0x42, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52,
0x0f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x0f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x22, 0x65, 0x0a, 0x13, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x22, 0x93, 0x01, 0x0a, 0x13, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x41, 0x63, 0x74, 0x69, 0x76, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x41, 0x63, 0x74, 0x69,
0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x41, 0x63, 0x74, 0x76, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x41, 0x63,
0x69, 0x76, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x52, 0x65, 0x66, 0x18, 0x02, 0x74, 0x69, 0x76, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x52, 0x65, 0x66, 0x18,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x52, 0x65, 0x66, 0x12, 0x1c, 0x0a, 0x09, 0x45, 0x61, 0x72, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x52, 0x65, 0x66, 0x12, 0x1c, 0x0a, 0x09, 0x45, 0x61,
0x6c, 0x79, 0x45, 0x78, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x45, 0x61, 0x72, 0x6c, 0x79, 0x45, 0x78, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x45,
0x72, 0x6c, 0x79, 0x45, 0x78, 0x69, 0x74, 0x22, 0x8e, 0x01, 0x0a, 0x11, 0x42, 0x75, 0x69, 0x6c, 0x61, 0x72, 0x6c, 0x79, 0x45, 0x78, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x46, 0x69, 0x6c, 0x74,
0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x65, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72,
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x6d, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52,
0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x05, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x8e, 0x01, 0x0a, 0x11, 0x42, 0x75, 0x69, 0x6c, 0x64,
0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x04,
0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x72, 0x65, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x6d, 0x6f, 0x62,
0x63, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x6f, 0x62,
0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75,
0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54,
0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x22, 0xd3, 0x09, 0x0a, 0x12, 0x42, 0x75, 0x69, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x72, 0x65, 0x63,
0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x6f, 0x62, 0x79,
0x10, 0x0a, 0x03, 0x52, 0x65, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x52, 0x65, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69,
0x66, 0x12, 0x1a, 0x0a, 0x08, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52,
0x01, 0x28, 0x09, 0x52, 0x08, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x12, 0x5d, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x22, 0xd3, 0x09, 0x0a, 0x12, 0x42, 0x75, 0x69, 0x6c,
0x0d, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x72, 0x73, 0x18, 0x03, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x10,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x0a, 0x03, 0x52, 0x65, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x52, 0x65, 0x66,
0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01,
0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x28, 0x09, 0x52, 0x08, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x12, 0x5d, 0x0a, 0x0d,
0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x46, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x72, 0x73, 0x18, 0x03, 0x20,
0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x72, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64,
0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74,
0x1a, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65,
0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x52, 0x09, 0x45, 0x78, 0x70, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x46, 0x72,
0x6f, 0x72, 0x74, 0x65, 0x72, 0x73, 0x12, 0x28, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x72, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x45,
0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a,
0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
0x12, 0x38, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x06, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3c, 0x0a, 0x0b, 0x43, 0x6f,
0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x43, 0x6f, 0x6d,
0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x30, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73,
0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75,
0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x6f, 0x72, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x66, 0x0a, 0x10, 0x45, 0x78,
0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x09,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c,
0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73,
0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72,
0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x52, 0x10, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x39, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x0a, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b,
0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c,
0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x4b, 0x0a,
0x07, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31,
0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76,
0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x52, 0x09, 0x45, 0x78, 0x70, 0x6f,
0x63, 0x6f, 0x72, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x72, 0x74, 0x65, 0x72, 0x73, 0x12, 0x28, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05,
0x79, 0x52, 0x07, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x47, 0x65, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70,
0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12,
0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x05, 0x74, 0x72, 0x38, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x06, 0x20, 0x01,
0x61, 0x63, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09,
0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x05, 0x74, 0x72, 0x61, 0x63, 0x65, 0x12, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3c, 0x0a, 0x0b, 0x43, 0x6f, 0x6d,
0x0a, 0x06, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x43, 0x61, 0x63, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x68, 0x65, 0x64, 0x53, 0x74, 0x65, 0x70, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x43, 0x6f, 0x6d, 0x70,
0x6e, 0x75, 0x6d, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x53, 0x74, 0x65, 0x70, 0x73, 0x12, 0x24, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x30, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18,
0x0a, 0x0d, 0x6e, 0x75, 0x6d, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x53, 0x74, 0x65, 0x70, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69,
0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x6e, 0x75, 0x6d, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x53, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x65, 0x70, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x6e, 0x75, 0x6d, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x74, 0x6f, 0x72, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x66, 0x0a, 0x10, 0x45, 0x78, 0x70,
0x65, 0x74, 0x65, 0x64, 0x53, 0x74, 0x65, 0x70, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x09, 0x20,
0x11, 0x6e, 0x75, 0x6d, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x53, 0x74, 0x65, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64,
0x70, 0x73, 0x12, 0x42, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x45, 0x72, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74,
0x72, 0x6f, 0x72, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x10, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x6c, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x75, 0x6d, 0x57, 0x61, 0x72, 0x65, 0x12, 0x39, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28,
0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69,
0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
0x74, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x4b, 0x0a, 0x07,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e,
0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x43, 0x0a, 0x15, 0x45, 0x78,
0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a,
0x5d, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
0x79, 0x12, 0x37, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x21, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74,
0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x49,
0x6e, 0x66, 0x6f, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x79,
0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73,
0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x52,
0x65, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x52, 0x65, 0x66, 0x12, 0x16, 0x0a,
0x06, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x50,
0x69, 0x6e, 0x6e, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18,
0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1a, 0x0a,
0x08, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52,
0x08, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x22, 0x1c, 0x0a, 0x1a, 0x55, 0x70, 0x64,
0x61, 0x74, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe8, 0x01, 0x0a, 0x0a, 0x44, 0x65, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f,
0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x64, 0x69,
0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a,
0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a,
0x65, 0x12, 0x4f, 0x0a, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75,
0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x6f, 0x72, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x1a, 0x3e, 0x0a, 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
0x38, 0x01, 0x22, 0xc1, 0x02, 0x0a, 0x0f, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x48, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1c, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74,
0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x10,
0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64,
0x12, 0x40, 0x0a, 0x0c, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75,
0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x6f, 0x72, 0x52, 0x0c, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x12, 0x48, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64,
0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x52, 0x07, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x1a, 0x58, 0x0a, 0x0c,
0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x32,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e,
0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31,
0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x63,
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x95, 0x01, 0x0a, 0x08, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x6f, 0x72, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x52, 0x07, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x47, 0x65, 0x6e,
0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x3b, 0x0a, 0x05, 0x41, 0x74, 0x74, 0x72, 0x73, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x47,
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x05, 0x74, 0x72, 0x61,
0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x63, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e,
0x65, 0x72, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x41, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63,
0x74, 0x74, 0x72, 0x73, 0x1a, 0x38, 0x0a, 0x0a, 0x41, 0x74, 0x74, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x05, 0x74, 0x72, 0x61, 0x63, 0x65, 0x12, 0x16, 0x0a,
0x06, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70,
0x69, 0x6e, 0x6e, 0x65, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x43, 0x61, 0x63, 0x68,
0x65, 0x64, 0x53, 0x74, 0x65, 0x70, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6e,
0x75, 0x6d, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x53, 0x74, 0x65, 0x70, 0x73, 0x12, 0x24, 0x0a,
0x0d, 0x6e, 0x75, 0x6d, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x53, 0x74, 0x65, 0x70, 0x73, 0x18, 0x10,
0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x6e, 0x75, 0x6d, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x53, 0x74,
0x65, 0x70, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x6e, 0x75, 0x6d, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65,
0x74, 0x65, 0x64, 0x53, 0x74, 0x65, 0x70, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11,
0x6e, 0x75, 0x6d, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x53, 0x74, 0x65, 0x70,
0x73, 0x12, 0x42, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x45, 0x72, 0x72,
0x6f, 0x72, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e,
0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x75, 0x6d, 0x57, 0x61, 0x72, 0x6e,
0x69, 0x6e, 0x67, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x57,
0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x46, 0x72, 0x6f, 0x6e, 0x74,
0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x43, 0x0a, 0x15, 0x45, 0x78, 0x70,
0x6f, 0x72, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x45, 0x6e, 0x74,
0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x2a, 0x3f, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5d,
0x0a, 0x15, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x76, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x41, 0x52, 0x54, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x12, 0x37, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02, 0x32, 0x21, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e,
0x89, 0x06, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x54, 0x0a, 0x09, 0x44, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x49, 0x6e,
0x69, 0x73, 0x6b, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x22, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x66, 0x6f, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x79, 0x0a,
0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x6b, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74,
0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x52, 0x65,
0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x52, 0x65, 0x66, 0x12, 0x16, 0x0a, 0x06,
0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x50, 0x69,
0x6e, 0x6e, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03,
0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08,
0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08,
0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x22, 0x1c, 0x0a, 0x1a, 0x55, 0x70, 0x64, 0x61,
0x74, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe8, 0x01, 0x0a, 0x0a, 0x44, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x74,
0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x64, 0x69, 0x61,
0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,
0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65,
0x12, 0x4f, 0x0a, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69,
0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x6f, 0x72, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x1a, 0x3e, 0x0a, 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x22, 0xc1, 0x02, 0x0a, 0x0f, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c,
0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x48, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x44,
0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1c, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e,
0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x10, 0x52,
0x65, 0x73, 0x75, 0x6c, 0x74, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12,
0x40, 0x0a, 0x0c, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69,
0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x6f, 0x72, 0x52, 0x0c, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x12, 0x48, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b,
0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c,
0x74, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x45, 0x6e, 0x74,
0x72, 0x79, 0x52, 0x07, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x1a, 0x58, 0x0a, 0x0c, 0x52,
0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x32, 0x0a,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d,
0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e,
0x44, 0x69, 0x73, 0x6b, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x12, 0x48, 0x0a, 0x05, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x12, 0x1e, 0x2e, 0x6d, 0x6f, 0x62, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x95, 0x01, 0x0a, 0x08, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x75, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6d, 0x6f, 0x62, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x3b, 0x0a, 0x05, 0x41, 0x74, 0x74, 0x72, 0x73, 0x18,
0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69,
0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x30, 0x01, 0x12, 0x48, 0x0a, 0x05, 0x53, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65,
0x6f, 0x6c, 0x76, 0x65, 0x12, 0x1e, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x72, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x41, 0x74,
0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6f, 0x6c, 0x76, 0x65, 0x52, 0x65, 0x71, 0x74, 0x72, 0x73, 0x1a, 0x38, 0x0a, 0x0a, 0x41, 0x74, 0x74, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6f, 0x6c, 0x76, 0x65, 0x52, 0x65, 0x73, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x2a, 0x3f, 0x0a,
0x1f, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x15, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x76, 0x65,
0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45,
0x1a, 0x20, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x10,
0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02, 0x32, 0x89,
0x73, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x06, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x54, 0x0a, 0x09, 0x44, 0x69,
0x1e, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x73, 0x6b, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x22, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62,
0x76, 0x31, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x6b, 0x55,
0x1e, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x6f,
0x76, 0x31, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44,
0x01, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x69, 0x73, 0x6b, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x72, 0x73, 0x12, 0x24, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x12, 0x48, 0x0a, 0x05, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x12, 0x1e, 0x2e, 0x6d, 0x6f, 0x62, 0x79,
0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x75,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6d, 0x6f, 0x62, 0x79,
0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x61,
0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x30, 0x01, 0x12, 0x48, 0x0a, 0x05, 0x53, 0x6f,
0x45, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x6c, 0x76, 0x65, 0x12, 0x1e, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64,
0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6f, 0x6c, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64,
0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6f, 0x6c, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1f,
0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76,
0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x20, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e,
0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e,
0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76,
0x31, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1e,
0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76,
0x31, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x01,
0x30, 0x01, 0x12, 0x5a, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72,
0x73, 0x12, 0x24, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69,
0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62,
0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57,
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45,
0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75,
0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69,
0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x25, 0x2e, 0x6d, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x42,
0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x25, 0x2e, 0x6d, 0x6f,
0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42,
0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b,
0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f,
0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x6f, 0x0a, 0x12, 0x55, 0x70, 0x64,
0x61, 0x74, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12,
0x2b, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e,
0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69,
0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6d,
0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e,
0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f,
0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x40, 0x5a, 0x3e, 0x67, 0x69,
0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x6f, 0x62, 0x79, 0x2f, 0x62, 0x75,
0x6f, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x6f, 0x0a, 0x12, 0x55, 0x70, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69,
0x64, 0x61, 0x74, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x63, 0x65, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3b, 0x6d, 0x6f, 0x62, 0x79,
0x12, 0x2b, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x5f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72,
0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x6f, 0x74, 0x6f, 0x33,
0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e,
0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31,
0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x69, 0x73, 0x74,
0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x40, 0x5a, 0x3e, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x6f, 0x62, 0x79, 0x2f, 0x62,
0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3b, 0x6d, 0x6f, 0x62,
0x79, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x5f, 0x76, 0x31, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -180,6 +180,8 @@ message BuildHistoryRequest {
bool ActiveOnly = 1; bool ActiveOnly = 1;
string Ref = 2; string Ref = 2;
bool EarlyExit = 3; bool EarlyExit = 3;
repeated string Filter = 4;
int32 Limit = 5;
} }
enum BuildHistoryEventType { enum BuildHistoryEventType {

View File

@@ -558,6 +558,12 @@ func (m *BuildHistoryRequest) CloneVT() *BuildHistoryRequest {
r.ActiveOnly = m.ActiveOnly r.ActiveOnly = m.ActiveOnly
r.Ref = m.Ref r.Ref = m.Ref
r.EarlyExit = m.EarlyExit r.EarlyExit = m.EarlyExit
r.Limit = m.Limit
if rhs := m.Filter; rhs != nil {
tmpContainer := make([]string, len(rhs))
copy(tmpContainer, rhs)
r.Filter = tmpContainer
}
if len(m.unknownFields) > 0 { if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields)) r.unknownFields = make([]byte, len(m.unknownFields))
copy(r.unknownFields, m.unknownFields) copy(r.unknownFields, m.unknownFields)
@@ -1569,6 +1575,18 @@ func (this *BuildHistoryRequest) EqualVT(that *BuildHistoryRequest) bool {
if this.EarlyExit != that.EarlyExit { if this.EarlyExit != that.EarlyExit {
return false return false
} }
if len(this.Filter) != len(that.Filter) {
return false
}
for i, vx := range this.Filter {
vy := that.Filter[i]
if vx != vy {
return false
}
}
if this.Limit != that.Limit {
return false
}
return string(this.unknownFields) == string(that.unknownFields) return string(this.unknownFields) == string(that.unknownFields)
} }
@@ -3272,6 +3290,20 @@ func (m *BuildHistoryRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
i -= len(m.unknownFields) i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields) copy(dAtA[i:], m.unknownFields)
} }
if m.Limit != 0 {
i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Limit))
i--
dAtA[i] = 0x28
}
if len(m.Filter) > 0 {
for iNdEx := len(m.Filter) - 1; iNdEx >= 0; iNdEx-- {
i -= len(m.Filter[iNdEx])
copy(dAtA[i:], m.Filter[iNdEx])
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Filter[iNdEx])))
i--
dAtA[i] = 0x22
}
}
if m.EarlyExit { if m.EarlyExit {
i-- i--
if m.EarlyExit { if m.EarlyExit {
@@ -4465,6 +4497,15 @@ func (m *BuildHistoryRequest) SizeVT() (n int) {
if m.EarlyExit { if m.EarlyExit {
n += 2 n += 2
} }
if len(m.Filter) > 0 {
for _, s := range m.Filter {
l = len(s)
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
}
if m.Limit != 0 {
n += 1 + protohelpers.SizeOfVarint(uint64(m.Limit))
}
n += len(m.unknownFields) n += len(m.unknownFields)
return n return n
} }
@@ -8694,6 +8735,57 @@ func (m *BuildHistoryRequest) UnmarshalVT(dAtA []byte) error {
} }
} }
m.EarlyExit = bool(v != 0) m.EarlyExit = bool(v != 0)
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Filter", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Filter = append(m.Filter, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType)
}
m.Limit = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Limit |= int32(b&0x7F) << shift
if b < 0x80 {
break
}
}
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:]) skippy, err := protohelpers.Skip(dAtA[iNdEx:])

View File

@@ -31,6 +31,7 @@ type WorkerRecord struct {
Platforms []*pb.Platform `protobuf:"bytes,3,rep,name=platforms,proto3" json:"platforms,omitempty"` Platforms []*pb.Platform `protobuf:"bytes,3,rep,name=platforms,proto3" json:"platforms,omitempty"`
GCPolicy []*GCPolicy `protobuf:"bytes,4,rep,name=GCPolicy,proto3" json:"GCPolicy,omitempty"` GCPolicy []*GCPolicy `protobuf:"bytes,4,rep,name=GCPolicy,proto3" json:"GCPolicy,omitempty"`
BuildkitVersion *BuildkitVersion `protobuf:"bytes,5,opt,name=BuildkitVersion,proto3" json:"BuildkitVersion,omitempty"` BuildkitVersion *BuildkitVersion `protobuf:"bytes,5,opt,name=BuildkitVersion,proto3" json:"BuildkitVersion,omitempty"`
CDIDevices []*CDIDevice `protobuf:"bytes,6,rep,name=CDIDevices,proto3" json:"CDIDevices,omitempty"`
} }
func (x *WorkerRecord) Reset() { func (x *WorkerRecord) Reset() {
@@ -98,6 +99,13 @@ func (x *WorkerRecord) GetBuildkitVersion() *BuildkitVersion {
return nil return nil
} }
func (x *WorkerRecord) GetCDIDevices() []*CDIDevice {
if x != nil {
return x.CDIDevices
}
return nil
}
type GCPolicy struct { type GCPolicy struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -245,6 +253,75 @@ func (x *BuildkitVersion) GetRevision() string {
return "" return ""
} }
type CDIDevice struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
AutoAllow bool `protobuf:"varint,2,opt,name=AutoAllow,proto3" json:"AutoAllow,omitempty"`
Annotations map[string]string `protobuf:"bytes,3,rep,name=Annotations,proto3" json:"Annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
OnDemand bool `protobuf:"varint,4,opt,name=OnDemand,proto3" json:"OnDemand,omitempty"`
}
func (x *CDIDevice) Reset() {
*x = CDIDevice{}
mi := &file_github_com_moby_buildkit_api_types_worker_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CDIDevice) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CDIDevice) ProtoMessage() {}
func (x *CDIDevice) ProtoReflect() protoreflect.Message {
mi := &file_github_com_moby_buildkit_api_types_worker_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CDIDevice.ProtoReflect.Descriptor instead.
func (*CDIDevice) Descriptor() ([]byte, []int) {
return file_github_com_moby_buildkit_api_types_worker_proto_rawDescGZIP(), []int{3}
}
func (x *CDIDevice) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *CDIDevice) GetAutoAllow() bool {
if x != nil {
return x.AutoAllow
}
return false
}
func (x *CDIDevice) GetAnnotations() map[string]string {
if x != nil {
return x.Annotations
}
return nil
}
func (x *CDIDevice) GetOnDemand() bool {
if x != nil {
return x.OnDemand
}
return false
}
var File_github_com_moby_buildkit_api_types_worker_proto protoreflect.FileDescriptor var File_github_com_moby_buildkit_api_types_worker_proto protoreflect.FileDescriptor
var file_github_com_moby_buildkit_api_types_worker_proto_rawDesc = []byte{ var file_github_com_moby_buildkit_api_types_worker_proto_rawDesc = []byte{
@@ -255,7 +332,7 @@ var file_github_com_moby_buildkit_api_types_worker_proto_rawDesc = []byte{
0x2e, 0x76, 0x31, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x1a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x2e, 0x76, 0x31, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x1a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x6f, 0x62, 0x79, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x6f, 0x62, 0x79, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64,
0x6b, 0x69, 0x74, 0x2f, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x62, 0x2f, 0x6f, 0x70, 0x6b, 0x69, 0x74, 0x2f, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x62, 0x2f, 0x6f, 0x70,
0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe0, 0x02, 0x0a, 0x0c, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa3, 0x03, 0x0a, 0x0c, 0x57, 0x6f, 0x72, 0x6b,
0x65, 0x72, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x65, 0x72, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x48, 0x0a, 0x06, 0x4c, 0x61, 0x62, 0x65, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x48, 0x0a, 0x06, 0x4c, 0x61, 0x62, 0x65,
0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e,
@@ -273,34 +350,54 @@ var file_github_com_moby_buildkit_api_types_worker_proto_rawDesc = []byte{
0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69,
0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x42, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x42,
0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0f,
0x42, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12,
0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x41, 0x0a, 0x0a, 0x43, 0x44, 0x49, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x06, 0x20,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64,
0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x6b, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x44, 0x49,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc8, 0x01, 0x0a, 0x08, 0x47, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x0a, 0x43, 0x44, 0x49, 0x44, 0x65, 0x76, 0x69, 0x63,
0x43, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x01, 0x65, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72,
0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x6c, 0x6c, 0x12, 0x22, 0x0a, 0x0c, 0x6b, 0x65, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x70, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x0c, 0x6b, 0x65, 0x65, 0x70, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc8, 0x01,
0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x0a, 0x08, 0x47, 0x43, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6c,
0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x65, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x6c, 0x6c, 0x12, 0x22, 0x0a, 0x0c,
0x76, 0x65, 0x64, 0x53, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6b, 0x65, 0x65, 0x70, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x22, 0x0a, 0x28, 0x03, 0x52, 0x0c, 0x6b, 0x65, 0x65, 0x70, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x0c, 0x6d, 0x61, 0x78, 0x55, 0x73, 0x65, 0x64, 0x53, 0x70, 0x61, 0x63, 0x65, 0x18, 0x05, 0x20, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28,
0x01, 0x28, 0x03, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x55, 0x73, 0x65, 0x64, 0x53, 0x70, 0x61, 0x63, 0x09, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65,
0x65, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x69, 0x6e, 0x46, 0x72, 0x65, 0x65, 0x53, 0x70, 0x61, 0x63, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x53, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x46, 0x72, 0x65, 0x65, 0x03, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x53, 0x70, 0x61, 0x63, 0x65,
0x53, 0x70, 0x61, 0x63, 0x65, 0x22, 0x61, 0x0a, 0x0f, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x55, 0x73, 0x65, 0x64, 0x53, 0x70, 0x61, 0x63, 0x65,
0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x55, 0x73, 0x65, 0x64, 0x53,
0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x70, 0x61, 0x63, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x69, 0x6e, 0x46, 0x72, 0x65, 0x65, 0x53,
0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x70, 0x61, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x46,
0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x22, 0x61, 0x0a, 0x0f, 0x42, 0x75, 0x69, 0x6c,
0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x6b, 0x69, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x70,
0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x6f, 0x62, 0x79, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x64, 0x6b, 0x69, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x3b, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12,
0x6f, 0x62, 0x79, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x5f, 0x76, 0x31, 0x5f, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28,
0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x09, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xef, 0x01, 0x0a, 0x09,
0x43, 0x44, 0x49, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a,
0x09, 0x41, 0x75, 0x74, 0x6f, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,
0x52, 0x09, 0x41, 0x75, 0x74, 0x6f, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x12, 0x54, 0x0a, 0x0b, 0x41,
0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x32, 0x2e, 0x6d, 0x6f, 0x62, 0x79, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74,
0x2e, 0x76, 0x31, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x44, 0x49, 0x44, 0x65, 0x76,
0x69, 0x63, 0x65, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x12, 0x1a, 0x0a, 0x08, 0x4f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x04, 0x20,
0x01, 0x28, 0x08, 0x52, 0x08, 0x4f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x3e, 0x0a,
0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x3b, 0x5a,
0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x6f, 0x62, 0x79,
0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79,
0x70, 0x65, 0x73, 0x3b, 0x6d, 0x6f, 0x62, 0x79, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69,
0x74, 0x5f, 0x76, 0x31, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
} }
var ( var (
@@ -315,24 +412,28 @@ func file_github_com_moby_buildkit_api_types_worker_proto_rawDescGZIP() []byte {
return file_github_com_moby_buildkit_api_types_worker_proto_rawDescData return file_github_com_moby_buildkit_api_types_worker_proto_rawDescData
} }
var file_github_com_moby_buildkit_api_types_worker_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_github_com_moby_buildkit_api_types_worker_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_github_com_moby_buildkit_api_types_worker_proto_goTypes = []any{ var file_github_com_moby_buildkit_api_types_worker_proto_goTypes = []any{
(*WorkerRecord)(nil), // 0: moby.buildkit.v1.types.WorkerRecord (*WorkerRecord)(nil), // 0: moby.buildkit.v1.types.WorkerRecord
(*GCPolicy)(nil), // 1: moby.buildkit.v1.types.GCPolicy (*GCPolicy)(nil), // 1: moby.buildkit.v1.types.GCPolicy
(*BuildkitVersion)(nil), // 2: moby.buildkit.v1.types.BuildkitVersion (*BuildkitVersion)(nil), // 2: moby.buildkit.v1.types.BuildkitVersion
nil, // 3: moby.buildkit.v1.types.WorkerRecord.LabelsEntry (*CDIDevice)(nil), // 3: moby.buildkit.v1.types.CDIDevice
(*pb.Platform)(nil), // 4: pb.Platform nil, // 4: moby.buildkit.v1.types.WorkerRecord.LabelsEntry
nil, // 5: moby.buildkit.v1.types.CDIDevice.AnnotationsEntry
(*pb.Platform)(nil), // 6: pb.Platform
} }
var file_github_com_moby_buildkit_api_types_worker_proto_depIdxs = []int32{ var file_github_com_moby_buildkit_api_types_worker_proto_depIdxs = []int32{
3, // 0: moby.buildkit.v1.types.WorkerRecord.Labels:type_name -> moby.buildkit.v1.types.WorkerRecord.LabelsEntry 4, // 0: moby.buildkit.v1.types.WorkerRecord.Labels:type_name -> moby.buildkit.v1.types.WorkerRecord.LabelsEntry
4, // 1: moby.buildkit.v1.types.WorkerRecord.platforms:type_name -> pb.Platform 6, // 1: moby.buildkit.v1.types.WorkerRecord.platforms:type_name -> pb.Platform
1, // 2: moby.buildkit.v1.types.WorkerRecord.GCPolicy:type_name -> moby.buildkit.v1.types.GCPolicy 1, // 2: moby.buildkit.v1.types.WorkerRecord.GCPolicy:type_name -> moby.buildkit.v1.types.GCPolicy
2, // 3: moby.buildkit.v1.types.WorkerRecord.BuildkitVersion:type_name -> moby.buildkit.v1.types.BuildkitVersion 2, // 3: moby.buildkit.v1.types.WorkerRecord.BuildkitVersion:type_name -> moby.buildkit.v1.types.BuildkitVersion
4, // [4:4] is the sub-list for method output_type 3, // 4: moby.buildkit.v1.types.WorkerRecord.CDIDevices:type_name -> moby.buildkit.v1.types.CDIDevice
4, // [4:4] is the sub-list for method input_type 5, // 5: moby.buildkit.v1.types.CDIDevice.Annotations:type_name -> moby.buildkit.v1.types.CDIDevice.AnnotationsEntry
4, // [4:4] is the sub-list for extension type_name 6, // [6:6] is the sub-list for method output_type
4, // [4:4] is the sub-list for extension extendee 6, // [6:6] is the sub-list for method input_type
0, // [0:4] is the sub-list for field type_name 6, // [6:6] is the sub-list for extension type_name
6, // [6:6] is the sub-list for extension extendee
0, // [0:6] is the sub-list for field type_name
} }
func init() { file_github_com_moby_buildkit_api_types_worker_proto_init() } func init() { file_github_com_moby_buildkit_api_types_worker_proto_init() }
@@ -346,7 +447,7 @@ func file_github_com_moby_buildkit_api_types_worker_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_github_com_moby_buildkit_api_types_worker_proto_rawDesc, RawDescriptor: file_github_com_moby_buildkit_api_types_worker_proto_rawDesc,
NumEnums: 0, NumEnums: 0,
NumMessages: 4, NumMessages: 6,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View File

@@ -12,6 +12,7 @@ message WorkerRecord {
repeated pb.Platform platforms = 3; repeated pb.Platform platforms = 3;
repeated GCPolicy GCPolicy = 4; repeated GCPolicy GCPolicy = 4;
BuildkitVersion BuildkitVersion = 5; BuildkitVersion BuildkitVersion = 5;
repeated CDIDevice CDIDevices = 6;
} }
message GCPolicy { message GCPolicy {
@@ -30,3 +31,10 @@ message BuildkitVersion {
string version = 2; string version = 2;
string revision = 3; string revision = 3;
} }
message CDIDevice {
string Name = 1;
bool AutoAllow = 2;
map<string, string> Annotations = 3;
bool OnDemand = 4;
}

View File

@@ -48,6 +48,13 @@ func (m *WorkerRecord) CloneVT() *WorkerRecord {
} }
r.GCPolicy = tmpContainer r.GCPolicy = tmpContainer
} }
if rhs := m.CDIDevices; rhs != nil {
tmpContainer := make([]*CDIDevice, len(rhs))
for k, v := range rhs {
tmpContainer[k] = v.CloneVT()
}
r.CDIDevices = tmpContainer
}
if len(m.unknownFields) > 0 { if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields)) r.unknownFields = make([]byte, len(m.unknownFields))
copy(r.unknownFields, m.unknownFields) copy(r.unknownFields, m.unknownFields)
@@ -104,6 +111,32 @@ func (m *BuildkitVersion) CloneMessageVT() proto.Message {
return m.CloneVT() return m.CloneVT()
} }
func (m *CDIDevice) CloneVT() *CDIDevice {
if m == nil {
return (*CDIDevice)(nil)
}
r := new(CDIDevice)
r.Name = m.Name
r.AutoAllow = m.AutoAllow
r.OnDemand = m.OnDemand
if rhs := m.Annotations; rhs != nil {
tmpContainer := make(map[string]string, len(rhs))
for k, v := range rhs {
tmpContainer[k] = v
}
r.Annotations = tmpContainer
}
if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields))
copy(r.unknownFields, m.unknownFields)
}
return r
}
func (m *CDIDevice) CloneMessageVT() proto.Message {
return m.CloneVT()
}
func (this *WorkerRecord) EqualVT(that *WorkerRecord) bool { func (this *WorkerRecord) EqualVT(that *WorkerRecord) bool {
if this == that { if this == that {
return true return true
@@ -162,6 +195,23 @@ func (this *WorkerRecord) EqualVT(that *WorkerRecord) bool {
if !this.BuildkitVersion.EqualVT(that.BuildkitVersion) { if !this.BuildkitVersion.EqualVT(that.BuildkitVersion) {
return false return false
} }
if len(this.CDIDevices) != len(that.CDIDevices) {
return false
}
for i, vx := range this.CDIDevices {
vy := that.CDIDevices[i]
if p, q := vx, vy; p != q {
if p == nil {
p = &CDIDevice{}
}
if q == nil {
q = &CDIDevice{}
}
if !p.EqualVT(q) {
return false
}
}
}
return string(this.unknownFields) == string(that.unknownFields) return string(this.unknownFields) == string(that.unknownFields)
} }
@@ -237,6 +287,43 @@ func (this *BuildkitVersion) EqualMessageVT(thatMsg proto.Message) bool {
} }
return this.EqualVT(that) return this.EqualVT(that)
} }
func (this *CDIDevice) EqualVT(that *CDIDevice) bool {
if this == that {
return true
} else if this == nil || that == nil {
return false
}
if this.Name != that.Name {
return false
}
if this.AutoAllow != that.AutoAllow {
return false
}
if len(this.Annotations) != len(that.Annotations) {
return false
}
for i, vx := range this.Annotations {
vy, ok := that.Annotations[i]
if !ok {
return false
}
if vx != vy {
return false
}
}
if this.OnDemand != that.OnDemand {
return false
}
return string(this.unknownFields) == string(that.unknownFields)
}
func (this *CDIDevice) EqualMessageVT(thatMsg proto.Message) bool {
that, ok := thatMsg.(*CDIDevice)
if !ok {
return false
}
return this.EqualVT(that)
}
func (m *WorkerRecord) MarshalVT() (dAtA []byte, err error) { func (m *WorkerRecord) MarshalVT() (dAtA []byte, err error) {
if m == nil { if m == nil {
return nil, nil return nil, nil
@@ -267,6 +354,18 @@ func (m *WorkerRecord) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
i -= len(m.unknownFields) i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields) copy(dAtA[i:], m.unknownFields)
} }
if len(m.CDIDevices) > 0 {
for iNdEx := len(m.CDIDevices) - 1; iNdEx >= 0; iNdEx-- {
size, err := m.CDIDevices[iNdEx].MarshalToSizedBufferVT(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = protohelpers.EncodeVarint(dAtA, i, uint64(size))
i--
dAtA[i] = 0x32
}
}
if m.BuildkitVersion != nil { if m.BuildkitVersion != nil {
size, err := m.BuildkitVersion.MarshalToSizedBufferVT(dAtA[:i]) size, err := m.BuildkitVersion.MarshalToSizedBufferVT(dAtA[:i])
if err != nil { if err != nil {
@@ -456,6 +555,85 @@ func (m *BuildkitVersion) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
return len(dAtA) - i, nil return len(dAtA) - i, nil
} }
func (m *CDIDevice) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
}
size := m.SizeVT()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *CDIDevice) MarshalToVT(dAtA []byte) (int, error) {
size := m.SizeVT()
return m.MarshalToSizedBufferVT(dAtA[:size])
}
func (m *CDIDevice) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
i := len(dAtA)
_ = i
var l int
_ = l
if m.unknownFields != nil {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if m.OnDemand {
i--
if m.OnDemand {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x20
}
if len(m.Annotations) > 0 {
for k := range m.Annotations {
v := m.Annotations[k]
baseI := i
i -= len(v)
copy(dAtA[i:], v)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(v)))
i--
dAtA[i] = 0x12
i -= len(k)
copy(dAtA[i:], k)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))
i--
dAtA[i] = 0xa
i = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))
i--
dAtA[i] = 0x1a
}
}
if m.AutoAllow {
i--
if m.AutoAllow {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x10
}
if len(m.Name) > 0 {
i -= len(m.Name)
copy(dAtA[i:], m.Name)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *WorkerRecord) SizeVT() (n int) { func (m *WorkerRecord) SizeVT() (n int) {
if m == nil { if m == nil {
return 0 return 0
@@ -490,6 +668,12 @@ func (m *WorkerRecord) SizeVT() (n int) {
l = m.BuildkitVersion.SizeVT() l = m.BuildkitVersion.SizeVT()
n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
} }
if len(m.CDIDevices) > 0 {
for _, e := range m.CDIDevices {
l = e.SizeVT()
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
}
n += len(m.unknownFields) n += len(m.unknownFields)
return n return n
} }
@@ -547,6 +731,34 @@ func (m *BuildkitVersion) SizeVT() (n int) {
return n return n
} }
func (m *CDIDevice) SizeVT() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Name)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
if m.AutoAllow {
n += 2
}
if len(m.Annotations) > 0 {
for k, v := range m.Annotations {
_ = k
_ = v
mapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + 1 + len(v) + protohelpers.SizeOfVarint(uint64(len(v)))
n += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))
}
}
if m.OnDemand {
n += 2
}
n += len(m.unknownFields)
return n
}
func (m *WorkerRecord) UnmarshalVT(dAtA []byte) error { func (m *WorkerRecord) UnmarshalVT(dAtA []byte) error {
l := len(dAtA) l := len(dAtA)
iNdEx := 0 iNdEx := 0
@@ -839,6 +1051,40 @@ func (m *WorkerRecord) UnmarshalVT(dAtA []byte) error {
return err return err
} }
iNdEx = postIndex iNdEx = postIndex
case 6:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CDIDevices", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.CDIDevices = append(m.CDIDevices, &CDIDevice{})
if err := m.CDIDevices[len(m.CDIDevices)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:]) skippy, err := protohelpers.Skip(dAtA[iNdEx:])
@@ -1187,3 +1433,253 @@ func (m *BuildkitVersion) UnmarshalVT(dAtA []byte) error {
} }
return nil return nil
} }
func (m *CDIDevice) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: CDIDevice: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: CDIDevice: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field AutoAllow", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.AutoAllow = bool(v != 0)
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Annotations", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Annotations == nil {
m.Annotations = make(map[string]string)
}
var mapkey string
var mapvalue string
for iNdEx < postIndex {
entryPreIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
if fieldNum == 1 {
var stringLenmapkey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapkey |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapkey := int(stringLenmapkey)
if intStringLenmapkey < 0 {
return protohelpers.ErrInvalidLength
}
postStringIndexmapkey := iNdEx + intStringLenmapkey
if postStringIndexmapkey < 0 {
return protohelpers.ErrInvalidLength
}
if postStringIndexmapkey > l {
return io.ErrUnexpectedEOF
}
mapkey = string(dAtA[iNdEx:postStringIndexmapkey])
iNdEx = postStringIndexmapkey
} else if fieldNum == 2 {
var stringLenmapvalue uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapvalue |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapvalue := int(stringLenmapvalue)
if intStringLenmapvalue < 0 {
return protohelpers.ErrInvalidLength
}
postStringIndexmapvalue := iNdEx + intStringLenmapvalue
if postStringIndexmapvalue < 0 {
return protohelpers.ErrInvalidLength
}
if postStringIndexmapvalue > l {
return io.ErrUnexpectedEOF
}
mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])
iNdEx = postStringIndexmapvalue
} else {
iNdEx = entryPreIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > postIndex {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
m.Annotations[mapkey] = mapvalue
iNdEx = postIndex
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field OnDemand", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.OnDemand = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}

View File

@@ -18,6 +18,13 @@ type BuildkitVersion struct {
Revision string `json:"revision"` Revision string `json:"revision"`
} }
type CDIDevice struct {
Name string `json:"name"`
AutoAllow bool `json:"autoAllow"`
Annotations map[string]string `json:"annotations"`
OnDemand bool `json:"onDemand"`
}
func (c *Client) Info(ctx context.Context) (*Info, error) { func (c *Client) Info(ctx context.Context) (*Info, error) {
res, err := c.ControlClient().Info(ctx, &controlapi.InfoRequest{}) res, err := c.ControlClient().Info(ctx, &controlapi.InfoRequest{})
if err != nil { if err != nil {
@@ -38,3 +45,16 @@ func fromAPIBuildkitVersion(in *apitypes.BuildkitVersion) BuildkitVersion {
Revision: in.Revision, Revision: in.Revision,
} }
} }
func fromAPICDIDevices(in []*apitypes.CDIDevice) []CDIDevice {
var out []CDIDevice
for _, d := range in {
out = append(out, CDIDevice{
Name: d.Name,
AutoAllow: d.AutoAllow,
Annotations: d.Annotations,
OnDemand: d.OnDemand,
})
}
return out
}

View File

@@ -60,6 +60,7 @@ type ExecOp struct {
isValidated bool isValidated bool
secrets []SecretInfo secrets []SecretInfo
ssh []SSHInfo ssh []SSHInfo
cdiDevices []CDIDeviceInfo
} }
func (e *ExecOp) AddMount(target string, source Output, opt ...MountOption) Output { func (e *ExecOp) AddMount(target string, source Output, opt ...MountOption) Output {
@@ -266,6 +267,7 @@ func (e *ExecOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, []
Network: network, Network: network,
Security: security, Security: security,
} }
if network != NetModeSandbox { if network != NetModeSandbox {
addCap(&e.constraints, pb.CapExecMetaNetwork) addCap(&e.constraints, pb.CapExecMetaNetwork)
} }
@@ -321,6 +323,18 @@ func (e *ExecOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, []
addCap(&e.constraints, pb.CapExecMountSSH) addCap(&e.constraints, pb.CapExecMountSSH)
} }
if len(e.cdiDevices) > 0 {
addCap(&e.constraints, pb.CapExecMetaCDI)
cd := make([]*pb.CDIDevice, len(e.cdiDevices))
for i, d := range e.cdiDevices {
cd[i] = &pb.CDIDevice{
Name: d.Name,
Optional: d.Optional,
}
}
peo.CdiDevices = cd
}
if e.constraints.Platform == nil { if e.constraints.Platform == nil {
p, err := getPlatform(e.base)(ctx, c) p, err := getPlatform(e.base)(ctx, c)
if err != nil { if err != nil {
@@ -624,6 +638,41 @@ func AddUlimit(name UlimitName, soft int64, hard int64) RunOption {
}) })
} }
func AddCDIDevice(opts ...CDIDeviceOption) RunOption {
return runOptionFunc(func(ei *ExecInfo) {
c := &CDIDeviceInfo{}
for _, opt := range opts {
opt.SetCDIDeviceOption(c)
}
ei.CDIDevices = append(ei.CDIDevices, *c)
})
}
type CDIDeviceOption interface {
SetCDIDeviceOption(*CDIDeviceInfo)
}
type cdiDeviceOptionFunc func(*CDIDeviceInfo)
func (fn cdiDeviceOptionFunc) SetCDIDeviceOption(ci *CDIDeviceInfo) {
fn(ci)
}
func CDIDeviceName(name string) CDIDeviceOption {
return cdiDeviceOptionFunc(func(ci *CDIDeviceInfo) {
ci.Name = name
})
}
var CDIDeviceOptional = cdiDeviceOptionFunc(func(ci *CDIDeviceInfo) {
ci.Optional = true
})
type CDIDeviceInfo struct {
Name string
Optional bool
}
func ValidExitCodes(codes ...int) RunOption { func ValidExitCodes(codes ...int) RunOption {
return runOptionFunc(func(ei *ExecInfo) { return runOptionFunc(func(ei *ExecInfo) {
ei.State = validExitCodes(codes...)(ei.State) ei.State = validExitCodes(codes...)(ei.State)
@@ -815,6 +864,7 @@ type ExecInfo struct {
ProxyEnv *ProxyEnv ProxyEnv *ProxyEnv
Secrets []SecretInfo Secrets []SecretInfo
SSH []SSHInfo SSH []SSHInfo
CDIDevices []CDIDeviceInfo
} }
type MountInfo struct { type MountInfo struct {

View File

@@ -295,6 +295,7 @@ func (s State) Run(ro ...RunOption) ExecState {
} }
exec.secrets = ei.Secrets exec.secrets = ei.Secrets
exec.ssh = ei.SSH exec.ssh = ei.SSH
exec.cdiDevices = ei.CDIDevices
return ExecState{ return ExecState{
State: s.WithOutput(exec.Output()), State: s.WithOutput(exec.Output()),

View File

@@ -18,6 +18,7 @@ type WorkerInfo struct {
Platforms []ocispecs.Platform `json:"platforms"` Platforms []ocispecs.Platform `json:"platforms"`
GCPolicy []PruneInfo `json:"gcPolicy"` GCPolicy []PruneInfo `json:"gcPolicy"`
BuildkitVersion BuildkitVersion `json:"buildkitVersion"` BuildkitVersion BuildkitVersion `json:"buildkitVersion"`
CDIDevices []CDIDevice `json:"cdiDevices"`
} }
// ListWorkers lists all active workers // ListWorkers lists all active workers
@@ -42,6 +43,7 @@ func (c *Client) ListWorkers(ctx context.Context, opts ...ListWorkersOption) ([]
Platforms: pb.ToSpecPlatforms(w.Platforms), Platforms: pb.ToSpecPlatforms(w.Platforms),
GCPolicy: fromAPIGCPolicy(w.GCPolicy), GCPolicy: fromAPIGCPolicy(w.GCPolicy),
BuildkitVersion: fromAPIBuildkitVersion(w.BuildkitVersion), BuildkitVersion: fromAPIBuildkitVersion(w.BuildkitVersion),
CDIDevices: fromAPICDIDevices(w.CDIDevices),
}) })
} }

View File

@@ -23,6 +23,8 @@ type Config struct {
OTEL OTELConfig `toml:"otel"` OTEL OTELConfig `toml:"otel"`
CDI CDIConfig `toml:"cdi"`
Workers struct { Workers struct {
OCI OCIConfig `toml:"oci"` OCI OCIConfig `toml:"oci"`
Containerd ContainerdConfig `toml:"containerd"` Containerd ContainerdConfig `toml:"containerd"`
@@ -74,6 +76,11 @@ type OTELConfig struct {
SocketPath string `toml:"socketPath"` SocketPath string `toml:"socketPath"`
} }
type CDIConfig struct {
Disabled *bool `toml:"disabled"`
SpecDirs []string `toml:"specDirs"`
}
type GCConfig struct { type GCConfig struct {
GC *bool `toml:"gc"` GC *bool `toml:"gc"`
// Deprecated: use GCReservedSpace instead // Deprecated: use GCReservedSpace instead

View File

@@ -18,7 +18,6 @@ import (
"github.com/moby/buildkit/frontend/gateway/client" "github.com/moby/buildkit/frontend/gateway/client"
"github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/util/flightcontrol" "github.com/moby/buildkit/util/flightcontrol"
dockerspec "github.com/moby/docker-image-spec/specs-go/v1"
"github.com/moby/patternmatcher/ignorefile" "github.com/moby/patternmatcher/ignorefile"
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1" ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
@@ -67,6 +66,7 @@ type Config struct {
ShmSize int64 ShmSize int64
Target string Target string
Ulimits []*pb.Ulimit Ulimits []*pb.Ulimit
Devices []*pb.CDIDevice
LinterConfig *linter.Config LinterConfig *linter.Config
CacheImports []client.CacheOptionsEntry CacheImports []client.CacheOptionsEntry
@@ -452,10 +452,10 @@ func (bc *Client) MainContext(ctx context.Context, opts ...llb.LocalOption) (*ll
return &st, nil return &st, nil
} }
func (bc *Client) NamedContext(ctx context.Context, name string, opt ContextOpt) (*llb.State, *dockerspec.DockerOCIImage, error) { func (bc *Client) NamedContext(name string, opt ContextOpt) (*NamedContext, error) {
named, err := reference.ParseNormalizedNamed(name) named, err := reference.ParseNormalizedNamed(name)
if err != nil { if err != nil {
return nil, nil, errors.Wrapf(err, "invalid context name %s", name) return nil, errors.Wrapf(err, "invalid context name %s", name)
} }
name = strings.TrimSuffix(reference.FamiliarString(named), ":latest") name = strings.TrimSuffix(reference.FamiliarString(named), ":latest")
@@ -464,11 +464,11 @@ func (bc *Client) NamedContext(ctx context.Context, name string, opt ContextOpt)
pp = *opt.Platform pp = *opt.Platform
} }
pname := name + "::" + platforms.FormatAll(platforms.Normalize(pp)) pname := name + "::" + platforms.FormatAll(platforms.Normalize(pp))
st, img, err := bc.namedContext(ctx, name, pname, opt) nc, err := bc.namedContext(name, pname, opt)
if err != nil || st != nil { if err != nil || nc != nil {
return st, img, err return nc, err
} }
return bc.namedContext(ctx, name, name, opt) return bc.namedContext(name, name, opt)
} }
func (bc *Client) IsNoCache(name string) bool { func (bc *Client) IsNoCache(name string) bool {

View File

@@ -26,31 +26,51 @@ const (
maxContextRecursion = 10 maxContextRecursion = 10
) )
func (bc *Client) namedContext(ctx context.Context, name string, nameWithPlatform string, opt ContextOpt) (*llb.State, *dockerspec.DockerOCIImage, error) { type NamedContext struct {
return bc.namedContextRecursive(ctx, name, nameWithPlatform, opt, 0) input string
bc *Client
name string
nameWithPlatform string
opt ContextOpt
} }
func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWithPlatform string, opt ContextOpt, count int) (*llb.State, *dockerspec.DockerOCIImage, error) { func (bc *Client) namedContext(name string, nameWithPlatform string, opt ContextOpt) (*NamedContext, error) {
opts := bc.bopts.Opts opts := bc.bopts.Opts
contextKey := contextPrefix + nameWithPlatform contextKey := contextPrefix + nameWithPlatform
v, ok := opts[contextKey] v, ok := opts[contextKey]
if !ok { if !ok {
return nil, nil, nil return nil, nil
} }
return &NamedContext{
input: v,
bc: bc,
name: name,
nameWithPlatform: nameWithPlatform,
opt: opt,
}, nil
}
func (nc *NamedContext) Load(ctx context.Context) (*llb.State, *dockerspec.DockerOCIImage, error) {
return nc.load(ctx, 0)
}
func (nc *NamedContext) load(ctx context.Context, count int) (*llb.State, *dockerspec.DockerOCIImage, error) {
opt := nc.opt
if count > maxContextRecursion { if count > maxContextRecursion {
return nil, nil, errors.New("context recursion limit exceeded; this may indicate a cycle in the provided source policies: " + v) return nil, nil, errors.New("context recursion limit exceeded; this may indicate a cycle in the provided source policies: " + nc.input)
} }
vv := strings.SplitN(v, ":", 2) vv := strings.SplitN(nc.input, ":", 2)
if len(vv) != 2 { if len(vv) != 2 {
return nil, nil, errors.Errorf("invalid context specifier %s for %s", v, nameWithPlatform) return nil, nil, errors.Errorf("invalid context specifier %s for %s", nc.input, nc.nameWithPlatform)
} }
// allow git@ without protocol for SSH URLs for backwards compatibility // allow git@ without protocol for SSH URLs for backwards compatibility
if strings.HasPrefix(vv[0], "git@") { if strings.HasPrefix(vv[0], "git@") {
vv[0] = "git" vv[0] = "git"
} }
switch vv[0] { switch vv[0] {
case "docker-image": case "docker-image":
ref := strings.TrimPrefix(vv[1], "//") ref := strings.TrimPrefix(vv[1], "//")
@@ -60,7 +80,7 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi
} }
imgOpt := []llb.ImageOption{ imgOpt := []llb.ImageOption{
llb.WithCustomName("[context " + nameWithPlatform + "] " + ref), llb.WithCustomName("[context " + nc.nameWithPlatform + "] " + ref),
} }
if opt.Platform != nil { if opt.Platform != nil {
imgOpt = append(imgOpt, llb.Platform(*opt.Platform)) imgOpt = append(imgOpt, llb.Platform(*opt.Platform))
@@ -73,8 +93,8 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi
named = reference.TagNameOnly(named) named = reference.TagNameOnly(named)
ref, dgst, data, err := bc.client.ResolveImageConfig(ctx, named.String(), sourceresolver.Opt{ ref, dgst, data, err := nc.bc.client.ResolveImageConfig(ctx, named.String(), sourceresolver.Opt{
LogName: fmt.Sprintf("[context %s] load metadata for %s", nameWithPlatform, ref), LogName: fmt.Sprintf("[context %s] load metadata for %s", nc.nameWithPlatform, ref),
Platform: opt.Platform, Platform: opt.Platform,
ImageOpt: &sourceresolver.ResolveImageOpt{ ImageOpt: &sourceresolver.ResolveImageOpt{
ResolveMode: opt.ResolveMode, ResolveMode: opt.ResolveMode,
@@ -88,8 +108,16 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi
return nil, nil, errors.Errorf("could not parse ref: %s", e.Updated) return nil, nil, errors.Errorf("could not parse ref: %s", e.Updated)
} }
bc.bopts.Opts[contextKey] = before + ":" + after nc.bc.bopts.Opts[contextPrefix+nc.nameWithPlatform] = before + ":" + after
return bc.namedContextRecursive(ctx, name, nameWithPlatform, opt, count+1)
ncnew, err := nc.bc.namedContext(nc.name, nc.nameWithPlatform, nc.opt)
if err != nil {
return nil, nil, err
}
if ncnew == nil {
return nil, nil, nil
}
return ncnew.load(ctx, count+1)
} }
return nil, nil, err return nil, nil, err
} }
@@ -110,15 +138,15 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi
} }
return &st, &img, nil return &st, &img, nil
case "git": case "git":
st, ok := DetectGitContext(v, true) st, ok := DetectGitContext(nc.input, true)
if !ok { if !ok {
return nil, nil, errors.Errorf("invalid git context %s", v) return nil, nil, errors.Errorf("invalid git context %s", nc.input)
} }
return st, nil, nil return st, nil, nil
case "http", "https": case "http", "https":
st, ok := DetectGitContext(v, true) st, ok := DetectGitContext(nc.input, true)
if !ok { if !ok {
httpst := llb.HTTP(v, llb.WithCustomName("[context "+nameWithPlatform+"] "+v)) httpst := llb.HTTP(nc.input, llb.WithCustomName("[context "+nc.nameWithPlatform+"] "+nc.input))
st = &httpst st = &httpst
} }
return st, nil, nil return st, nil, nil
@@ -139,21 +167,21 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi
// for the dummy ref primarily used in log messages, we can use the // for the dummy ref primarily used in log messages, we can use the
// original name, since the store key may not be significant // original name, since the store key may not be significant
dummyRef, err := reference.ParseNormalizedNamed(name) dummyRef, err := reference.ParseNormalizedNamed(nc.name)
if err != nil { if err != nil {
return nil, nil, errors.Wrapf(err, "could not parse oci-layout reference %q", name) return nil, nil, errors.Wrapf(err, "could not parse oci-layout reference %q", nc.name)
} }
dummyRef, err = reference.WithDigest(dummyRef, dgstd.Digest()) dummyRef, err = reference.WithDigest(dummyRef, dgstd.Digest())
if err != nil { if err != nil {
return nil, nil, errors.Wrapf(err, "could not wrap %q with digest", name) return nil, nil, errors.Wrapf(err, "could not wrap %q with digest", nc.name)
} }
_, dgst, data, err := bc.client.ResolveImageConfig(ctx, dummyRef.String(), sourceresolver.Opt{ _, dgst, data, err := nc.bc.client.ResolveImageConfig(ctx, dummyRef.String(), sourceresolver.Opt{
LogName: fmt.Sprintf("[context %s] load metadata for %s", nameWithPlatform, dummyRef.String()), LogName: fmt.Sprintf("[context %s] load metadata for %s", nc.nameWithPlatform, dummyRef.String()),
Platform: opt.Platform, Platform: opt.Platform,
OCILayoutOpt: &sourceresolver.ResolveOCILayoutOpt{ OCILayoutOpt: &sourceresolver.ResolveOCILayoutOpt{
Store: sourceresolver.ResolveImageConfigOptStore{ Store: sourceresolver.ResolveImageConfigOptStore{
SessionID: bc.bopts.SessionID, SessionID: nc.bc.bopts.SessionID,
StoreID: named.Name(), StoreID: named.Name(),
}, },
}, },
@@ -168,8 +196,8 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi
} }
ociOpt := []llb.OCILayoutOption{ ociOpt := []llb.OCILayoutOption{
llb.WithCustomName("[context " + nameWithPlatform + "] OCI load from client"), llb.WithCustomName("[context " + nc.nameWithPlatform + "] OCI load from client"),
llb.OCIStore(bc.bopts.SessionID, named.Name()), llb.OCIStore(nc.bc.bopts.SessionID, named.Name()),
} }
if opt.Platform != nil { if opt.Platform != nil {
ociOpt = append(ociOpt, llb.Platform(*opt.Platform)) ociOpt = append(ociOpt, llb.Platform(*opt.Platform))
@@ -187,22 +215,22 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi
} }
return &st, &img, nil return &st, &img, nil
case "local": case "local":
sessionID := bc.bopts.SessionID sessionID := nc.bc.bopts.SessionID
if v, ok := bc.localsSessionIDs[vv[1]]; ok { if v, ok := nc.bc.localsSessionIDs[vv[1]]; ok {
sessionID = v sessionID = v
} }
st := llb.Local(vv[1], st := llb.Local(vv[1],
llb.SessionID(sessionID), llb.SessionID(sessionID),
llb.FollowPaths([]string{DefaultDockerignoreName}), llb.FollowPaths([]string{DefaultDockerignoreName}),
llb.SharedKeyHint("context:"+nameWithPlatform+"-"+DefaultDockerignoreName), llb.SharedKeyHint("context:"+nc.nameWithPlatform+"-"+DefaultDockerignoreName),
llb.WithCustomName("[context "+nameWithPlatform+"] load "+DefaultDockerignoreName), llb.WithCustomName("[context "+nc.nameWithPlatform+"] load "+DefaultDockerignoreName),
llb.Differ(llb.DiffNone, false), llb.Differ(llb.DiffNone, false),
) )
def, err := st.Marshal(ctx) def, err := st.Marshal(ctx)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
res, err := bc.client.Solve(ctx, client.SolveRequest{ res, err := nc.bc.client.Solve(ctx, client.SolveRequest{
Evaluate: true, Evaluate: true,
Definition: def.ToPB(), Definition: def.ToPB(),
}) })
@@ -229,7 +257,7 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi
localOutput := &asyncLocalOutput{ localOutput := &asyncLocalOutput{
name: vv[1], name: vv[1],
nameWithPlatform: nameWithPlatform, nameWithPlatform: nc.nameWithPlatform,
sessionID: sessionID, sessionID: sessionID,
excludes: excludes, excludes: excludes,
extraOpts: opt.AsyncLocalOpts, extraOpts: opt.AsyncLocalOpts,
@@ -237,15 +265,15 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi
st = llb.NewState(localOutput) st = llb.NewState(localOutput)
return &st, nil, nil return &st, nil, nil
case "input": case "input":
inputs, err := bc.client.Inputs(ctx) inputs, err := nc.bc.client.Inputs(ctx)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
st, ok := inputs[vv[1]] st, ok := inputs[vv[1]]
if !ok { if !ok {
return nil, nil, errors.Errorf("invalid input %s for %s", vv[1], nameWithPlatform) return nil, nil, errors.Errorf("invalid input %s for %s", vv[1], nc.nameWithPlatform)
} }
md, ok := opts[inputMetadataPrefix+vv[1]] md, ok := nc.bc.bopts.Opts[inputMetadataPrefix+vv[1]]
if ok { if ok {
m := make(map[string][]byte) m := make(map[string][]byte)
if err := json.Unmarshal([]byte(md), &m); err != nil { if err := json.Unmarshal([]byte(md), &m); err != nil {
@@ -258,14 +286,14 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi
return nil, nil, err return nil, nil, err
} }
if err := json.Unmarshal(dtic, &img); err != nil { if err := json.Unmarshal(dtic, &img); err != nil {
return nil, nil, errors.Wrapf(err, "failed to parse image config for %s", nameWithPlatform) return nil, nil, errors.Wrapf(err, "failed to parse image config for %s", nc.nameWithPlatform)
} }
} }
return &st, img, nil return &st, img, nil
} }
return &st, nil, nil return &st, nil, nil
default: default:
return nil, nil, errors.Errorf("unsupported context source %s for %s", vv[0], nameWithPlatform) return nil, nil, errors.Errorf("unsupported context source %s for %s", vv[0], nc.nameWithPlatform)
} }
} }

View File

@@ -38,18 +38,43 @@ const (
dockerHubRegistryHost = "registry-1.docker.io" dockerHubRegistryHost = "registry-1.docker.io"
) )
func NewDockerAuthProvider(cfg *configfile.ConfigFile, tlsConfigs map[string]*AuthTLSConfig) session.Attachable { type DockerAuthProviderConfig struct {
// ConfigFile is the docker config file
ConfigFile *configfile.ConfigFile
// TLSConfigs is a map of host to TLS config
TLSConfigs map[string]*AuthTLSConfig
// ExpireCachedAuth is a function that returns true auth config should be refreshed
// instead of using a pre-cached result.
// If nil then the cached result will expire after 10 minutes.
// The function is called with the time the cached auth config was created
// and the server URL the auth config is for.
ExpireCachedAuth func(created time.Time, serverURL string) bool
}
type authConfigCacheEntry struct {
Created time.Time
Auth *types.AuthConfig
}
func NewDockerAuthProvider(cfg DockerAuthProviderConfig) session.Attachable {
if cfg.ExpireCachedAuth == nil {
cfg.ExpireCachedAuth = func(created time.Time, _ string) bool {
return time.Since(created) > 10*time.Minute
}
}
return &authProvider{ return &authProvider{
authConfigCache: map[string]*types.AuthConfig{}, authConfigCache: map[string]authConfigCacheEntry{},
config: cfg, expireAc: cfg.ExpireCachedAuth,
config: cfg.ConfigFile,
seeds: &tokenSeeds{dir: config.Dir()}, seeds: &tokenSeeds{dir: config.Dir()},
loggerCache: map[string]struct{}{}, loggerCache: map[string]struct{}{},
tlsConfigs: tlsConfigs, tlsConfigs: cfg.TLSConfigs,
} }
} }
type authProvider struct { type authProvider struct {
authConfigCache map[string]*types.AuthConfig authConfigCache map[string]authConfigCacheEntry
expireAc func(time.Time, string) bool
config *configfile.ConfigFile config *configfile.ConfigFile
seeds *tokenSeeds seeds *tokenSeeds
logger progresswriter.Logger logger progresswriter.Logger
@@ -247,17 +272,25 @@ func (ap *authProvider) getAuthConfig(ctx context.Context, host string) (*types.
host = dockerHubConfigfileKey host = dockerHubConfigfileKey
} }
if _, exists := ap.authConfigCache[host]; !exists { entry, exists := ap.authConfigCache[host]
if exists && !ap.expireAc(entry.Created, host) {
return entry.Auth, nil
}
span, _ := tracing.StartSpan(ctx, fmt.Sprintf("load credentials for %s", host)) span, _ := tracing.StartSpan(ctx, fmt.Sprintf("load credentials for %s", host))
ac, err := ap.config.GetAuthConfig(host) ac, err := ap.config.GetAuthConfig(host)
tracing.FinishWithError(span, err) tracing.FinishWithError(span, err)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ap.authConfigCache[host] = &ac entry = authConfigCacheEntry{
Created: time.Now(),
Auth: &ac,
} }
return ap.authConfigCache[host], nil ap.authConfigCache[host] = entry
return entry.Auth, nil
} }
func (ap *authProvider) getAuthorityKey(ctx context.Context, host string, salt []byte) (ed25519.PrivateKey, error) { func (ap *authProvider) getAuthorityKey(ctx context.Context, host string, salt []byte) (ed25519.PrivateKey, error) {

View File

@@ -47,6 +47,7 @@ const (
CapExecMetaSecurityDeviceWhitelistV1 apicaps.CapID = "exec.meta.security.devices.v1" CapExecMetaSecurityDeviceWhitelistV1 apicaps.CapID = "exec.meta.security.devices.v1"
CapExecMetaSetsDefaultPath apicaps.CapID = "exec.meta.setsdefaultpath" CapExecMetaSetsDefaultPath apicaps.CapID = "exec.meta.setsdefaultpath"
CapExecMetaUlimit apicaps.CapID = "exec.meta.ulimit" CapExecMetaUlimit apicaps.CapID = "exec.meta.ulimit"
CapExecMetaCDI apicaps.CapID = "exec.meta.cdi"
CapExecMetaRemoveMountStubsRecursive apicaps.CapID = "exec.meta.removemountstubs.recursive" CapExecMetaRemoveMountStubsRecursive apicaps.CapID = "exec.meta.removemountstubs.recursive"
CapExecMountBind apicaps.CapID = "exec.mount.bind" CapExecMountBind apicaps.CapID = "exec.mount.bind"
CapExecMountBindReadWriteNoOutput apicaps.CapID = "exec.mount.bind.readwrite-nooutput" CapExecMountBindReadWriteNoOutput apicaps.CapID = "exec.mount.bind.readwrite-nooutput"
@@ -96,6 +97,9 @@ const (
// GC/Prune controls allow MinFreeSpace and MaxUsedSpace to be set // GC/Prune controls allow MinFreeSpace and MaxUsedSpace to be set
CapGCFreeSpaceFilter apicaps.CapID = "gc.freespacefilter" CapGCFreeSpaceFilter apicaps.CapID = "gc.freespacefilter"
// ListenBuildHistory requests support server-side filters
CapHistoryFilters apicaps.CapID = "history.filter"
) )
func init() { func init() {
@@ -291,6 +295,12 @@ func init() {
Status: apicaps.CapStatusExperimental, Status: apicaps.CapStatusExperimental,
}) })
Caps.Init(apicaps.Cap{
ID: CapExecMetaCDI,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{ Caps.Init(apicaps.Cap{
ID: CapExecMountBind, ID: CapExecMountBind,
Enabled: true, Enabled: true,
@@ -453,7 +463,7 @@ func init() {
Caps.Init(apicaps.Cap{ Caps.Init(apicaps.Cap{
ID: CapRemoteCacheAzBlob, ID: CapRemoteCacheAzBlob,
Enabled: true, Enabled: false,
Status: apicaps.CapStatusExperimental, Status: apicaps.CapStatusExperimental,
}) })
@@ -505,4 +515,10 @@ func init() {
Enabled: true, Enabled: true,
Status: apicaps.CapStatusExperimental, Status: apicaps.CapStatusExperimental,
}) })
Caps.Init(apicaps.Cap{
ID: CapHistoryFilters,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
} }

File diff suppressed because it is too large Load Diff

View File

@@ -47,6 +47,7 @@ message ExecOp {
NetMode network = 3; NetMode network = 3;
SecurityMode security = 4; SecurityMode security = 4;
repeated SecretEnv secretenv = 5; repeated SecretEnv secretenv = 5;
repeated CDIDevice cdiDevices = 6;
} }
// Meta is a set of arguments for ExecOp. // Meta is a set of arguments for ExecOp.
@@ -95,6 +96,15 @@ message SecretEnv {
bool optional = 3; bool optional = 3;
} }
// CDIDevice specifies a CDI device information.
message CDIDevice {
// Fully qualified CDI device name (e.g., vendor.com/gpu=gpudevice1)
// https://github.com/cncf-tags/container-device-interface/blob/main/SPEC.md
string name = 1;
// Optional defines if CDI device is required.
bool optional = 2;
}
// Mount specifies how to mount an input Op as a filesystem. // Mount specifies how to mount an input Op as a filesystem.
message Mount { message Mount {
int64 input = 1; int64 input = 1;

View File

@@ -166,6 +166,13 @@ func (m *ExecOp) CloneVT() *ExecOp {
} }
r.Secretenv = tmpContainer r.Secretenv = tmpContainer
} }
if rhs := m.CdiDevices; rhs != nil {
tmpContainer := make([]*CDIDevice, len(rhs))
for k, v := range rhs {
tmpContainer[k] = v.CloneVT()
}
r.CdiDevices = tmpContainer
}
if len(m.unknownFields) > 0 { if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields)) r.unknownFields = make([]byte, len(m.unknownFields))
copy(r.unknownFields, m.unknownFields) copy(r.unknownFields, m.unknownFields)
@@ -284,6 +291,24 @@ func (m *SecretEnv) CloneMessageVT() proto.Message {
return m.CloneVT() return m.CloneVT()
} }
func (m *CDIDevice) CloneVT() *CDIDevice {
if m == nil {
return (*CDIDevice)(nil)
}
r := new(CDIDevice)
r.Name = m.Name
r.Optional = m.Optional
if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields))
copy(r.unknownFields, m.unknownFields)
}
return r
}
func (m *CDIDevice) CloneMessageVT() proto.Message {
return m.CloneVT()
}
func (m *Mount) CloneVT() *Mount { func (m *Mount) CloneVT() *Mount {
if m == nil { if m == nil {
return (*Mount)(nil) return (*Mount)(nil)
@@ -1429,6 +1454,23 @@ func (this *ExecOp) EqualVT(that *ExecOp) bool {
} }
} }
} }
if len(this.CdiDevices) != len(that.CdiDevices) {
return false
}
for i, vx := range this.CdiDevices {
vy := that.CdiDevices[i]
if p, q := vx, vy; p != q {
if p == nil {
p = &CDIDevice{}
}
if q == nil {
q = &CDIDevice{}
}
if !p.EqualVT(q) {
return false
}
}
}
return string(this.unknownFields) == string(that.unknownFields) return string(this.unknownFields) == string(that.unknownFields)
} }
@@ -1606,6 +1648,28 @@ func (this *SecretEnv) EqualMessageVT(thatMsg proto.Message) bool {
} }
return this.EqualVT(that) return this.EqualVT(that)
} }
func (this *CDIDevice) EqualVT(that *CDIDevice) bool {
if this == that {
return true
} else if this == nil || that == nil {
return false
}
if this.Name != that.Name {
return false
}
if this.Optional != that.Optional {
return false
}
return string(this.unknownFields) == string(that.unknownFields)
}
func (this *CDIDevice) EqualMessageVT(thatMsg proto.Message) bool {
that, ok := thatMsg.(*CDIDevice)
if !ok {
return false
}
return this.EqualVT(that)
}
func (this *Mount) EqualVT(that *Mount) bool { func (this *Mount) EqualVT(that *Mount) bool {
if this == that { if this == that {
return true return true
@@ -3220,6 +3284,18 @@ func (m *ExecOp) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
i -= len(m.unknownFields) i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields) copy(dAtA[i:], m.unknownFields)
} }
if len(m.CdiDevices) > 0 {
for iNdEx := len(m.CdiDevices) - 1; iNdEx >= 0; iNdEx-- {
size, err := m.CdiDevices[iNdEx].MarshalToSizedBufferVT(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = protohelpers.EncodeVarint(dAtA, i, uint64(size))
i--
dAtA[i] = 0x32
}
}
if len(m.Secretenv) > 0 { if len(m.Secretenv) > 0 {
for iNdEx := len(m.Secretenv) - 1; iNdEx >= 0; iNdEx-- { for iNdEx := len(m.Secretenv) - 1; iNdEx >= 0; iNdEx-- {
size, err := m.Secretenv[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) size, err := m.Secretenv[iNdEx].MarshalToSizedBufferVT(dAtA[:i])
@@ -3565,6 +3641,56 @@ func (m *SecretEnv) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
return len(dAtA) - i, nil return len(dAtA) - i, nil
} }
func (m *CDIDevice) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
}
size := m.SizeVT()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *CDIDevice) MarshalToVT(dAtA []byte) (int, error) {
size := m.SizeVT()
return m.MarshalToSizedBufferVT(dAtA[:size])
}
func (m *CDIDevice) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
i := len(dAtA)
_ = i
var l int
_ = l
if m.unknownFields != nil {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if m.Optional {
i--
if m.Optional {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x10
}
if len(m.Name) > 0 {
i -= len(m.Name)
copy(dAtA[i:], m.Name)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *Mount) MarshalVT() (dAtA []byte, err error) { func (m *Mount) MarshalVT() (dAtA []byte, err error) {
if m == nil { if m == nil {
return nil, nil return nil, nil
@@ -6023,6 +6149,12 @@ func (m *ExecOp) SizeVT() (n int) {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
} }
} }
if len(m.CdiDevices) > 0 {
for _, e := range m.CdiDevices {
l = e.SizeVT()
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
}
n += len(m.unknownFields) n += len(m.unknownFields)
return n return n
} }
@@ -6150,6 +6282,23 @@ func (m *SecretEnv) SizeVT() (n int) {
return n return n
} }
func (m *CDIDevice) SizeVT() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Name)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
if m.Optional {
n += 2
}
n += len(m.unknownFields)
return n
}
func (m *Mount) SizeVT() (n int) { func (m *Mount) SizeVT() (n int) {
if m == nil { if m == nil {
return 0 return 0
@@ -7936,6 +8085,40 @@ func (m *ExecOp) UnmarshalVT(dAtA []byte) error {
return err return err
} }
iNdEx = postIndex iNdEx = postIndex
case 6:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CdiDevices", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.CdiDevices = append(m.CdiDevices, &CDIDevice{})
if err := m.CdiDevices[len(m.CdiDevices)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:]) skippy, err := protohelpers.Skip(dAtA[iNdEx:])
@@ -8772,6 +8955,109 @@ func (m *SecretEnv) UnmarshalVT(dAtA []byte) error {
} }
return nil return nil
} }
func (m *CDIDevice) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: CDIDevice: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: CDIDevice: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Optional", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.Optional = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *Mount) UnmarshalVT(dAtA []byte) error { func (m *Mount) UnmarshalVT(dAtA []byte) error {
l := len(dAtA) l := len(dAtA)
iNdEx := 0 iNdEx := 0

View File

@@ -17,6 +17,7 @@ const (
var ( var (
UserCNIConfigPath = filepath.Join(UserConfigDir(), "cni.json") UserCNIConfigPath = filepath.Join(UserConfigDir(), "cni.json")
CDISpecDirs = []string{"/etc/cdi", "/var/run/cdi", "/etc/buildkit/cdi"}
) )
// UserAddress typically returns /run/user/$UID/buildkit/buildkitd.sock // UserAddress typically returns /run/user/$UID/buildkit/buildkitd.sock

View File

@@ -18,6 +18,7 @@ var (
var ( var (
UserCNIConfigPath = DefaultCNIConfigPath UserCNIConfigPath = DefaultCNIConfigPath
CDISpecDirs []string
) )
func UserAddress() string { func UserAddress() string {

View File

@@ -16,12 +16,41 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func ProviderFromRef(ref string) (ocispecs.Descriptor, content.Provider, error) { type ResolveOpt struct {
Credentials func(string) (string, string, error)
}
type ResolveOptFunc func(*ResolveOpt)
func WithCredentials(c func(string) (string, string, error)) ResolveOptFunc {
return func(o *ResolveOpt) {
o.Credentials = func(host string) (string, string, error) {
if host == "registry-1.docker.io" {
host = "https://index.docker.io/v1/"
}
return c(host)
}
}
}
func ProviderFromRef(ref string, opts ...ResolveOptFunc) (ocispecs.Descriptor, content.Provider, error) {
headers := http.Header{} headers := http.Header{}
headers.Set("User-Agent", version.UserAgent()) headers.Set("User-Agent", version.UserAgent())
remote := docker.NewResolver(docker.ResolverOptions{
var ro ResolveOpt
for _, f := range opts {
f(&ro)
}
dro := docker.ResolverOptions{
Headers: headers, Headers: headers,
}) }
if ro.Credentials != nil {
dro.Hosts = docker.ConfigureDefaultRegistries(
docker.WithAuthorizer(docker.NewDockerAuthorizer(docker.WithAuthCreds(ro.Credentials))),
)
}
remote := docker.NewResolver(dro)
name, desc, err := remote.Resolve(context.TODO(), ref) name, desc, err := remote.Resolve(context.TODO(), ref)
if err != nil { if err != nil {

View File

@@ -19,6 +19,7 @@ import (
"github.com/containerd/containerd/v2/core/content" "github.com/containerd/containerd/v2/core/content"
"github.com/containerd/containerd/v2/core/remotes/docker" "github.com/containerd/containerd/v2/core/remotes/docker"
"github.com/docker/cli/cli/config"
"github.com/gofrs/flock" "github.com/gofrs/flock"
"github.com/moby/buildkit/util/appcontext" "github.com/moby/buildkit/util/appcontext"
"github.com/moby/buildkit/util/contentutil" "github.com/moby/buildkit/util/contentutil"
@@ -59,12 +60,14 @@ type Sandbox interface {
NewRegistry() (string, error) NewRegistry() (string, error)
Value(string) interface{} // chosen matrix value Value(string) interface{} // chosen matrix value
Name() string Name() string
CDISpecDir() string
} }
// BackendConfig is used to configure backends created by a worker. // BackendConfig is used to configure backends created by a worker.
type BackendConfig struct { type BackendConfig struct {
Logs map[string]*bytes.Buffer Logs map[string]*bytes.Buffer
DaemonConfig []ConfigUpdater DaemonConfig []ConfigUpdater
CDISpecDir string
} }
type Worker interface { type Worker interface {
@@ -257,7 +260,16 @@ func copyImagesLocal(t *testing.T, host string, images map[string]string) error
defer closer() defer closer()
} }
} else { } else {
desc, provider, err = contentutil.ProviderFromRef(from) dockerConfig := config.LoadDefaultConfigFile(os.Stderr)
desc, provider, err = contentutil.ProviderFromRef(from, contentutil.WithCredentials(
func(host string) (string, string, error) {
ac, err := dockerConfig.GetAuthConfig(host)
if err != nil {
return "", "", err
}
return ac.Username, ac.Password, nil
}))
if err != nil { if err != nil {
return err return err
} }

View File

@@ -31,6 +31,7 @@ type sandbox struct {
cleanup *MultiCloser cleanup *MultiCloser
mv matrixValue mv matrixValue
ctx context.Context ctx context.Context
cdiSpecDir string
name string name string
} }
@@ -42,6 +43,10 @@ func (sb *sandbox) Context() context.Context {
return sb.ctx return sb.ctx
} }
func (sb *sandbox) CDISpecDir() string {
return sb.cdiSpecDir
}
func (sb *sandbox) Logs() map[string]*bytes.Buffer { func (sb *sandbox) Logs() map[string]*bytes.Buffer {
return sb.logs return sb.logs
} }
@@ -110,6 +115,15 @@ func newSandbox(ctx context.Context, t *testing.T, w Worker, mirror string, mv m
} }
}() }()
cdiSpecDir, err := os.MkdirTemp("", "buildkit-integration-cdi")
if err != nil {
return nil, nil, errors.Wrap(err, "cannot create cdi spec dir")
}
deferF.Append(func() error {
return os.RemoveAll(cdiSpecDir)
})
cfg.CDISpecDir = cdiSpecDir
b, closer, err := w.New(ctx, cfg) b, closer, err := w.New(ctx, cfg)
if err != nil { if err != nil {
return nil, nil, errors.Wrap(err, "creating worker") return nil, nil, errors.Wrap(err, "creating worker")
@@ -144,6 +158,7 @@ func newSandbox(ctx context.Context, t *testing.T, w Worker, mirror string, mv m
cleanup: deferF, cleanup: deferF,
mv: mv, mv: mv,
ctx: ctx, ctx: ctx,
cdiSpecDir: cfg.CDISpecDir,
name: w.Name(), name: w.Name(),
}, cl, nil }, cl, nil
} }

View File

@@ -47,7 +47,12 @@ func (s *OCI) New(ctx context.Context, cfg *integration.BackendConfig) (integrat
return nil, nil, err return nil, nil, err
} }
// Include use of --oci-worker-labels to trigger https://github.com/moby/buildkit/pull/603 // Include use of --oci-worker-labels to trigger https://github.com/moby/buildkit/pull/603
buildkitdArgs := []string{"buildkitd", "--oci-worker=true", "--containerd-worker=false", "--oci-worker-gc=false", "--oci-worker-labels=org.mobyproject.buildkit.worker.sandbox=true"} buildkitdArgs := []string{"buildkitd",
"--oci-worker=true",
"--containerd-worker=false",
"--oci-worker-gc=false",
"--oci-worker-labels=org.mobyproject.buildkit.worker.sandbox=true",
}
if s.Snapshotter != "" { if s.Snapshotter != "" {
buildkitdArgs = append(buildkitdArgs, buildkitdArgs = append(buildkitdArgs,

View File

@@ -25,6 +25,20 @@ func (osp otelSocketPath) UpdateConfigFile(in string) string {
`, in, osp) `, in, osp)
} }
func withCDISpecDir(specDir string) integration.ConfigUpdater {
return cdiSpecDir(specDir)
}
type cdiSpecDir string
func (csd cdiSpecDir) UpdateConfigFile(in string) string {
return fmt.Sprintf(`%s
[cdi]
specDirs = [%q]
`, in, csd)
}
func runBuildkitd( func runBuildkitd(
conf *integration.BackendConfig, conf *integration.BackendConfig,
args []string, args []string,
@@ -61,7 +75,11 @@ func runBuildkitd(
deferF.Append(func() error { return os.RemoveAll(tmpdir) }) deferF.Append(func() error { return os.RemoveAll(tmpdir) })
cfgfile, err := integration.WriteConfig( cfgfile, err := integration.WriteConfig(
append(conf.DaemonConfig, withOTELSocketPath(getTraceSocketPath(tmpdir)))) append(conf.DaemonConfig,
withOTELSocketPath(getTraceSocketPath(tmpdir)),
withCDISpecDir(conf.CDISpecDir),
),
)
if err != nil { if err != nil {
return "", "", nil, err return "", "", nil, err
} }

View File

@@ -81,7 +81,7 @@ func setRawTerminal(fd uintptr) (*State, error) {
return makeRaw(fd) return makeRaw(fd)
} }
func setRawTerminalOutput(fd uintptr) (*State, error) { func setRawTerminalOutput(uintptr) (*State, error) {
return nil, nil return nil, nil
} }

34
vendor/github.com/tonistiigi/jaeger-ui-rest/Dockerfile generated vendored Normal file
View File

@@ -0,0 +1,34 @@
ARG NODE_VERSION=23.6
ARG ALPINE_VERSION=3.21
ARG GOLANG_VERSION=1.23
ARG JAEGERUI_VERSION=v1.66.0
FROM scratch AS jaegerui-src
ARG JAEGERUI_REPO=https://github.com/jaegertracing/jaeger-ui.git
ARG JAEGERUI_VERSION
ADD ${JAEGERUI_REPO}#${JAEGERUI_VERSION} /
FROM --platform=$BUILDPLATFORM node:${NODE_VERSION}-alpine${ALPINE_VERSION} AS builder
WORKDIR /work/jaeger-ui
COPY --from=jaegerui-src / .
RUN npm install
WORKDIR /work/jaeger-ui/packages/jaeger-ui
RUN NODE_ENVIRONMENT=production npm run build
# failed to find a way to avoid legacy build
RUN rm build/static/*-legacy* && rm build/static/*.png
FROM scratch AS jaegerui
COPY --from=builder /work/jaeger-ui/packages/jaeger-ui/build /
FROM alpine AS compressor
RUN --mount=target=/in,from=jaegerui <<EOT
set -ex
mkdir -p /out
cp -a /in/. /out
cd /out
find . -type f -exec sh -c 'gzip -9 -c "$1" > "$1.tmp" && mv "$1.tmp" "$1"' _ {} \;
# stop
EOT
FROM scratch AS jaegerui-compressed
COPY --from=compressor /out /

42
vendor/github.com/tonistiigi/jaeger-ui-rest/config.go generated vendored Normal file
View File

@@ -0,0 +1,42 @@
package jaegerui
import (
"bytes"
"encoding/json"
"slices"
)
type Menu struct {
Label string `json:"label"`
Items []MenuItem `json:"items"`
}
type MenuItem struct {
Label string `json:"label"`
URL string `json:"url"`
}
type Config struct {
Dependencies struct {
MenuEnabled bool `json:"menuEnabled"`
} `json:"dependencies"`
Monitor struct {
MenuEnabled bool `json:"menuEnabled"`
} `json:"monitor"`
ArchiveEnabled bool `json:"archiveEnabled"`
Menu []Menu `json:"menu"`
}
func (cfg Config) Inject(name string, dt []byte) ([]byte, bool) {
if name != "index.html" {
return dt, false
}
cfgData, err := json.Marshal(cfg)
if err != nil {
return dt, false
}
dt = bytes.Replace(dt, []byte("const JAEGER_CONFIG = DEFAULT_CONFIG;"), slices.Concat([]byte(`const JAEGER_CONFIG = `), cfgData, []byte(`;`)), 1)
return dt, true
}

View File

@@ -0,0 +1,117 @@
package decompress
import (
"bytes"
"compress/gzip"
"io"
"io/fs"
"path/filepath"
"sync"
)
type decompressFS struct {
fs.FS
mu sync.Mutex
data map[string][]byte
inject Injector
}
type Injector interface {
Inject(name string, dt []byte) ([]byte, bool)
}
func NewFS(fsys fs.FS, injector Injector) fs.FS {
return &decompressFS{
FS: fsys,
data: make(map[string][]byte),
inject: injector,
}
}
func (d *decompressFS) Open(name string) (fs.File, error) {
name = filepath.Clean(name)
f, err := d.FS.Open(name)
if err != nil {
return nil, err
}
d.mu.Lock()
defer d.mu.Unlock()
dt, ok := d.data[name]
if ok {
return &staticFile{
Reader: bytes.NewReader(dt),
f: f,
}, nil
}
fi, err := f.Stat()
if err != nil {
f.Close()
return nil, err
}
if fi.IsDir() {
return f, nil
}
gzReader, err := gzip.NewReader(f)
if err != nil {
f.Close()
return nil, err
}
buf := &bytes.Buffer{}
if _, err := io.Copy(buf, gzReader); err != nil {
f.Close()
return nil, err
}
dt = buf.Bytes()
if d.inject != nil {
newdt, ok := d.inject.Inject(name, dt)
if ok {
dt = newdt
}
}
d.data[name] = dt
return &staticFile{
Reader: bytes.NewReader(dt),
f: f,
}, nil
}
type staticFile struct {
*bytes.Reader
f fs.File
}
func (s *staticFile) Stat() (fs.FileInfo, error) {
fi, err := s.f.Stat()
if err != nil {
return nil, err
}
return &fileInfo{
FileInfo: fi,
size: int64(s.Len()),
}, nil
}
func (s *staticFile) Close() error {
return s.f.Close()
}
type fileInfo struct {
fs.FileInfo
size int64
}
func (f *fileInfo) Size() int64 {
return f.size
}
var _ fs.File = &staticFile{}

View File

@@ -0,0 +1,3 @@
target "public" {
output = ["./public"]
}

17
vendor/github.com/tonistiigi/jaeger-ui-rest/fs.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
package jaegerui
import (
"embed"
"io/fs"
"net/http"
"github.com/tonistiigi/jaeger-ui-rest/decompress"
)
//go:embed public
var staticFiles embed.FS
func FS(cfg Config) http.FileSystem {
files, _ := fs.Sub(staticFiles, "public")
return http.FS(decompress.NewFS(files, cfg))
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,3 @@
### jaeger-ui-rest
[Jaeger UI](https://github.com/jaegertracing/jaeger-ui) server with only the UI component and simple REST API for loading pregenerated JSON traces.

172
vendor/github.com/tonistiigi/jaeger-ui-rest/server.go generated vendored Normal file
View File

@@ -0,0 +1,172 @@
package jaegerui
import (
"bytes"
"encoding/json"
"io"
"net"
"net/http"
"os"
"strings"
"sync"
"github.com/pkg/errors"
)
func NewServer(cfg Config) *Server {
mux := &http.ServeMux{}
s := &Server{
config: cfg,
server: &http.Server{
Handler: mux,
},
}
fsHandler := http.FileServer(FS(cfg))
mux.HandleFunc("GET /api/services", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`{"data": [], "total": 0}`))
})
mux.HandleFunc("GET /trace/", redirectRoot(fsHandler))
mux.HandleFunc("GET /search", redirectRoot(fsHandler))
mux.HandleFunc("POST /api/traces/", func(w http.ResponseWriter, r *http.Request) {
traceID := strings.TrimPrefix(r.URL.Path, "/api/traces/")
if traceID == "" || strings.Contains(traceID, "/") {
http.Error(w, "Invalid trace ID", http.StatusBadRequest)
return
}
handleHTTPError(s.AddTrace(traceID, r.Body), w)
})
mux.HandleFunc("GET /api/traces/", func(w http.ResponseWriter, r *http.Request) {
traceID := strings.TrimPrefix(r.URL.Path, "/api/traces/")
if traceID == "" {
qry := r.URL.Query()
ids := qry["traceID"]
if len(ids) > 0 {
dt, err := s.GetTraces(ids...)
if err != nil {
handleHTTPError(err, w)
return
}
w.Write(dt)
return
}
}
if traceID == "" || strings.Contains(traceID, "/") {
http.Error(w, "Invalid trace ID", http.StatusBadRequest)
return
}
dt, err := s.GetTraces(traceID)
if err != nil {
handleHTTPError(err, w)
return
}
w.Write(dt)
})
mux.Handle("/", fsHandler)
return s
}
type Server struct {
config Config
server *http.Server
mu sync.Mutex
traces map[string][]byte
}
func (s *Server) AddTrace(traceID string, rdr io.Reader) error {
var payload struct {
Data []struct {
TraceID string `json:"traceID"`
} `json:"data"`
}
buf := &bytes.Buffer{}
if _, err := io.Copy(buf, rdr); err != nil {
return errors.Wrapf(err, "failed to read trace data")
}
dt := buf.Bytes()
if err := json.Unmarshal(dt, &payload); err != nil {
return errors.Wrapf(err, "failed to unmarshal trace data")
}
if len(payload.Data) != 1 {
return errors.Errorf("expected 1 trace, got %d", len(payload.Data))
}
if payload.Data[0].TraceID != traceID {
return errors.Errorf("trace ID mismatch: %s != %s", payload.Data[0].TraceID, traceID)
}
s.mu.Lock()
defer s.mu.Unlock()
if s.traces == nil {
s.traces = make(map[string][]byte)
}
s.traces[traceID] = dt
return nil
}
func (s *Server) GetTraces(traceIDs ...string) ([]byte, error) {
s.mu.Lock()
defer s.mu.Unlock()
if len(traceIDs) == 0 {
return nil, errors.Errorf("trace ID is required")
}
if len(traceIDs) == 1 {
dt, ok := s.traces[traceIDs[0]]
if !ok {
return nil, errors.Wrapf(os.ErrNotExist, "trace %s not found", traceIDs[0])
}
return dt, nil
}
type payloadT struct {
Data []interface{} `json:"data"`
}
var payload payloadT
for _, traceID := range traceIDs {
dt, ok := s.traces[traceID]
if !ok {
return nil, errors.Wrapf(os.ErrNotExist, "trace %s not found", traceID)
}
var p payloadT
if err := json.Unmarshal(dt, &p); err != nil {
return nil, errors.Wrapf(err, "failed to unmarshal trace data")
}
payload.Data = append(payload.Data, p.Data...)
}
return json.MarshalIndent(payload, "", " ")
}
func (s *Server) Serve(l net.Listener) error {
return s.server.Serve(l)
}
func redirectRoot(h http.Handler) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
r.URL.Path = "/"
h.ServeHTTP(w, r)
}
}
func handleHTTPError(err error, w http.ResponseWriter) {
switch {
case err == nil:
return
case errors.Is(err, os.ErrNotExist):
http.Error(w, err.Error(), http.StatusNotFound)
default:
http.Error(w, err.Error(), http.StatusBadRequest)
}
}

View File

@@ -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.

View File

@@ -0,0 +1,3 @@
# STDOUT Trace Exporter
[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/exporters/stdout/stdouttrace)](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/stdout/stdouttrace)

View File

@@ -0,0 +1,85 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package stdouttrace // import "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
import (
"io"
"os"
)
var (
defaultWriter = os.Stdout
defaultPrettyPrint = false
defaultTimestamps = true
)
// config contains options for the STDOUT exporter.
type config struct {
// Writer is the destination. If not set, os.Stdout is used.
Writer io.Writer
// PrettyPrint will encode the output into readable JSON. Default is
// false.
PrettyPrint bool
// Timestamps specifies if timestamps should be printed. Default is
// true.
Timestamps bool
}
// newConfig creates a validated Config configured with options.
func newConfig(options ...Option) config {
cfg := config{
Writer: defaultWriter,
PrettyPrint: defaultPrettyPrint,
Timestamps: defaultTimestamps,
}
for _, opt := range options {
cfg = opt.apply(cfg)
}
return cfg
}
// Option sets the value of an option for a Config.
type Option interface {
apply(config) config
}
// WithWriter sets the export stream destination.
func WithWriter(w io.Writer) Option {
return writerOption{w}
}
type writerOption struct {
W io.Writer
}
func (o writerOption) apply(cfg config) config {
cfg.Writer = o.W
return cfg
}
// WithPrettyPrint prettifies the emitted output.
func WithPrettyPrint() Option {
return prettyPrintOption(true)
}
type prettyPrintOption bool
func (o prettyPrintOption) apply(cfg config) config {
cfg.PrettyPrint = bool(o)
return cfg
}
// WithoutTimestamps sets the export stream to not include timestamps.
func WithoutTimestamps() Option {
return timestampsOption(false)
}
type timestampsOption bool
func (o timestampsOption) apply(cfg config) config {
cfg.Timestamps = bool(o)
return cfg
}

View File

@@ -0,0 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
// Package stdouttrace contains an OpenTelemetry exporter for tracing
// telemetry to be written to an output destination as JSON.
package stdouttrace // import "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"

View File

@@ -0,0 +1,103 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package stdouttrace // import "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
import (
"context"
"encoding/json"
"sync"
"time"
"go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/sdk/trace/tracetest"
)
var zeroTime time.Time
var _ trace.SpanExporter = &Exporter{}
// New creates an Exporter with the passed options.
func New(options ...Option) (*Exporter, error) {
cfg := newConfig(options...)
enc := json.NewEncoder(cfg.Writer)
if cfg.PrettyPrint {
enc.SetIndent("", "\t")
}
return &Exporter{
encoder: enc,
timestamps: cfg.Timestamps,
}, nil
}
// Exporter is an implementation of trace.SpanSyncer that writes spans to stdout.
type Exporter struct {
encoder *json.Encoder
encoderMu sync.Mutex
timestamps bool
stoppedMu sync.RWMutex
stopped bool
}
// ExportSpans writes spans in json format to stdout.
func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {
if err := ctx.Err(); err != nil {
return err
}
e.stoppedMu.RLock()
stopped := e.stopped
e.stoppedMu.RUnlock()
if stopped {
return nil
}
if len(spans) == 0 {
return nil
}
stubs := tracetest.SpanStubsFromReadOnlySpans(spans)
e.encoderMu.Lock()
defer e.encoderMu.Unlock()
for i := range stubs {
stub := &stubs[i]
// Remove timestamps
if !e.timestamps {
stub.StartTime = zeroTime
stub.EndTime = zeroTime
for j := range stub.Events {
ev := &stub.Events[j]
ev.Time = zeroTime
}
}
// Encode span stubs, one by one
if err := e.encoder.Encode(stub); err != nil {
return err
}
}
return nil
}
// Shutdown is called to stop the exporter, it performs no action.
func (e *Exporter) Shutdown(ctx context.Context) error {
e.stoppedMu.Lock()
e.stopped = true
e.stoppedMu.Unlock()
return nil
}
// MarshalLog is the marshaling function used by the logging system to represent this Exporter.
func (e *Exporter) MarshalLog() interface{} {
return struct {
Type string
WithTimestamps bool
}{
Type: "stdout",
WithTimestamps: e.timestamps,
}
}

View File

@@ -246,6 +246,18 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
return sendfile(outfd, infd, offset, count) return sendfile(outfd, infd, offset, count)
} }
func Dup3(oldfd, newfd, flags int) error {
if oldfd == newfd || flags&^O_CLOEXEC != 0 {
return EINVAL
}
how := F_DUP2FD
if flags&O_CLOEXEC != 0 {
how = F_DUP2FD_CLOEXEC
}
_, err := fcntl(oldfd, how, newfd)
return err
}
/* /*
* Exposed directly * Exposed directly
*/ */

View File

@@ -43,8 +43,8 @@ type DLL struct {
// LoadDLL loads DLL file into memory. // LoadDLL loads DLL file into memory.
// //
// Warning: using LoadDLL without an absolute path name is subject to // Warning: using LoadDLL without an absolute path name is subject to
// DLL preloading attacks. To safely load a system DLL, use LazyDLL // DLL preloading attacks. To safely load a system DLL, use [NewLazySystemDLL],
// with System set to true, or use LoadLibraryEx directly. // or use [LoadLibraryEx] directly.
func LoadDLL(name string) (dll *DLL, err error) { func LoadDLL(name string) (dll *DLL, err error) {
namep, err := UTF16PtrFromString(name) namep, err := UTF16PtrFromString(name)
if err != nil { if err != nil {
@@ -271,6 +271,9 @@ func (d *LazyDLL) NewProc(name string) *LazyProc {
} }
// NewLazyDLL creates new LazyDLL associated with DLL file. // NewLazyDLL creates new LazyDLL associated with DLL file.
//
// Warning: using NewLazyDLL without an absolute path name is subject to
// DLL preloading attacks. To safely load a system DLL, use [NewLazySystemDLL].
func NewLazyDLL(name string) *LazyDLL { func NewLazyDLL(name string) *LazyDLL {
return &LazyDLL{Name: name} return &LazyDLL{Name: name}
} }
@@ -410,7 +413,3 @@ func loadLibraryEx(name string, system bool) (*DLL, error) {
} }
return &DLL{Name: name, Handle: h}, nil return &DLL{Name: name, Handle: h}, nil
} }
type errString string
func (s errString) Error() string { return string(s) }

12
vendor/golang.org/x/tools/cmd/stringer/gotypesalias.go generated vendored Normal file
View File

@@ -0,0 +1,12 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.23
//go:debug gotypesalias=1
package main
// Materialize aliases whenever the go toolchain version is after 1.23 (#69772).
// Remove this file after go.mod >= 1.23 (which implies gotypesalias=1).

View File

@@ -58,6 +58,11 @@
// where t is the lower-cased name of the first type listed. It can be overridden // where t is the lower-cased name of the first type listed. It can be overridden
// with the -output flag. // with the -output flag.
// //
// Types can also be declared in tests, in which case type declarations in the
// non-test package or its test variant are preferred over types defined in the
// package with suffix "_test".
// The default output file for type declarations in tests is t_string_test.go with t picked as above.
//
// The -linecomment flag tells stringer to generate the text of any line comment, trimmed // The -linecomment flag tells stringer to generate the text of any line comment, trimmed
// of leading spaces, instead of the constant name. For instance, if the constants above had a // of leading spaces, instead of the constant name. For instance, if the constants above had a
// Pill prefix, one could write // Pill prefix, one could write
@@ -128,10 +133,6 @@ func main() {
// Parse the package once. // Parse the package once.
var dir string var dir string
g := Generator{
trimPrefix: *trimprefix,
lineComment: *linecomment,
}
// TODO(suzmue): accept other patterns for packages (directories, list of files, import paths, etc). // TODO(suzmue): accept other patterns for packages (directories, list of files, import paths, etc).
if len(args) == 1 && isDirectory(args[0]) { if len(args) == 1 && isDirectory(args[0]) {
dir = args[0] dir = args[0]
@@ -142,7 +143,32 @@ func main() {
dir = filepath.Dir(args[0]) dir = filepath.Dir(args[0])
} }
g.parsePackage(args, tags) // For each type, generate code in the first package where the type is declared.
// The order of packages is as follows:
// package x
// package x compiled for tests
// package x_test
//
// Each package pass could result in a separate generated file.
// These files must have the same package and test/not-test nature as the types
// from which they were generated.
//
// Types will be excluded when generated, to avoid repetitions.
pkgs := loadPackages(args, tags, *trimprefix, *linecomment, nil /* logf */)
sort.Slice(pkgs, func(i, j int) bool {
// Put x_test packages last.
iTest := strings.HasSuffix(pkgs[i].name, "_test")
jTest := strings.HasSuffix(pkgs[j].name, "_test")
if iTest != jTest {
return !iTest
}
return len(pkgs[i].files) < len(pkgs[j].files)
})
for _, pkg := range pkgs {
g := Generator{
pkg: pkg,
}
// Print the header and package clause. // Print the header and package clause.
g.Printf("// Code generated by \"stringer %s\"; DO NOT EDIT.\n", strings.Join(os.Args[1:], " ")) g.Printf("// Code generated by \"stringer %s\"; DO NOT EDIT.\n", strings.Join(os.Args[1:], " "))
@@ -151,10 +177,25 @@ func main() {
g.Printf("\n") g.Printf("\n")
g.Printf("import \"strconv\"\n") // Used by all methods. g.Printf("import \"strconv\"\n") // Used by all methods.
// Run generate for each type. // Run generate for types that can be found. Keep the rest for the remainingTypes iteration.
var foundTypes, remainingTypes []string
for _, typeName := range types { for _, typeName := range types {
g.generate(typeName) values := findValues(typeName, pkg)
if len(values) > 0 {
g.generate(typeName, values)
foundTypes = append(foundTypes, typeName)
} else {
remainingTypes = append(remainingTypes, typeName)
} }
}
if len(foundTypes) == 0 {
// This package didn't have any of the relevant types, skip writing a file.
continue
}
if len(remainingTypes) > 0 && output != nil && *output != "" {
log.Fatalf("cannot write to single file (-output=%q) when matching types are found in multiple packages", *output)
}
types = remainingTypes
// Format the output. // Format the output.
src := g.format() src := g.format()
@@ -162,8 +203,11 @@ func main() {
// Write to file. // Write to file.
outputName := *output outputName := *output
if outputName == "" { if outputName == "" {
baseName := fmt.Sprintf("%s_string.go", types[0]) // Type names will be unique across packages since only the first
outputName = filepath.Join(dir, strings.ToLower(baseName)) // match is picked.
// So there won't be collisions between a package compiled for tests
// and the separate package of tests (package foo_test).
outputName = filepath.Join(dir, baseName(pkg, foundTypes[0]))
} }
err := os.WriteFile(outputName, src, 0644) err := os.WriteFile(outputName, src, 0644)
if err != nil { if err != nil {
@@ -171,6 +215,20 @@ func main() {
} }
} }
if len(types) > 0 {
log.Fatalf("no values defined for types: %s", strings.Join(types, ","))
}
}
// baseName that will put the generated code together with pkg.
func baseName(pkg *Package, typename string) string {
suffix := "string.go"
if pkg.hasTestFiles {
suffix = "string_test.go"
}
return fmt.Sprintf("%s_%s", strings.ToLower(typename), suffix)
}
// isDirectory reports whether the named file is a directory. // isDirectory reports whether the named file is a directory.
func isDirectory(name string) bool { func isDirectory(name string) bool {
info, err := os.Stat(name) info, err := os.Stat(name)
@@ -186,9 +244,6 @@ type Generator struct {
buf bytes.Buffer // Accumulated output. buf bytes.Buffer // Accumulated output.
pkg *Package // Package we are scanning. pkg *Package // Package we are scanning.
trimPrefix string
lineComment bool
logf func(format string, args ...interface{}) // test logging hook; nil when not testing logf func(format string, args ...interface{}) // test logging hook; nil when not testing
} }
@@ -212,51 +267,71 @@ type Package struct {
name string name string
defs map[*ast.Ident]types.Object defs map[*ast.Ident]types.Object
files []*File files []*File
hasTestFiles bool
} }
// parsePackage analyzes the single package constructed from the patterns and tags. // loadPackages analyzes the single package constructed from the patterns and tags.
// parsePackage exits if there is an error. // loadPackages exits if there is an error.
func (g *Generator) parsePackage(patterns []string, tags []string) { //
// Returns all variants (such as tests) of the package.
//
// logf is a test logging hook. It can be nil when not testing.
func loadPackages(
patterns, tags []string,
trimPrefix string, lineComment bool,
logf func(format string, args ...interface{}),
) []*Package {
cfg := &packages.Config{ cfg := &packages.Config{
Mode: packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax, Mode: packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax | packages.NeedFiles,
// TODO: Need to think about constants in test files. Maybe write type_string_test.go // Tests are included, let the caller decide how to fold them in.
// in a separate pass? For later. Tests: true,
Tests: false,
BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join(tags, " "))}, BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join(tags, " "))},
Logf: g.logf, Logf: logf,
} }
pkgs, err := packages.Load(cfg, patterns...) pkgs, err := packages.Load(cfg, patterns...)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
if len(pkgs) != 1 { if len(pkgs) == 0 {
log.Fatalf("error: %d packages matching %v", len(pkgs), strings.Join(patterns, " ")) log.Fatalf("error: no packages matching %v", strings.Join(patterns, " "))
}
g.addPackage(pkgs[0])
} }
// addPackage adds a type checked Package and its syntax files to the generator. out := make([]*Package, len(pkgs))
func (g *Generator) addPackage(pkg *packages.Package) { for i, pkg := range pkgs {
g.pkg = &Package{ p := &Package{
name: pkg.Name, name: pkg.Name,
defs: pkg.TypesInfo.Defs, defs: pkg.TypesInfo.Defs,
files: make([]*File, len(pkg.Syntax)), files: make([]*File, len(pkg.Syntax)),
} }
for i, file := range pkg.Syntax { for j, file := range pkg.Syntax {
g.pkg.files[i] = &File{ p.files[j] = &File{
file: file, file: file,
pkg: g.pkg, pkg: p,
trimPrefix: g.trimPrefix,
lineComment: g.lineComment, trimPrefix: trimPrefix,
} lineComment: lineComment,
} }
} }
// generate produces the String method for the named type. // Keep track of test files, since we might want to generated
func (g *Generator) generate(typeName string) { // code that ends up in that kind of package.
// Can be replaced once https://go.dev/issue/38445 lands.
for _, f := range pkg.GoFiles {
if strings.HasSuffix(f, "_test.go") {
p.hasTestFiles = true
break
}
}
out[i] = p
}
return out
}
func findValues(typeName string, pkg *Package) []Value {
values := make([]Value, 0, 100) values := make([]Value, 0, 100)
for _, file := range g.pkg.files { for _, file := range pkg.files {
// Set the state for this run of the walker. // Set the state for this run of the walker.
file.typeName = typeName file.typeName = typeName
file.values = nil file.values = nil
@@ -265,10 +340,11 @@ func (g *Generator) generate(typeName string) {
values = append(values, file.values...) values = append(values, file.values...)
} }
} }
return values
if len(values) == 0 {
log.Fatalf("no values defined for type %s", typeName)
} }
// generate produces the String method for the named type.
func (g *Generator) generate(typeName string, values []Value) {
// Generate code that will fail if the constants change value. // Generate code that will fail if the constants change value.
g.Printf("func _() {\n") g.Printf("func _() {\n")
g.Printf("\t// An \"invalid array index\" compiler error signifies that the constant values have changed.\n") g.Printf("\t// An \"invalid array index\" compiler error signifies that the constant values have changed.\n")

View File

@@ -2,22 +2,64 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package gcexportdata provides functions for locating, reading, and // Package gcexportdata provides functions for reading and writing
// writing export data files containing type information produced by the // export data, which is a serialized description of the API of a Go
// gc compiler. This package supports go1.7 export data format and all // package including the names, kinds, types, and locations of all
// later versions. // exported declarations.
// //
// Although it might seem convenient for this package to live alongside // The standard Go compiler (cmd/compile) writes an export data file
// go/types in the standard library, this would cause version skew // for each package it compiles, which it later reads when compiling
// problems for developer tools that use it, since they must be able to // packages that import the earlier one. The compiler must thus
// consume the outputs of the gc compiler both before and after a Go // contain logic to both write and read export data.
// update such as from Go 1.7 to Go 1.8. Because this package lives in // (See the "Export" section in the cmd/compile/README file.)
// golang.org/x/tools, sites can update their version of this repo some //
// time before the Go 1.8 release and rebuild and redeploy their // The [Read] function in this package can read files produced by the
// developer tools, which will then be able to consume both Go 1.7 and // compiler, producing [go/types] data structures. As a matter of
// Go 1.8 export data files, so they will work before and after the // policy, Read supports export data files produced by only the last
// Go update. (See discussion at https://golang.org/issue/15651.) // two Go releases plus tip; see https://go.dev/issue/68898. The
package gcexportdata // import "golang.org/x/tools/go/gcexportdata" // export data files produced by the compiler contain additional
// details related to generics, inlining, and other optimizations that
// cannot be decoded by the [Read] function.
//
// In files written by the compiler, the export data is not at the
// start of the file. Before calling Read, use [NewReader] to locate
// the desired portion of the file.
//
// The [Write] function in this package encodes the exported API of a
// Go package ([types.Package]) as a file. Such files can be later
// decoded by Read, but cannot be consumed by the compiler.
//
// # Future changes
//
// Although Read supports the formats written by both Write and the
// compiler, the two are quite different, and there is an open
// proposal (https://go.dev/issue/69491) to separate these APIs.
//
// Under that proposal, this package would ultimately provide only the
// Read operation for compiler export data, which must be defined in
// this module (golang.org/x/tools), not in the standard library, to
// avoid version skew for developer tools that need to read compiler
// export data both before and after a Go release, such as from Go
// 1.23 to Go 1.24. Because this package lives in the tools module,
// clients can update their version of the module some time before the
// Go 1.24 release and rebuild and redeploy their tools, which will
// then be able to consume both Go 1.23 and Go 1.24 export data files,
// so they will work before and after the Go update. (See discussion
// at https://go.dev/issue/15651.)
//
// The operations to import and export [go/types] data structures
// would be defined in the go/types package as Import and Export.
// [Write] would (eventually) delegate to Export,
// and [Read], when it detects a file produced by Export,
// would delegate to Import.
//
// # Deprecations
//
// The [NewImporter] and [Find] functions are deprecated and should
// not be used in new code. The [WriteBundle] and [ReadBundle]
// functions are experimental, and there is an open proposal to
// deprecate them (https://go.dev/issue/69573).
package gcexportdata
import ( import (
"bufio" "bufio"
@@ -100,6 +142,11 @@ func readAll(r io.Reader) ([]byte, error) {
// Read reads export data from in, decodes it, and returns type // Read reads export data from in, decodes it, and returns type
// information for the package. // information for the package.
// //
// Read is capable of reading export data produced by [Write] at the
// same source code version, or by the last two Go releases (plus tip)
// of the standard Go compiler. Reading files from older compilers may
// produce an error.
//
// The package path (effectively its linker symbol prefix) is // The package path (effectively its linker symbol prefix) is
// specified by path, since unlike the package name, this information // specified by path, since unlike the package name, this information
// may not be recorded in the export data. // may not be recorded in the export data.
@@ -128,14 +175,26 @@ func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package,
// (from "version"). Select appropriate importer. // (from "version"). Select appropriate importer.
if len(data) > 0 { if len(data) > 0 {
switch data[0] { switch data[0] {
case 'v', 'c', 'd': // binary, till go1.10 case 'v', 'c', 'd':
// binary, produced by cmd/compile till go1.10
return nil, fmt.Errorf("binary (%c) import format is no longer supported", data[0]) return nil, fmt.Errorf("binary (%c) import format is no longer supported", data[0])
case 'i': // indexed, till go1.19 case 'i':
// indexed, produced by cmd/compile till go1.19,
// and also by [Write].
//
// If proposal #69491 is accepted, go/types
// serialization will be implemented by
// types.Export, to which Write would eventually
// delegate (explicitly dropping any pretence at
// inter-version Write-Read compatibility).
// This [Read] function would delegate to types.Import
// when it detects that the file was produced by Export.
_, pkg, err := gcimporter.IImportData(fset, imports, data[1:], path) _, pkg, err := gcimporter.IImportData(fset, imports, data[1:], path)
return pkg, err return pkg, err
case 'u': // unified, from go1.20 case 'u':
// unified, produced by cmd/compile since go1.20
_, pkg, err := gcimporter.UImportData(fset, imports, data[1:], path) _, pkg, err := gcimporter.UImportData(fset, imports, data[1:], path)
return pkg, err return pkg, err

View File

@@ -64,7 +64,7 @@ graph using the Imports fields.
The Load function can be configured by passing a pointer to a Config as The Load function can be configured by passing a pointer to a Config as
the first argument. A nil Config is equivalent to the zero Config, which the first argument. A nil Config is equivalent to the zero Config, which
causes Load to run in LoadFiles mode, collecting minimal information. causes Load to run in [LoadFiles] mode, collecting minimal information.
See the documentation for type Config for details. See the documentation for type Config for details.
As noted earlier, the Config.Mode controls the amount of detail As noted earlier, the Config.Mode controls the amount of detail
@@ -72,14 +72,14 @@ reported about the loaded packages. See the documentation for type LoadMode
for details. for details.
Most tools should pass their command-line arguments (after any flags) Most tools should pass their command-line arguments (after any flags)
uninterpreted to [Load], so that it can interpret them uninterpreted to Load, so that it can interpret them
according to the conventions of the underlying build system. according to the conventions of the underlying build system.
See the Example function for typical usage. See the Example function for typical usage.
# The driver protocol # The driver protocol
[Load] may be used to load Go packages even in Go projects that use Load may be used to load Go packages even in Go projects that use
alternative build systems, by installing an appropriate "driver" alternative build systems, by installing an appropriate "driver"
program for the build system and specifying its location in the program for the build system and specifying its location in the
GOPACKAGESDRIVER environment variable. GOPACKAGESDRIVER environment variable.
@@ -97,6 +97,15 @@ JSON-encoded [DriverRequest] message providing additional information
is written to the driver's standard input. The driver must write a is written to the driver's standard input. The driver must write a
JSON-encoded [DriverResponse] message to its standard output. (This JSON-encoded [DriverResponse] message to its standard output. (This
message differs from the JSON schema produced by 'go list'.) message differs from the JSON schema produced by 'go list'.)
The value of the PWD environment variable seen by the driver process
is the preferred name of its working directory. (The working directory
may have other aliases due to symbolic links; see the comment on the
Dir field of [exec.Cmd] for related information.)
When the driver process emits in its response the name of a file
that is a descendant of this directory, it must use an absolute path
that has the value of PWD as a prefix, to ensure that the returned
filenames satisfy the original query.
*/ */
package packages // import "golang.org/x/tools/go/packages" package packages // import "golang.org/x/tools/go/packages"

View File

@@ -79,7 +79,7 @@ type DriverResponse struct {
// driver is the type for functions that query the build system for the // driver is the type for functions that query the build system for the
// packages named by the patterns. // packages named by the patterns.
type driver func(cfg *Config, patterns ...string) (*DriverResponse, error) type driver func(cfg *Config, patterns []string) (*DriverResponse, error)
// findExternalDriver returns the file path of a tool that supplies // findExternalDriver returns the file path of a tool that supplies
// the build system package structure, or "" if not found. // the build system package structure, or "" if not found.
@@ -103,7 +103,7 @@ func findExternalDriver(cfg *Config) driver {
return nil return nil
} }
} }
return func(cfg *Config, words ...string) (*DriverResponse, error) { return func(cfg *Config, patterns []string) (*DriverResponse, error) {
req, err := json.Marshal(DriverRequest{ req, err := json.Marshal(DriverRequest{
Mode: cfg.Mode, Mode: cfg.Mode,
Env: cfg.Env, Env: cfg.Env,
@@ -117,7 +117,7 @@ func findExternalDriver(cfg *Config) driver {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
cmd := exec.CommandContext(cfg.Context, tool, words...) cmd := exec.CommandContext(cfg.Context, tool, patterns...)
cmd.Dir = cfg.Dir cmd.Dir = cfg.Dir
// The cwd gets resolved to the real path. On Darwin, where // The cwd gets resolved to the real path. On Darwin, where
// /tmp is a symlink, this breaks anything that expects the // /tmp is a symlink, this breaks anything that expects the

View File

@@ -80,6 +80,12 @@ type golistState struct {
cfg *Config cfg *Config
ctx context.Context ctx context.Context
runner *gocommand.Runner
// overlay is the JSON file that encodes the Config.Overlay
// mapping, used by 'go list -overlay=...'.
overlay string
envOnce sync.Once envOnce sync.Once
goEnvError error goEnvError error
goEnv map[string]string goEnv map[string]string
@@ -127,7 +133,10 @@ func (state *golistState) mustGetEnv() map[string]string {
// goListDriver uses the go list command to interpret the patterns and produce // goListDriver uses the go list command to interpret the patterns and produce
// the build system package structure. // the build system package structure.
// See driver for more details. // See driver for more details.
func goListDriver(cfg *Config, patterns ...string) (_ *DriverResponse, err error) { //
// overlay is the JSON file that encodes the cfg.Overlay
// mapping, used by 'go list -overlay=...'
func goListDriver(cfg *Config, runner *gocommand.Runner, overlay string, patterns []string) (_ *DriverResponse, err error) {
// Make sure that any asynchronous go commands are killed when we return. // Make sure that any asynchronous go commands are killed when we return.
parentCtx := cfg.Context parentCtx := cfg.Context
if parentCtx == nil { if parentCtx == nil {
@@ -142,13 +151,15 @@ func goListDriver(cfg *Config, patterns ...string) (_ *DriverResponse, err error
cfg: cfg, cfg: cfg,
ctx: ctx, ctx: ctx,
vendorDirs: map[string]bool{}, vendorDirs: map[string]bool{},
overlay: overlay,
runner: runner,
} }
// Fill in response.Sizes asynchronously if necessary. // Fill in response.Sizes asynchronously if necessary.
if cfg.Mode&NeedTypesSizes != 0 || cfg.Mode&NeedTypes != 0 { if cfg.Mode&NeedTypesSizes != 0 || cfg.Mode&(NeedTypes|NeedTypesInfo) != 0 {
errCh := make(chan error) errCh := make(chan error)
go func() { go func() {
compiler, arch, err := getSizesForArgs(ctx, state.cfgInvocation(), cfg.gocmdRunner) compiler, arch, err := getSizesForArgs(ctx, state.cfgInvocation(), runner)
response.dr.Compiler = compiler response.dr.Compiler = compiler
response.dr.Arch = arch response.dr.Arch = arch
errCh <- err errCh <- err
@@ -681,7 +692,7 @@ func (state *golistState) shouldAddFilenameFromError(p *jsonPackage) bool {
// getGoVersion returns the effective minor version of the go command. // getGoVersion returns the effective minor version of the go command.
func (state *golistState) getGoVersion() (int, error) { func (state *golistState) getGoVersion() (int, error) {
state.goVersionOnce.Do(func() { state.goVersionOnce.Do(func() {
state.goVersion, state.goVersionError = gocommand.GoVersion(state.ctx, state.cfgInvocation(), state.cfg.gocmdRunner) state.goVersion, state.goVersionError = gocommand.GoVersion(state.ctx, state.cfgInvocation(), state.runner)
}) })
return state.goVersion, state.goVersionError return state.goVersion, state.goVersionError
} }
@@ -751,7 +762,7 @@ func jsonFlag(cfg *Config, goVersion int) string {
} }
} }
addFields("Name", "ImportPath", "Error") // These fields are always needed addFields("Name", "ImportPath", "Error") // These fields are always needed
if cfg.Mode&NeedFiles != 0 || cfg.Mode&NeedTypes != 0 { if cfg.Mode&NeedFiles != 0 || cfg.Mode&(NeedTypes|NeedTypesInfo) != 0 {
addFields("Dir", "GoFiles", "IgnoredGoFiles", "IgnoredOtherFiles", "CFiles", addFields("Dir", "GoFiles", "IgnoredGoFiles", "IgnoredOtherFiles", "CFiles",
"CgoFiles", "CXXFiles", "MFiles", "HFiles", "FFiles", "SFiles", "CgoFiles", "CXXFiles", "MFiles", "HFiles", "FFiles", "SFiles",
"SwigFiles", "SwigCXXFiles", "SysoFiles") "SwigFiles", "SwigCXXFiles", "SysoFiles")
@@ -759,7 +770,7 @@ func jsonFlag(cfg *Config, goVersion int) string {
addFields("TestGoFiles", "XTestGoFiles") addFields("TestGoFiles", "XTestGoFiles")
} }
} }
if cfg.Mode&NeedTypes != 0 { if cfg.Mode&(NeedTypes|NeedTypesInfo) != 0 {
// CompiledGoFiles seems to be required for the test case TestCgoNoSyntax, // CompiledGoFiles seems to be required for the test case TestCgoNoSyntax,
// even when -compiled isn't passed in. // even when -compiled isn't passed in.
// TODO(#52435): Should we make the test ask for -compiled, or automatically // TODO(#52435): Should we make the test ask for -compiled, or automatically
@@ -840,7 +851,7 @@ func (state *golistState) cfgInvocation() gocommand.Invocation {
Env: cfg.Env, Env: cfg.Env,
Logf: cfg.Logf, Logf: cfg.Logf,
WorkingDir: cfg.Dir, WorkingDir: cfg.Dir,
Overlay: cfg.goListOverlayFile, Overlay: state.overlay,
} }
} }
@@ -851,11 +862,8 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer,
inv := state.cfgInvocation() inv := state.cfgInvocation()
inv.Verb = verb inv.Verb = verb
inv.Args = args inv.Args = args
gocmdRunner := cfg.gocmdRunner
if gocmdRunner == nil { stdout, stderr, friendlyErr, err := state.runner.RunRaw(cfg.Context, inv)
gocmdRunner = &gocommand.Runner{}
}
stdout, stderr, friendlyErr, err := gocmdRunner.RunRaw(cfg.Context, inv)
if err != nil { if err != nil {
// Check for 'go' executable not being found. // Check for 'go' executable not being found.
if ee, ok := err.(*exec.Error); ok && ee.Err == exec.ErrNotFound { if ee, ok := err.(*exec.Error); ok && ee.Err == exec.ErrNotFound {
@@ -879,6 +887,12 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer,
return nil, friendlyErr return nil, friendlyErr
} }
// Return an error if 'go list' failed due to missing tools in
// $GOROOT/pkg/tool/$GOOS_$GOARCH (#69606).
if len(stderr.String()) > 0 && strings.Contains(stderr.String(), `go: no such tool`) {
return nil, friendlyErr
}
// Is there an error running the C compiler in cgo? This will be reported in the "Error" field // Is there an error running the C compiler in cgo? This will be reported in the "Error" field
// and should be suppressed by go list -e. // and should be suppressed by go list -e.
// //

View File

@@ -9,49 +9,46 @@ import (
"strings" "strings"
) )
var allModes = []LoadMode{ var modes = [...]struct {
NeedName, mode LoadMode
NeedFiles, name string
NeedCompiledGoFiles, }{
NeedImports, {NeedName, "NeedName"},
NeedDeps, {NeedFiles, "NeedFiles"},
NeedExportFile, {NeedCompiledGoFiles, "NeedCompiledGoFiles"},
NeedTypes, {NeedImports, "NeedImports"},
NeedSyntax, {NeedDeps, "NeedDeps"},
NeedTypesInfo, {NeedExportFile, "NeedExportFile"},
NeedTypesSizes, {NeedTypes, "NeedTypes"},
{NeedSyntax, "NeedSyntax"},
{NeedTypesInfo, "NeedTypesInfo"},
{NeedTypesSizes, "NeedTypesSizes"},
{NeedModule, "NeedModule"},
{NeedEmbedFiles, "NeedEmbedFiles"},
{NeedEmbedPatterns, "NeedEmbedPatterns"},
} }
var modeStrings = []string{ func (mode LoadMode) String() string {
"NeedName", if mode == 0 {
"NeedFiles",
"NeedCompiledGoFiles",
"NeedImports",
"NeedDeps",
"NeedExportFile",
"NeedTypes",
"NeedSyntax",
"NeedTypesInfo",
"NeedTypesSizes",
}
func (mod LoadMode) String() string {
m := mod
if m == 0 {
return "LoadMode(0)" return "LoadMode(0)"
} }
var out []string var out []string
for i, x := range allModes { // named bits
if x > m { for _, item := range modes {
break if (mode & item.mode) != 0 {
} mode ^= item.mode
if (m & x) != 0 { out = append(out, item.name)
out = append(out, modeStrings[i])
m = m ^ x
} }
} }
if m != 0 { // unnamed residue
out = append(out, "Unknown") if mode != 0 {
if out == nil {
return fmt.Sprintf("LoadMode(%#x)", int(mode))
} }
return fmt.Sprintf("LoadMode(%s)", strings.Join(out, "|")) out = append(out, fmt.Sprintf("%#x", int(mode)))
}
if len(out) == 1 {
return out[0]
}
return "(" + strings.Join(out, "|") + ")"
} }

View File

@@ -16,13 +16,13 @@ import (
"go/scanner" "go/scanner"
"go/token" "go/token"
"go/types" "go/types"
"io"
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
@@ -31,7 +31,6 @@ import (
"golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/gocommand"
"golang.org/x/tools/internal/packagesinternal" "golang.org/x/tools/internal/packagesinternal"
"golang.org/x/tools/internal/typesinternal" "golang.org/x/tools/internal/typesinternal"
"golang.org/x/tools/internal/versions"
) )
// A LoadMode controls the amount of detail to return when loading. // A LoadMode controls the amount of detail to return when loading.
@@ -56,7 +55,7 @@ const (
// NeedName adds Name and PkgPath. // NeedName adds Name and PkgPath.
NeedName LoadMode = 1 << iota NeedName LoadMode = 1 << iota
// NeedFiles adds GoFiles and OtherFiles. // NeedFiles adds GoFiles, OtherFiles, and IgnoredFiles
NeedFiles NeedFiles
// NeedCompiledGoFiles adds CompiledGoFiles. // NeedCompiledGoFiles adds CompiledGoFiles.
@@ -78,7 +77,7 @@ const (
// NeedSyntax adds Syntax and Fset. // NeedSyntax adds Syntax and Fset.
NeedSyntax NeedSyntax
// NeedTypesInfo adds TypesInfo. // NeedTypesInfo adds TypesInfo and Fset.
NeedTypesInfo NeedTypesInfo
// NeedTypesSizes adds TypesSizes. // NeedTypesSizes adds TypesSizes.
@@ -103,25 +102,37 @@ const (
// NeedEmbedPatterns adds EmbedPatterns. // NeedEmbedPatterns adds EmbedPatterns.
NeedEmbedPatterns NeedEmbedPatterns
// Be sure to update loadmode_string.go when adding new items!
) )
const ( const (
// LoadFiles loads the name and file names for the initial packages.
//
// Deprecated: LoadFiles exists for historical compatibility // Deprecated: LoadFiles exists for historical compatibility
// and should not be used. Please directly specify the needed fields using the Need values. // and should not be used. Please directly specify the needed fields using the Need values.
LoadFiles = NeedName | NeedFiles | NeedCompiledGoFiles LoadFiles = NeedName | NeedFiles | NeedCompiledGoFiles
// LoadImports loads the name, file names, and import mapping for the initial packages.
//
// Deprecated: LoadImports exists for historical compatibility // Deprecated: LoadImports exists for historical compatibility
// and should not be used. Please directly specify the needed fields using the Need values. // and should not be used. Please directly specify the needed fields using the Need values.
LoadImports = LoadFiles | NeedImports LoadImports = LoadFiles | NeedImports
// LoadTypes loads exported type information for the initial packages.
//
// Deprecated: LoadTypes exists for historical compatibility // Deprecated: LoadTypes exists for historical compatibility
// and should not be used. Please directly specify the needed fields using the Need values. // and should not be used. Please directly specify the needed fields using the Need values.
LoadTypes = LoadImports | NeedTypes | NeedTypesSizes LoadTypes = LoadImports | NeedTypes | NeedTypesSizes
// LoadSyntax loads typed syntax for the initial packages.
//
// Deprecated: LoadSyntax exists for historical compatibility // Deprecated: LoadSyntax exists for historical compatibility
// and should not be used. Please directly specify the needed fields using the Need values. // and should not be used. Please directly specify the needed fields using the Need values.
LoadSyntax = LoadTypes | NeedSyntax | NeedTypesInfo LoadSyntax = LoadTypes | NeedSyntax | NeedTypesInfo
// LoadAllSyntax loads typed syntax for the initial packages and all dependencies.
//
// Deprecated: LoadAllSyntax exists for historical compatibility // Deprecated: LoadAllSyntax exists for historical compatibility
// and should not be used. Please directly specify the needed fields using the Need values. // and should not be used. Please directly specify the needed fields using the Need values.
LoadAllSyntax = LoadSyntax | NeedDeps LoadAllSyntax = LoadSyntax | NeedDeps
@@ -133,13 +144,7 @@ const (
// A Config specifies details about how packages should be loaded. // A Config specifies details about how packages should be loaded.
// The zero value is a valid configuration. // The zero value is a valid configuration.
// //
// Calls to Load do not modify this struct. // Calls to [Load] do not modify this struct.
//
// TODO(adonovan): #67702: this is currently false: in fact,
// calls to [Load] do not modify the public fields of this struct, but
// may modify hidden fields, so concurrent calls to [Load] must not
// use the same Config. But perhaps we should reestablish the
// documented invariant.
type Config struct { type Config struct {
// Mode controls the level of information returned for each package. // Mode controls the level of information returned for each package.
Mode LoadMode Mode LoadMode
@@ -170,19 +175,10 @@ type Config struct {
// //
Env []string Env []string
// gocmdRunner guards go command calls from concurrency errors.
gocmdRunner *gocommand.Runner
// BuildFlags is a list of command-line flags to be passed through to // BuildFlags is a list of command-line flags to be passed through to
// the build system's query tool. // the build system's query tool.
BuildFlags []string BuildFlags []string
// modFile will be used for -modfile in go command invocations.
modFile string
// modFlag will be used for -modfile in go command invocations.
modFlag string
// Fset provides source position information for syntax trees and types. // Fset provides source position information for syntax trees and types.
// If Fset is nil, Load will use a new fileset, but preserve Fset's value. // If Fset is nil, Load will use a new fileset, but preserve Fset's value.
Fset *token.FileSet Fset *token.FileSet
@@ -229,21 +225,24 @@ type Config struct {
// drivers may vary in their level of support for overlays. // drivers may vary in their level of support for overlays.
Overlay map[string][]byte Overlay map[string][]byte
// goListOverlayFile is the JSON file that encodes the Overlay // -- Hidden configuration fields only for use in x/tools --
// mapping, used by 'go list -overlay=...'
goListOverlayFile string // modFile will be used for -modfile in go command invocations.
modFile string
// modFlag will be used for -modfile in go command invocations.
modFlag string
} }
// Load loads and returns the Go packages named by the given patterns. // Load loads and returns the Go packages named by the given patterns.
// //
// Config specifies loading options; // The cfg parameter specifies loading options; nil behaves the same as an empty [Config].
// nil behaves the same as an empty Config.
// //
// The [Config.Mode] field is a set of bits that determine what kinds // The [Config.Mode] field is a set of bits that determine what kinds
// of information should be computed and returned. Modes that require // of information should be computed and returned. Modes that require
// more information tend to be slower. See [LoadMode] for details // more information tend to be slower. See [LoadMode] for details
// and important caveats. Its zero value is equivalent to // and important caveats. Its zero value is equivalent to
// NeedName | NeedFiles | NeedCompiledGoFiles. // [NeedName] | [NeedFiles] | [NeedCompiledGoFiles].
// //
// Each call to Load returns a new set of [Package] instances. // Each call to Load returns a new set of [Package] instances.
// The Packages and their Imports form a directed acyclic graph. // The Packages and their Imports form a directed acyclic graph.
@@ -260,7 +259,7 @@ type Config struct {
// Errors associated with a particular package are recorded in the // Errors associated with a particular package are recorded in the
// corresponding Package's Errors list, and do not cause Load to // corresponding Package's Errors list, and do not cause Load to
// return an error. Clients may need to handle such errors before // return an error. Clients may need to handle such errors before
// proceeding with further analysis. The PrintErrors function is // proceeding with further analysis. The [PrintErrors] function is
// provided for convenient display of all errors. // provided for convenient display of all errors.
func Load(cfg *Config, patterns ...string) ([]*Package, error) { func Load(cfg *Config, patterns ...string) ([]*Package, error) {
ld := newLoader(cfg) ld := newLoader(cfg)
@@ -323,21 +322,24 @@ func defaultDriver(cfg *Config, patterns ...string) (*DriverResponse, bool, erro
} else if !response.NotHandled { } else if !response.NotHandled {
return response, true, nil return response, true, nil
} }
// (fall through) // not handled: fall through
} }
// go list fallback // go list fallback
//
// Write overlays once, as there are many calls // Write overlays once, as there are many calls
// to 'go list' (one per chunk plus others too). // to 'go list' (one per chunk plus others too).
overlay, cleanupOverlay, err := gocommand.WriteOverlays(cfg.Overlay) overlayFile, cleanupOverlay, err := gocommand.WriteOverlays(cfg.Overlay)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
defer cleanupOverlay() defer cleanupOverlay()
cfg.goListOverlayFile = overlay
response, err := callDriverOnChunks(goListDriver, cfg, chunks) var runner gocommand.Runner // (shared across many 'go list' calls)
driver := func(cfg *Config, patterns []string) (*DriverResponse, error) {
return goListDriver(cfg, &runner, overlayFile, patterns)
}
response, err := callDriverOnChunks(driver, cfg, chunks)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
@@ -375,16 +377,14 @@ func splitIntoChunks(patterns []string, argMax int) ([][]string, error) {
func callDriverOnChunks(driver driver, cfg *Config, chunks [][]string) (*DriverResponse, error) { func callDriverOnChunks(driver driver, cfg *Config, chunks [][]string) (*DriverResponse, error) {
if len(chunks) == 0 { if len(chunks) == 0 {
return driver(cfg) return driver(cfg, nil)
} }
responses := make([]*DriverResponse, len(chunks)) responses := make([]*DriverResponse, len(chunks))
errNotHandled := errors.New("driver returned NotHandled") errNotHandled := errors.New("driver returned NotHandled")
var g errgroup.Group var g errgroup.Group
for i, chunk := range chunks { for i, chunk := range chunks {
i := i
chunk := chunk
g.Go(func() (err error) { g.Go(func() (err error) {
responses[i], err = driver(cfg, chunk...) responses[i], err = driver(cfg, chunk)
if responses[i] != nil && responses[i].NotHandled { if responses[i] != nil && responses[i].NotHandled {
err = errNotHandled err = errNotHandled
} }
@@ -682,7 +682,8 @@ func (p *Package) String() string { return p.ID }
type loaderPackage struct { type loaderPackage struct {
*Package *Package
importErrors map[string]error // maps each bad import to its error importErrors map[string]error // maps each bad import to its error
loadOnce sync.Once preds []*loaderPackage // packages that import this one
unfinishedSuccs atomic.Int32 // number of direct imports not yet loaded
color uint8 // for cycle detection color uint8 // for cycle detection
needsrc bool // load from source (Mode >= LoadTypes) needsrc bool // load from source (Mode >= LoadTypes)
needtypes bool // type information is either requested or depended on needtypes bool // type information is either requested or depended on
@@ -692,7 +693,7 @@ type loaderPackage struct {
// loader holds the working state of a single call to load. // loader holds the working state of a single call to load.
type loader struct { type loader struct {
pkgs map[string]*loaderPackage pkgs map[string]*loaderPackage // keyed by Package.ID
Config Config
sizes types.Sizes // non-nil if needed by mode sizes types.Sizes // non-nil if needed by mode
parseCache map[string]*parseValue parseCache map[string]*parseValue
@@ -738,9 +739,6 @@ func newLoader(cfg *Config) *loader {
if ld.Config.Env == nil { if ld.Config.Env == nil {
ld.Config.Env = os.Environ() ld.Config.Env = os.Environ()
} }
if ld.Config.gocmdRunner == nil {
ld.Config.gocmdRunner = &gocommand.Runner{}
}
if ld.Context == nil { if ld.Context == nil {
ld.Context = context.Background() ld.Context = context.Background()
} }
@@ -754,7 +752,7 @@ func newLoader(cfg *Config) *loader {
ld.requestedMode = ld.Mode ld.requestedMode = ld.Mode
ld.Mode = impliedLoadMode(ld.Mode) ld.Mode = impliedLoadMode(ld.Mode)
if ld.Mode&NeedTypes != 0 || ld.Mode&NeedSyntax != 0 { if ld.Mode&(NeedSyntax|NeedTypes|NeedTypesInfo) != 0 {
if ld.Fset == nil { if ld.Fset == nil {
ld.Fset = token.NewFileSet() ld.Fset = token.NewFileSet()
} }
@@ -763,6 +761,7 @@ func newLoader(cfg *Config) *loader {
// because we load source if export data is missing. // because we load source if export data is missing.
if ld.ParseFile == nil { if ld.ParseFile == nil {
ld.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) { ld.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) {
// We implicitly promise to keep doing ast.Object resolution. :(
const mode = parser.AllErrors | parser.ParseComments const mode = parser.AllErrors | parser.ParseComments
return parser.ParseFile(fset, filename, src, mode) return parser.ParseFile(fset, filename, src, mode)
} }
@@ -794,7 +793,7 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
exportDataInvalid := len(ld.Overlay) > 0 || pkg.ExportFile == "" && pkg.PkgPath != "unsafe" exportDataInvalid := len(ld.Overlay) > 0 || pkg.ExportFile == "" && pkg.PkgPath != "unsafe"
// This package needs type information if the caller requested types and the package is // This package needs type information if the caller requested types and the package is
// either a root, or it's a non-root and the user requested dependencies ... // either a root, or it's a non-root and the user requested dependencies ...
needtypes := (ld.Mode&NeedTypes|NeedTypesInfo != 0 && (rootIndex >= 0 || ld.Mode&NeedDeps != 0)) needtypes := (ld.Mode&(NeedTypes|NeedTypesInfo) != 0 && (rootIndex >= 0 || ld.Mode&NeedDeps != 0))
// This package needs source if the call requested source (or types info, which implies source) // This package needs source if the call requested source (or types info, which implies source)
// and the package is either a root, or itas a non- root and the user requested dependencies... // and the package is either a root, or itas a non- root and the user requested dependencies...
needsrc := ((ld.Mode&(NeedSyntax|NeedTypesInfo) != 0 && (rootIndex >= 0 || ld.Mode&NeedDeps != 0)) || needsrc := ((ld.Mode&(NeedSyntax|NeedTypesInfo) != 0 && (rootIndex >= 0 || ld.Mode&NeedDeps != 0)) ||
@@ -819,9 +818,10 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
} }
} }
if ld.Mode&NeedImports != 0 { // Materialize the import graph if it is needed (NeedImports),
// Materialize the import graph. // or if we'll be using loadPackages (Need{Syntax|Types|TypesInfo}).
var leaves []*loaderPackage // packages with no unfinished successors
if ld.Mode&(NeedImports|NeedSyntax|NeedTypes|NeedTypesInfo) != 0 {
const ( const (
white = 0 // new white = 0 // new
grey = 1 // in progress grey = 1 // in progress
@@ -840,14 +840,12 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
// dependency on a package that does. These are the only packages // dependency on a package that does. These are the only packages
// for which we load source code. // for which we load source code.
var stack []*loaderPackage var stack []*loaderPackage
var visit func(lpkg *loaderPackage) bool var visit func(from, lpkg *loaderPackage) bool
visit = func(lpkg *loaderPackage) bool { visit = func(from, lpkg *loaderPackage) bool {
switch lpkg.color { if lpkg.color == grey {
case black:
return lpkg.needsrc
case grey:
panic("internal error: grey node") panic("internal error: grey node")
} }
if lpkg.color == white {
lpkg.color = grey lpkg.color = grey
stack = append(stack, lpkg) // push stack = append(stack, lpkg) // push
stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports
@@ -869,12 +867,14 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
continue continue
} }
if visit(imp) { if visit(lpkg, imp) {
lpkg.needsrc = true lpkg.needsrc = true
} }
lpkg.Imports[importPath] = imp.Package lpkg.Imports[importPath] = imp.Package
} }
// -- postorder --
// Complete type information is required for the // Complete type information is required for the
// immediate dependencies of each source package. // immediate dependencies of each source package.
if lpkg.needsrc && ld.Mode&NeedTypes != 0 { if lpkg.needsrc && ld.Mode&NeedTypes != 0 {
@@ -888,15 +888,28 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
if ld.Mode&NeedTypesSizes != 0 { if ld.Mode&NeedTypesSizes != 0 {
lpkg.TypesSizes = ld.sizes lpkg.TypesSizes = ld.sizes
} }
// Add packages with no imports directly to the queue of leaves.
if len(lpkg.Imports) == 0 {
leaves = append(leaves, lpkg)
}
stack = stack[:len(stack)-1] // pop stack = stack[:len(stack)-1] // pop
lpkg.color = black lpkg.color = black
}
// Add edge from predecessor.
if from != nil {
from.unfinishedSuccs.Add(+1) // incref
lpkg.preds = append(lpkg.preds, from)
}
return lpkg.needsrc return lpkg.needsrc
} }
// For each initial package, create its import DAG. // For each initial package, create its import DAG.
for _, lpkg := range initial { for _, lpkg := range initial {
visit(lpkg) visit(nil, lpkg)
} }
} else { } else {
@@ -909,16 +922,45 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
// Load type data and syntax if needed, starting at // Load type data and syntax if needed, starting at
// the initial packages (roots of the import DAG). // the initial packages (roots of the import DAG).
if ld.Mode&NeedTypes != 0 || ld.Mode&NeedSyntax != 0 { if ld.Mode&(NeedSyntax|NeedTypes|NeedTypesInfo) != 0 {
var wg sync.WaitGroup
for _, lpkg := range initial { // We avoid using g.SetLimit to limit concurrency as
wg.Add(1) // it makes g.Go stop accepting work, which prevents
go func(lpkg *loaderPackage) { // workers from enqeuing, and thus finishing, and thus
ld.loadRecursive(lpkg) // allowing the group to make progress: deadlock.
wg.Done() //
}(lpkg) // Instead we use the ioLimit and cpuLimit semaphores.
g, _ := errgroup.WithContext(ld.Context)
// enqueues adds a package to the type-checking queue.
// It must have no unfinished successors.
var enqueue func(*loaderPackage)
enqueue = func(lpkg *loaderPackage) {
g.Go(func() error {
// Parse and type-check.
ld.loadPackage(lpkg)
// Notify each waiting predecessor,
// and enqueue it when it becomes a leaf.
for _, pred := range lpkg.preds {
if pred.unfinishedSuccs.Add(-1) == 0 { // decref
enqueue(pred)
}
}
return nil
})
}
// Load leaves first, adding new packages
// to the queue as they become leaves.
for _, leaf := range leaves {
enqueue(leaf)
}
if err := g.Wait(); err != nil {
return nil, err // cancelled
} }
wg.Wait()
} }
// If the context is done, return its error and // If the context is done, return its error and
@@ -965,7 +1007,7 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
if ld.requestedMode&NeedSyntax == 0 { if ld.requestedMode&NeedSyntax == 0 {
ld.pkgs[i].Syntax = nil ld.pkgs[i].Syntax = nil
} }
if ld.requestedMode&NeedTypes == 0 && ld.requestedMode&NeedSyntax == 0 { if ld.requestedMode&(NeedSyntax|NeedTypes|NeedTypesInfo) == 0 {
ld.pkgs[i].Fset = nil ld.pkgs[i].Fset = nil
} }
if ld.requestedMode&NeedTypesInfo == 0 { if ld.requestedMode&NeedTypesInfo == 0 {
@@ -982,31 +1024,10 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
return result, nil return result, nil
} }
// loadRecursive loads the specified package and its dependencies, // loadPackage loads/parses/typechecks the specified package.
// recursively, in parallel, in topological order.
// It is atomic and idempotent.
// Precondition: ld.Mode&NeedTypes.
func (ld *loader) loadRecursive(lpkg *loaderPackage) {
lpkg.loadOnce.Do(func() {
// Load the direct dependencies, in parallel.
var wg sync.WaitGroup
for _, ipkg := range lpkg.Imports {
imp := ld.pkgs[ipkg.ID]
wg.Add(1)
go func(imp *loaderPackage) {
ld.loadRecursive(imp)
wg.Done()
}(imp)
}
wg.Wait()
ld.loadPackage(lpkg)
})
}
// loadPackage loads the specified package.
// It must be called only once per Package, // It must be called only once per Package,
// after immediate dependencies are loaded. // after immediate dependencies are loaded.
// Precondition: ld.Mode & NeedTypes. // Precondition: ld.Mode&(NeedSyntax|NeedTypes|NeedTypesInfo) != 0.
func (ld *loader) loadPackage(lpkg *loaderPackage) { func (ld *loader) loadPackage(lpkg *loaderPackage) {
if lpkg.PkgPath == "unsafe" { if lpkg.PkgPath == "unsafe" {
// Fill in the blanks to avoid surprises. // Fill in the blanks to avoid surprises.
@@ -1042,6 +1063,10 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
if !lpkg.needtypes && !lpkg.needsrc { if !lpkg.needtypes && !lpkg.needsrc {
return return
} }
// TODO(adonovan): this condition looks wrong:
// I think it should be lpkg.needtypes && !lpg.needsrc,
// so that NeedSyntax without NeedTypes can be satisfied by export data.
if !lpkg.needsrc { if !lpkg.needsrc {
if err := ld.loadFromExportData(lpkg); err != nil { if err := ld.loadFromExportData(lpkg); err != nil {
lpkg.Errors = append(lpkg.Errors, Error{ lpkg.Errors = append(lpkg.Errors, Error{
@@ -1147,7 +1172,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
} }
lpkg.Syntax = files lpkg.Syntax = files
if ld.Config.Mode&NeedTypes == 0 { if ld.Config.Mode&(NeedTypes|NeedTypesInfo) == 0 {
return return
} }
@@ -1158,6 +1183,9 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
return return
} }
// Populate TypesInfo only if needed, as it
// causes the type checker to work much harder.
if ld.Config.Mode&NeedTypesInfo != 0 {
lpkg.TypesInfo = &types.Info{ lpkg.TypesInfo = &types.Info{
Types: make(map[ast.Expr]types.TypeAndValue), Types: make(map[ast.Expr]types.TypeAndValue),
Defs: make(map[*ast.Ident]types.Object), Defs: make(map[*ast.Ident]types.Object),
@@ -1166,8 +1194,9 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
Instances: make(map[*ast.Ident]types.Instance), Instances: make(map[*ast.Ident]types.Instance),
Scopes: make(map[ast.Node]*types.Scope), Scopes: make(map[ast.Node]*types.Scope),
Selections: make(map[*ast.SelectorExpr]*types.Selection), Selections: make(map[*ast.SelectorExpr]*types.Selection),
FileVersions: make(map[*ast.File]string),
}
} }
versions.InitFileVersions(lpkg.TypesInfo)
lpkg.TypesSizes = ld.sizes lpkg.TypesSizes = ld.sizes
importer := importerFunc(func(path string) (*types.Package, error) { importer := importerFunc(func(path string) (*types.Package, error) {
@@ -1220,6 +1249,10 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
} }
} }
// Type-checking is CPU intensive.
cpuLimit <- unit{} // acquire a token
defer func() { <-cpuLimit }() // release a token
typErr := types.NewChecker(tc, ld.Fset, lpkg.Types, lpkg.TypesInfo).Files(lpkg.Syntax) typErr := types.NewChecker(tc, ld.Fset, lpkg.Types, lpkg.TypesInfo).Files(lpkg.Syntax)
lpkg.importErrors = nil // no longer needed lpkg.importErrors = nil // no longer needed
@@ -1284,8 +1317,11 @@ type importerFunc func(path string) (*types.Package, error)
func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) } func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }
// We use a counting semaphore to limit // We use a counting semaphore to limit
// the number of parallel I/O calls per process. // the number of parallel I/O calls or CPU threads per process.
var ioLimit = make(chan bool, 20) var (
ioLimit = make(chan unit, 20)
cpuLimit = make(chan unit, runtime.GOMAXPROCS(0))
)
func (ld *loader) parseFile(filename string) (*ast.File, error) { func (ld *loader) parseFile(filename string) (*ast.File, error) {
ld.parseCacheMu.Lock() ld.parseCacheMu.Lock()
@@ -1302,20 +1338,28 @@ func (ld *loader) parseFile(filename string) (*ast.File, error) {
var src []byte var src []byte
for f, contents := range ld.Config.Overlay { for f, contents := range ld.Config.Overlay {
// TODO(adonovan): Inefficient for large overlays.
// Do an exact name-based map lookup
// (for nonexistent files) followed by a
// FileID-based map lookup (for existing ones).
if sameFile(f, filename) { if sameFile(f, filename) {
src = contents src = contents
break
} }
} }
var err error var err error
if src == nil { if src == nil {
ioLimit <- true // wait ioLimit <- unit{} // acquire a token
src, err = os.ReadFile(filename) src, err = os.ReadFile(filename)
<-ioLimit // signal <-ioLimit // release a token
} }
if err != nil { if err != nil {
v.err = err v.err = err
} else { } else {
// Parsing is CPU intensive.
cpuLimit <- unit{} // acquire a token
v.f, v.err = ld.ParseFile(ld.Fset, filename, src) v.f, v.err = ld.ParseFile(ld.Fset, filename, src)
<-cpuLimit // release a token
} }
close(v.ready) close(v.ready)
@@ -1330,18 +1374,21 @@ func (ld *loader) parseFile(filename string) (*ast.File, error) {
// Because files are scanned in parallel, the token.Pos // Because files are scanned in parallel, the token.Pos
// positions of the resulting ast.Files are not ordered. // positions of the resulting ast.Files are not ordered.
func (ld *loader) parseFiles(filenames []string) ([]*ast.File, []error) { func (ld *loader) parseFiles(filenames []string) ([]*ast.File, []error) {
var wg sync.WaitGroup var (
n := len(filenames) n = len(filenames)
parsed := make([]*ast.File, n) parsed = make([]*ast.File, n)
errors := make([]error, n) errors = make([]error, n)
for i, file := range filenames { )
wg.Add(1) var g errgroup.Group
go func(i int, filename string) { for i, filename := range filenames {
// This creates goroutines unnecessarily in the
// cache-hit case, but that case is uncommon.
g.Go(func() error {
parsed[i], errors[i] = ld.parseFile(filename) parsed[i], errors[i] = ld.parseFile(filename)
wg.Done() return nil
}(i, file) })
} }
wg.Wait() g.Wait()
// Eliminate nils, preserving order. // Eliminate nils, preserving order.
var o int var o int
@@ -1512,4 +1559,4 @@ func usesExportData(cfg *Config) bool {
return cfg.Mode&NeedExportFile != 0 || cfg.Mode&NeedTypes != 0 && cfg.Mode&NeedDeps == 0 return cfg.Mode&NeedExportFile != 0 || cfg.Mode&NeedTypes != 0 && cfg.Mode&NeedDeps == 0
} }
var _ interface{} = io.Discard // assert build toolchain is go1.16 or later type unit struct{}

View File

@@ -228,7 +228,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
// Reject obviously non-viable cases. // Reject obviously non-viable cases.
switch obj := obj.(type) { switch obj := obj.(type) {
case *types.TypeName: case *types.TypeName:
if _, ok := aliases.Unalias(obj.Type()).(*types.TypeParam); !ok { if _, ok := types.Unalias(obj.Type()).(*types.TypeParam); !ok {
// With the exception of type parameters, only package-level type names // With the exception of type parameters, only package-level type names
// have a path. // have a path.
return "", fmt.Errorf("no path for %v", obj) return "", fmt.Errorf("no path for %v", obj)
@@ -280,26 +280,26 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
path = append(path, opType) path = append(path, opType)
T := o.Type() T := o.Type()
if alias, ok := T.(*aliases.Alias); ok { if alias, ok := T.(*types.Alias); ok {
if r := findTypeParam(obj, aliases.TypeParams(alias), path, opTypeParam, nil); r != nil { if r := findTypeParam(obj, aliases.TypeParams(alias), path, opTypeParam); r != nil {
return Path(r), nil return Path(r), nil
} }
if r := find(obj, aliases.Rhs(alias), append(path, opRhs), nil); r != nil { if r := find(obj, aliases.Rhs(alias), append(path, opRhs)); r != nil {
return Path(r), nil return Path(r), nil
} }
} else if tname.IsAlias() { } else if tname.IsAlias() {
// legacy alias // legacy alias
if r := find(obj, T, path, nil); r != nil { if r := find(obj, T, path); r != nil {
return Path(r), nil return Path(r), nil
} }
} else if named, ok := T.(*types.Named); ok { } else if named, ok := T.(*types.Named); ok {
// defined (named) type // defined (named) type
if r := findTypeParam(obj, named.TypeParams(), path, opTypeParam, nil); r != nil { if r := findTypeParam(obj, named.TypeParams(), path, opTypeParam); r != nil {
return Path(r), nil return Path(r), nil
} }
if r := find(obj, named.Underlying(), append(path, opUnderlying), nil); r != nil { if r := find(obj, named.Underlying(), append(path, opUnderlying)); r != nil {
return Path(r), nil return Path(r), nil
} }
} }
@@ -312,7 +312,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
if _, ok := o.(*types.TypeName); !ok { if _, ok := o.(*types.TypeName); !ok {
if o.Exported() { if o.Exported() {
// exported non-type (const, var, func) // exported non-type (const, var, func)
if r := find(obj, o.Type(), append(path, opType), nil); r != nil { if r := find(obj, o.Type(), append(path, opType)); r != nil {
return Path(r), nil return Path(r), nil
} }
} }
@@ -320,7 +320,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
} }
// Inspect declared methods of defined types. // Inspect declared methods of defined types.
if T, ok := aliases.Unalias(o.Type()).(*types.Named); ok { if T, ok := types.Unalias(o.Type()).(*types.Named); ok {
path = append(path, opType) path = append(path, opType)
// The method index here is always with respect // The method index here is always with respect
// to the underlying go/types data structures, // to the underlying go/types data structures,
@@ -332,7 +332,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
if m == obj { if m == obj {
return Path(path2), nil // found declared method return Path(path2), nil // found declared method
} }
if r := find(obj, m.Type(), append(path2, opType), nil); r != nil { if r := find(obj, m.Type(), append(path2, opType)); r != nil {
return Path(r), nil return Path(r), nil
} }
} }
@@ -447,46 +447,64 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) {
// //
// The seen map is used to short circuit cycles through type parameters. If // The seen map is used to short circuit cycles through type parameters. If
// nil, it will be allocated as necessary. // nil, it will be allocated as necessary.
func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]bool) []byte { //
// The seenMethods map is used internally to short circuit cycles through
// interface methods, such as occur in the following example:
//
// type I interface { f() interface{I} }
//
// See golang/go#68046 for details.
func find(obj types.Object, T types.Type, path []byte) []byte {
return (&finder{obj: obj}).find(T, path)
}
// finder closes over search state for a call to find.
type finder struct {
obj types.Object // the sought object
seenTParamNames map[*types.TypeName]bool // for cycle breaking through type parameters
seenMethods map[*types.Func]bool // for cycle breaking through recursive interfaces
}
func (f *finder) find(T types.Type, path []byte) []byte {
switch T := T.(type) { switch T := T.(type) {
case *aliases.Alias: case *types.Alias:
return find(obj, aliases.Unalias(T), path, seen) return f.find(types.Unalias(T), path)
case *types.Basic, *types.Named: case *types.Basic, *types.Named:
// Named types belonging to pkg were handled already, // Named types belonging to pkg were handled already,
// so T must belong to another package. No path. // so T must belong to another package. No path.
return nil return nil
case *types.Pointer: case *types.Pointer:
return find(obj, T.Elem(), append(path, opElem), seen) return f.find(T.Elem(), append(path, opElem))
case *types.Slice: case *types.Slice:
return find(obj, T.Elem(), append(path, opElem), seen) return f.find(T.Elem(), append(path, opElem))
case *types.Array: case *types.Array:
return find(obj, T.Elem(), append(path, opElem), seen) return f.find(T.Elem(), append(path, opElem))
case *types.Chan: case *types.Chan:
return find(obj, T.Elem(), append(path, opElem), seen) return f.find(T.Elem(), append(path, opElem))
case *types.Map: case *types.Map:
if r := find(obj, T.Key(), append(path, opKey), seen); r != nil { if r := f.find(T.Key(), append(path, opKey)); r != nil {
return r return r
} }
return find(obj, T.Elem(), append(path, opElem), seen) return f.find(T.Elem(), append(path, opElem))
case *types.Signature: case *types.Signature:
if r := findTypeParam(obj, T.RecvTypeParams(), path, opRecvTypeParam, nil); r != nil { if r := f.findTypeParam(T.RecvTypeParams(), path, opRecvTypeParam); r != nil {
return r return r
} }
if r := findTypeParam(obj, T.TypeParams(), path, opTypeParam, seen); r != nil { if r := f.findTypeParam(T.TypeParams(), path, opTypeParam); r != nil {
return r return r
} }
if r := find(obj, T.Params(), append(path, opParams), seen); r != nil { if r := f.find(T.Params(), append(path, opParams)); r != nil {
return r return r
} }
return find(obj, T.Results(), append(path, opResults), seen) return f.find(T.Results(), append(path, opResults))
case *types.Struct: case *types.Struct:
for i := 0; i < T.NumFields(); i++ { for i := 0; i < T.NumFields(); i++ {
fld := T.Field(i) fld := T.Field(i)
path2 := appendOpArg(path, opField, i) path2 := appendOpArg(path, opField, i)
if fld == obj { if fld == f.obj {
return path2 // found field var return path2 // found field var
} }
if r := find(obj, fld.Type(), append(path2, opType), seen); r != nil { if r := f.find(fld.Type(), append(path2, opType)); r != nil {
return r return r
} }
} }
@@ -495,10 +513,10 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]
for i := 0; i < T.Len(); i++ { for i := 0; i < T.Len(); i++ {
v := T.At(i) v := T.At(i)
path2 := appendOpArg(path, opAt, i) path2 := appendOpArg(path, opAt, i)
if v == obj { if v == f.obj {
return path2 // found param/result var return path2 // found param/result var
} }
if r := find(obj, v.Type(), append(path2, opType), seen); r != nil { if r := f.find(v.Type(), append(path2, opType)); r != nil {
return r return r
} }
} }
@@ -506,28 +524,35 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]
case *types.Interface: case *types.Interface:
for i := 0; i < T.NumMethods(); i++ { for i := 0; i < T.NumMethods(); i++ {
m := T.Method(i) m := T.Method(i)
if f.seenMethods[m] {
return nil
}
path2 := appendOpArg(path, opMethod, i) path2 := appendOpArg(path, opMethod, i)
if m == obj { if m == f.obj {
return path2 // found interface method return path2 // found interface method
} }
if r := find(obj, m.Type(), append(path2, opType), seen); r != nil { if f.seenMethods == nil {
f.seenMethods = make(map[*types.Func]bool)
}
f.seenMethods[m] = true
if r := f.find(m.Type(), append(path2, opType)); r != nil {
return r return r
} }
} }
return nil return nil
case *types.TypeParam: case *types.TypeParam:
name := T.Obj() name := T.Obj()
if name == obj { if f.seenTParamNames[name] {
return append(path, opObj)
}
if seen[name] {
return nil return nil
} }
if seen == nil { if name == f.obj {
seen = make(map[*types.TypeName]bool) return append(path, opObj)
} }
seen[name] = true if f.seenTParamNames == nil {
if r := find(obj, T.Constraint(), append(path, opConstraint), seen); r != nil { f.seenTParamNames = make(map[*types.TypeName]bool)
}
f.seenTParamNames[name] = true
if r := f.find(T.Constraint(), append(path, opConstraint)); r != nil {
return r return r
} }
return nil return nil
@@ -535,11 +560,15 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]
panic(T) panic(T)
} }
func findTypeParam(obj types.Object, list *types.TypeParamList, path []byte, op byte, seen map[*types.TypeName]bool) []byte { func findTypeParam(obj types.Object, list *types.TypeParamList, path []byte, op byte) []byte {
return (&finder{obj: obj}).findTypeParam(list, path, op)
}
func (f *finder) findTypeParam(list *types.TypeParamList, path []byte, op byte) []byte {
for i := 0; i < list.Len(); i++ { for i := 0; i < list.Len(); i++ {
tparam := list.At(i) tparam := list.At(i)
path2 := appendOpArg(path, op, i) path2 := appendOpArg(path, op, i)
if r := find(obj, tparam, path2, seen); r != nil { if r := f.find(tparam, path2); r != nil {
return r return r
} }
} }
@@ -626,7 +655,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
// Inv: t != nil, obj == nil // Inv: t != nil, obj == nil
t = aliases.Unalias(t) t = types.Unalias(t)
switch code { switch code {
case opElem: case opElem:
hasElem, ok := t.(hasElem) // Pointer, Slice, Array, Chan, Map hasElem, ok := t.(hasElem) // Pointer, Slice, Array, Chan, Map
@@ -664,7 +693,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
t = named.Underlying() t = named.Underlying()
case opRhs: case opRhs:
if alias, ok := t.(*aliases.Alias); ok { if alias, ok := t.(*types.Alias); ok {
t = aliases.Rhs(alias) t = aliases.Rhs(alias)
} else if false && aliases.Enabled() { } else if false && aliases.Enabled() {
// The Enabled check is too expensive, so for now we // The Enabled check is too expensive, so for now we

Some files were not shown because too many files have changed in this diff Show More