mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-08-14 15:55:54 +08:00
Compare commits
130 Commits
v0.21.0
...
v0.23.0-rc
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f58f0221e2 | ||
![]() |
9696b50d1e | ||
![]() |
15495efa86 | ||
![]() |
bde47313d4 | ||
![]() |
d69301d57b | ||
![]() |
ee77cdb175 | ||
![]() |
8fb1157b5f | ||
![]() |
a34cdff84e | ||
![]() |
77139daa4b | ||
![]() |
10e3892a63 | ||
![]() |
d80ece5bb3 | ||
![]() |
1f44971fc9 | ||
![]() |
a91db7ccc9 | ||
![]() |
98c3abb756 | ||
![]() |
3b824a0e39 | ||
![]() |
b0156cd631 | ||
![]() |
29614f9734 | ||
![]() |
f1b895196c | ||
![]() |
900502b139 | ||
![]() |
49bd7e4edc | ||
![]() |
8f9c25e8b0 | ||
![]() |
7659798f80 | ||
![]() |
7b8bf9f801 | ||
![]() |
8efc528b84 | ||
![]() |
8593e0397b | ||
![]() |
0c0e8eefdf | ||
![]() |
e114dd09a5 | ||
![]() |
d25e260d2e | ||
![]() |
86e4e77ac1 | ||
![]() |
534d9fc276 | ||
![]() |
e0c67bfc79 | ||
![]() |
53e576b306 | ||
![]() |
d3aef6642c | ||
![]() |
824cef1b92 | ||
![]() |
a8b0fa8965 | ||
![]() |
45dfb84361 | ||
![]() |
13ef01196d | ||
![]() |
646df6d4a0 | ||
![]() |
d46c1d8141 | ||
![]() |
c682742de0 | ||
![]() |
391acba718 | ||
![]() |
db4b96e62c | ||
![]() |
882ef0db91 | ||
![]() |
967fc2a696 | ||
![]() |
212d598ab1 | ||
![]() |
bf95aa3dfa | ||
![]() |
18ccba0720 | ||
![]() |
f5196f1167 | ||
![]() |
ef99381eab | ||
![]() |
a41c9fa649 | ||
![]() |
00fdcd38ab | ||
![]() |
97f1d47464 | ||
![]() |
337578242d | ||
![]() |
503a8925d2 | ||
![]() |
0d708c0bc2 | ||
![]() |
3a7523a117 | ||
![]() |
5dc1a3308d | ||
![]() |
eb78253dfd | ||
![]() |
5f8b78a113 | ||
![]() |
67d3ed34e4 | ||
![]() |
b88423be50 | ||
![]() |
c1e2ae5636 | ||
![]() |
23afb70e40 | ||
![]() |
812b42b329 | ||
![]() |
d5d3d3d502 | ||
![]() |
e19c729d3e | ||
![]() |
aefa49c4fa | ||
![]() |
7d927ee604 | ||
![]() |
058c098c8c | ||
![]() |
7b7dbe88b1 | ||
![]() |
cadf4a5893 | ||
![]() |
6cd9fef556 | ||
![]() |
963b9ca30d | ||
![]() |
4636c8051a | ||
![]() |
e23695d50d | ||
![]() |
6eff9b2d51 | ||
![]() |
fcbfc85f42 | ||
![]() |
9a204c44c3 | ||
![]() |
4c6eba5acd | ||
![]() |
fea7459880 | ||
![]() |
e2d52a8465 | ||
![]() |
48a591b1e1 | ||
![]() |
128acdb471 | ||
![]() |
411d3f8cea | ||
![]() |
7925a96726 | ||
![]() |
b06bddfee6 | ||
![]() |
fe17ebda89 | ||
![]() |
4ed1e07f16 | ||
![]() |
f49593ce2c | ||
![]() |
4e91fe6507 | ||
![]() |
921b576f3a | ||
![]() |
548c80ab5a | ||
![]() |
f3a4740d5f | ||
![]() |
89917dc696 | ||
![]() |
f7276201ac | ||
![]() |
beb9f515c0 | ||
![]() |
4f7d145c0e | ||
![]() |
ccdf63c644 | ||
![]() |
9a6b8754b1 | ||
![]() |
e75ac22ba6 | ||
![]() |
62f5cc7c80 | ||
![]() |
6272ae1afa | ||
![]() |
accfbf6e24 | ||
![]() |
af2d8fe555 | ||
![]() |
18f4275a92 | ||
![]() |
221a608b3c | ||
![]() |
cc0391eba5 | ||
![]() |
aef388bf7a | ||
![]() |
80c16bc28c | ||
![]() |
75160643e1 | ||
![]() |
ad18ffc018 | ||
![]() |
80c3832c94 | ||
![]() |
7762ab2c38 | ||
![]() |
b973de2dd3 | ||
![]() |
352ce7e875 | ||
![]() |
cdfc1ed750 | ||
![]() |
d0d3433b12 | ||
![]() |
b04d39494f | ||
![]() |
52f503e806 | ||
![]() |
79a978484d | ||
![]() |
f7992033bf | ||
![]() |
73f61aa338 | ||
![]() |
faa573f484 | ||
![]() |
0a4a1babd1 | ||
![]() |
461bd9e5d1 | ||
![]() |
d6fdf83f45 | ||
![]() |
ef4e9fea83 | ||
![]() |
0c296fe857 | ||
![]() |
2dc0350ffe | ||
![]() |
b85fc5c484 |
26
.github/workflows/build.yml
vendored
26
.github/workflows/build.yml
vendored
@@ -54,9 +54,9 @@ jobs:
|
||||
- master
|
||||
- latest
|
||||
- buildx-stable-1
|
||||
- v0.20.2
|
||||
- v0.19.0
|
||||
- v0.18.2
|
||||
- v0.17.2
|
||||
worker:
|
||||
- docker-container
|
||||
- remote
|
||||
@@ -76,6 +76,16 @@ jobs:
|
||||
- worker: docker+containerd # same as docker, but with containerd snapshotter
|
||||
pkg: ./tests
|
||||
mode: experimental
|
||||
- worker: "docker@27.5"
|
||||
pkg: ./tests
|
||||
- worker: "docker+containerd@27.5" # same as docker, but with containerd snapshotter
|
||||
pkg: ./tests
|
||||
- worker: "docker@27.5"
|
||||
pkg: ./tests
|
||||
mode: experimental
|
||||
- worker: "docker+containerd@27.5" # same as docker, but with containerd snapshotter
|
||||
pkg: ./tests
|
||||
mode: experimental
|
||||
- worker: "docker@26.1"
|
||||
pkg: ./tests
|
||||
- worker: "docker+containerd@26.1" # same as docker, but with containerd snapshotter
|
||||
@@ -248,12 +258,17 @@ jobs:
|
||||
matrix:
|
||||
os:
|
||||
- freebsd
|
||||
- netbsd
|
||||
- openbsd
|
||||
steps:
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
echo "VAGRANT_FILE=hack/Vagrantfile.${{ matrix.os }}" >> $GITHUB_ENV
|
||||
|
||||
# Sets semver Go version to be able to download tarball during vagrant setup
|
||||
goVersion=$(curl --silent "https://go.dev/dl/?mode=json&include=all" | jq -r '.[].files[].version' | uniq | sed -e 's/go//' | sort -V | grep $GO_VERSION | tail -1)
|
||||
echo "GO_VERSION=$goVersion" >> $GITHUB_ENV
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -396,6 +411,15 @@ jobs:
|
||||
- test-unit
|
||||
if: ${{ github.event_name != 'pull_request' && github.repository == 'docker/buildx' }}
|
||||
steps:
|
||||
-
|
||||
name: Free disk space
|
||||
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
|
||||
with:
|
||||
android: true
|
||||
dotnet: true
|
||||
haskell: true
|
||||
large-packages: true
|
||||
swap-storage: true
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
2
.github/workflows/docs-release.yml
vendored
2
.github/workflows/docs-release.yml
vendored
@@ -77,7 +77,7 @@ jobs:
|
||||
VENDOR_MODULE: github.com/docker/buildx@${{ env.RELEASE_NAME }}
|
||||
-
|
||||
name: Create PR on docs repo
|
||||
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
|
||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
||||
with:
|
||||
token: ${{ secrets.GHPAT_DOCS_DISPATCH }}
|
||||
push-to-fork: docker-tools-robot/docker.github.io
|
||||
|
6
.github/workflows/e2e.yml
vendored
6
.github/workflows/e2e.yml
vendored
@@ -29,7 +29,7 @@ env:
|
||||
SETUP_BUILDX_VERSION: "edge"
|
||||
SETUP_BUILDKIT_IMAGE: "moby/buildkit:latest"
|
||||
DESTDIR: "./bin"
|
||||
K3S_VERSION: "v1.21.2-k3s1"
|
||||
K3S_VERSION: "v1.32.2+k3s1"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
retention-days: 7
|
||||
|
||||
driver:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- build
|
||||
strategy:
|
||||
@@ -153,7 +153,7 @@ jobs:
|
||||
-
|
||||
name: Install k3s
|
||||
if: matrix.driver == 'kubernetes'
|
||||
uses: crazy-max/.github/.github/actions/install-k3s@fa6141aedf23596fb8bdcceab9cce8dadaa31bd9
|
||||
uses: crazy-max/.github/.github/actions/install-k3s@7730d1434364d4b9aded32735b078a7ace5ea79a
|
||||
with:
|
||||
version: ${{ env.K3S_VERSION }}
|
||||
-
|
||||
|
@@ -1,9 +1,6 @@
|
||||
run:
|
||||
timeout: 30m
|
||||
modules-download-mode: vendor
|
||||
# default uses Go version from the go.mod file, fallback on the env var
|
||||
# `GOVERSION`, fallback on 1.17: https://golangci-lint.run/usage/configuration/#run-configuration
|
||||
go: "1.23"
|
||||
|
||||
linters:
|
||||
enable:
|
||||
|
20
Dockerfile
20
Dockerfile
@@ -5,20 +5,23 @@ ARG ALPINE_VERSION=3.21
|
||||
ARG XX_VERSION=1.6.1
|
||||
|
||||
# for testing
|
||||
ARG DOCKER_VERSION=28.0.0-rc.1
|
||||
ARG DOCKER_VERSION=28.0.0
|
||||
ARG DOCKER_VERSION_ALT_27=27.5.1
|
||||
ARG DOCKER_VERSION_ALT_26=26.1.3
|
||||
ARG DOCKER_CLI_VERSION=${DOCKER_VERSION}
|
||||
ARG GOTESTSUM_VERSION=v1.12.0
|
||||
ARG REGISTRY_VERSION=2.8.3
|
||||
ARG BUILDKIT_VERSION=v0.19.0
|
||||
ARG BUILDKIT_VERSION=v0.20.2
|
||||
ARG UNDOCK_VERSION=0.9.0
|
||||
|
||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
||||
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS golatest
|
||||
FROM moby/moby-bin:$DOCKER_VERSION AS docker-engine
|
||||
FROM dockereng/cli-bin:$DOCKER_CLI_VERSION AS docker-cli
|
||||
FROM moby/moby-bin:$DOCKER_VERSION_ALT_26 AS docker-engine-alt
|
||||
FROM dockereng/cli-bin:$DOCKER_VERSION_ALT_26 AS docker-cli-alt
|
||||
FROM moby/moby-bin:$DOCKER_VERSION_ALT_27 AS docker-engine-alt27
|
||||
FROM moby/moby-bin:$DOCKER_VERSION_ALT_26 AS docker-engine-alt26
|
||||
FROM dockereng/cli-bin:$DOCKER_VERSION_ALT_27 AS docker-cli-alt27
|
||||
FROM dockereng/cli-bin:$DOCKER_VERSION_ALT_26 AS docker-cli-alt26
|
||||
FROM registry:$REGISTRY_VERSION AS registry
|
||||
FROM moby/buildkit:$BUILDKIT_VERSION AS buildkit
|
||||
FROM crazymax/undock:$UNDOCK_VERSION AS undock
|
||||
@@ -102,6 +105,7 @@ COPY --link --from=buildx-build /usr/bin/docker-buildx /buildx
|
||||
FROM binaries-unix AS binaries-darwin
|
||||
FROM binaries-unix AS binaries-freebsd
|
||||
FROM binaries-unix AS binaries-linux
|
||||
FROM binaries-unix AS binaries-netbsd
|
||||
FROM binaries-unix AS binaries-openbsd
|
||||
|
||||
FROM scratch AS binaries-windows
|
||||
@@ -127,13 +131,15 @@ COPY --link --from=gotestsum /out /usr/bin/
|
||||
COPY --link --from=registry /bin/registry /usr/bin/
|
||||
COPY --link --from=docker-engine / /usr/bin/
|
||||
COPY --link --from=docker-cli / /usr/bin/
|
||||
COPY --link --from=docker-engine-alt / /opt/docker-alt-26/
|
||||
COPY --link --from=docker-cli-alt / /opt/docker-alt-26/
|
||||
COPY --link --from=docker-engine-alt27 / /opt/docker-alt-27/
|
||||
COPY --link --from=docker-engine-alt26 / /opt/docker-alt-26/
|
||||
COPY --link --from=docker-cli-alt27 / /opt/docker-alt-27/
|
||||
COPY --link --from=docker-cli-alt26 / /opt/docker-alt-26/
|
||||
COPY --link --from=buildkit /usr/bin/buildkitd /usr/bin/
|
||||
COPY --link --from=buildkit /usr/bin/buildctl /usr/bin/
|
||||
COPY --link --from=undock /usr/local/bin/undock /usr/bin/
|
||||
COPY --link --from=binaries /buildx /usr/bin/
|
||||
ENV TEST_DOCKER_EXTRA="docker@26.1=/opt/docker-alt-26"
|
||||
ENV TEST_DOCKER_EXTRA="docker@27.5=/opt/docker-alt-27,docker@26.1=/opt/docker-alt-26"
|
||||
|
||||
FROM integration-test-base AS integration-test
|
||||
COPY . .
|
||||
|
@@ -21,7 +21,7 @@
|
||||
- [Verify essential information](#verify-essential-information)
|
||||
- [Classify the issue](#classify-the-issue)
|
||||
- [Prioritization guidelines for `kind/bug`](#prioritization-guidelines-for-kindbug)
|
||||
- [Issue lifecyle](#issue-lifecyle)
|
||||
- [Issue lifecycle](#issue-lifecycle)
|
||||
- [Examples](#examples)
|
||||
- [Submitting a bug](#submitting-a-bug)
|
||||
- [Pull request review process](#pull-request-review-process)
|
||||
@@ -308,7 +308,7 @@ Examples:
|
||||
- Bugs in non-default configurations
|
||||
- Most enhancements
|
||||
|
||||
## Issue lifecyle
|
||||
## Issue lifecycle
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
|
132
bake/bake.go
132
bake/bake.go
@@ -3,7 +3,9 @@ package bake
|
||||
import (
|
||||
"context"
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"maps"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -27,7 +29,6 @@ import (
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/client/llb"
|
||||
"github.com/moby/buildkit/session/auth/authprovider"
|
||||
"github.com/moby/buildkit/util/entitlements"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/convert"
|
||||
@@ -46,6 +47,7 @@ type File struct {
|
||||
type Override struct {
|
||||
Value string
|
||||
ArrValue []string
|
||||
Append bool
|
||||
}
|
||||
|
||||
func defaultFilenames() []string {
|
||||
@@ -486,10 +488,8 @@ func (c Config) loadLinks(name string, t *Target, m map[string]*Target, o map[st
|
||||
if target == name {
|
||||
return errors.Errorf("target %s cannot link to itself", target)
|
||||
}
|
||||
for _, v := range visited {
|
||||
if v == target {
|
||||
return errors.Errorf("infinite loop from %s to %s", name, target)
|
||||
}
|
||||
if slices.Contains(visited, target) {
|
||||
return errors.Errorf("infinite loop from %s to %s", name, target)
|
||||
}
|
||||
t2, ok := m[target]
|
||||
if !ok {
|
||||
@@ -529,9 +529,12 @@ func (c Config) newOverrides(v []string) (map[string]map[string]Override, error)
|
||||
m := map[string]map[string]Override{}
|
||||
for _, v := range v {
|
||||
parts := strings.SplitN(v, "=", 2)
|
||||
keys := strings.SplitN(parts[0], ".", 3)
|
||||
|
||||
skey := strings.TrimSuffix(parts[0], "+")
|
||||
appendTo := strings.HasSuffix(parts[0], "+")
|
||||
keys := strings.SplitN(skey, ".", 3)
|
||||
if len(keys) < 2 {
|
||||
return nil, errors.Errorf("invalid override key %s, expected target.name", parts[0])
|
||||
return nil, errors.Errorf("invalid override key %s, expected target.name", skey)
|
||||
}
|
||||
|
||||
pattern := keys[0]
|
||||
@@ -544,8 +547,7 @@ func (c Config) newOverrides(v []string) (map[string]map[string]Override, error)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kk := strings.SplitN(parts[0], ".", 2)
|
||||
|
||||
okey := strings.Join(keys[1:], ".")
|
||||
for _, name := range names {
|
||||
t, ok := m[name]
|
||||
if !ok {
|
||||
@@ -553,14 +555,15 @@ func (c Config) newOverrides(v []string) (map[string]map[string]Override, error)
|
||||
m[name] = t
|
||||
}
|
||||
|
||||
o := t[kk[1]]
|
||||
override := t[okey]
|
||||
|
||||
// IMPORTANT: if you add more fields here, do not forget to update
|
||||
// docs/bake-reference.md and https://docs.docker.com/build/bake/overrides/
|
||||
// docs/reference/buildx_bake.md (--set) and https://docs.docker.com/build/bake/overrides/
|
||||
switch keys[1] {
|
||||
case "output", "cache-to", "cache-from", "tags", "platform", "secrets", "ssh", "attest", "entitlements", "network":
|
||||
case "output", "cache-to", "cache-from", "tags", "platform", "secrets", "ssh", "attest", "entitlements", "network", "annotations":
|
||||
if len(parts) == 2 {
|
||||
o.ArrValue = append(o.ArrValue, parts[1])
|
||||
override.Append = appendTo
|
||||
override.ArrValue = append(override.ArrValue, parts[1])
|
||||
}
|
||||
case "args":
|
||||
if len(keys) != 3 {
|
||||
@@ -571,7 +574,7 @@ func (c Config) newOverrides(v []string) (map[string]map[string]Override, error)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
o.Value = v
|
||||
override.Value = v
|
||||
}
|
||||
fallthrough
|
||||
case "contexts":
|
||||
@@ -581,11 +584,11 @@ func (c Config) newOverrides(v []string) (map[string]map[string]Override, error)
|
||||
fallthrough
|
||||
default:
|
||||
if len(parts) == 2 {
|
||||
o.Value = parts[1]
|
||||
override.Value = parts[1]
|
||||
}
|
||||
}
|
||||
|
||||
t[kk[1]] = o
|
||||
t[okey] = override
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
@@ -731,6 +734,41 @@ type Target struct {
|
||||
linked bool
|
||||
}
|
||||
|
||||
func (t *Target) MarshalJSON() ([]byte, error) {
|
||||
tgt := *t
|
||||
esc := func(s string) string {
|
||||
return strings.ReplaceAll(strings.ReplaceAll(s, "${", "$${"), "%{", "%%{")
|
||||
}
|
||||
|
||||
tgt.Annotations = slices.Clone(t.Annotations)
|
||||
for i, v := range tgt.Annotations {
|
||||
tgt.Annotations[i] = esc(v)
|
||||
}
|
||||
|
||||
if tgt.DockerfileInline != nil {
|
||||
escaped := esc(*tgt.DockerfileInline)
|
||||
tgt.DockerfileInline = &escaped
|
||||
}
|
||||
|
||||
tgt.Labels = maps.Clone(t.Labels)
|
||||
for k, v := range t.Labels {
|
||||
if v != nil {
|
||||
escaped := esc(*v)
|
||||
tgt.Labels[k] = &escaped
|
||||
}
|
||||
}
|
||||
|
||||
tgt.Args = maps.Clone(t.Args)
|
||||
for k, v := range t.Args {
|
||||
if v != nil {
|
||||
escaped := esc(*v)
|
||||
tgt.Args[k] = &escaped
|
||||
}
|
||||
}
|
||||
|
||||
return json.Marshal(tgt)
|
||||
}
|
||||
|
||||
var (
|
||||
_ hclparser.WithEvalContexts = &Target{}
|
||||
_ hclparser.WithGetName = &Target{}
|
||||
@@ -897,13 +935,21 @@ func (t *Target) AddOverrides(overrides map[string]Override, ent *EntitlementCon
|
||||
}
|
||||
t.Labels[keys[1]] = &value
|
||||
case "tags":
|
||||
t.Tags = o.ArrValue
|
||||
if o.Append {
|
||||
t.Tags = append(t.Tags, o.ArrValue...)
|
||||
} else {
|
||||
t.Tags = o.ArrValue
|
||||
}
|
||||
case "cache-from":
|
||||
cacheFrom, err := buildflags.ParseCacheEntry(o.ArrValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.CacheFrom = cacheFrom
|
||||
if o.Append {
|
||||
t.CacheFrom = t.CacheFrom.Merge(cacheFrom)
|
||||
} else {
|
||||
t.CacheFrom = cacheFrom
|
||||
}
|
||||
for _, c := range t.CacheFrom {
|
||||
if c.Type == "local" {
|
||||
if v, ok := c.Attrs["src"]; ok {
|
||||
@@ -916,7 +962,11 @@ func (t *Target) AddOverrides(overrides map[string]Override, ent *EntitlementCon
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.CacheTo = cacheTo
|
||||
if o.Append {
|
||||
t.CacheTo = t.CacheTo.Merge(cacheTo)
|
||||
} else {
|
||||
t.CacheTo = cacheTo
|
||||
}
|
||||
for _, c := range t.CacheTo {
|
||||
if c.Type == "local" {
|
||||
if v, ok := c.Attrs["dest"]; ok {
|
||||
@@ -933,7 +983,11 @@ func (t *Target) AddOverrides(overrides map[string]Override, ent *EntitlementCon
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid value for outputs")
|
||||
}
|
||||
t.Secrets = secrets
|
||||
if o.Append {
|
||||
t.Secrets = t.Secrets.Merge(secrets)
|
||||
} else {
|
||||
t.Secrets = secrets
|
||||
}
|
||||
for _, s := range t.Secrets {
|
||||
if s.FilePath != "" {
|
||||
ent.FSRead = append(ent.FSRead, s.FilePath)
|
||||
@@ -944,18 +998,30 @@ func (t *Target) AddOverrides(overrides map[string]Override, ent *EntitlementCon
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid value for outputs")
|
||||
}
|
||||
t.SSH = ssh
|
||||
if o.Append {
|
||||
t.SSH = t.SSH.Merge(ssh)
|
||||
} else {
|
||||
t.SSH = ssh
|
||||
}
|
||||
for _, s := range t.SSH {
|
||||
ent.FSRead = append(ent.FSRead, s.Paths...)
|
||||
}
|
||||
case "platform":
|
||||
t.Platforms = o.ArrValue
|
||||
if o.Append {
|
||||
t.Platforms = append(t.Platforms, o.ArrValue...)
|
||||
} else {
|
||||
t.Platforms = o.ArrValue
|
||||
}
|
||||
case "output":
|
||||
outputs, err := parseArrValue[buildflags.ExportEntry](o.ArrValue)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid value for outputs")
|
||||
}
|
||||
t.Outputs = outputs
|
||||
if o.Append {
|
||||
t.Outputs = t.Outputs.Merge(outputs)
|
||||
} else {
|
||||
t.Outputs = outputs
|
||||
}
|
||||
for _, o := range t.Outputs {
|
||||
if o.Destination != "" {
|
||||
ent.FSWrite = append(ent.FSWrite, o.Destination)
|
||||
@@ -985,11 +1051,19 @@ func (t *Target) AddOverrides(overrides map[string]Override, ent *EntitlementCon
|
||||
}
|
||||
t.NoCache = &noCache
|
||||
case "no-cache-filter":
|
||||
t.NoCacheFilter = o.ArrValue
|
||||
if o.Append {
|
||||
t.NoCacheFilter = append(t.NoCacheFilter, o.ArrValue...)
|
||||
} else {
|
||||
t.NoCacheFilter = o.ArrValue
|
||||
}
|
||||
case "shm-size":
|
||||
t.ShmSize = &value
|
||||
case "ulimits":
|
||||
t.Ulimits = o.ArrValue
|
||||
if o.Append {
|
||||
t.Ulimits = append(t.Ulimits, o.ArrValue...)
|
||||
} else {
|
||||
t.Ulimits = o.ArrValue
|
||||
}
|
||||
case "network":
|
||||
t.NetworkMode = &value
|
||||
case "pull":
|
||||
@@ -1067,9 +1141,7 @@ func (t *Target) GetEvalContexts(ectx *hcl.EvalContext, block *hcl.Block, loadDe
|
||||
e2 := ectx.NewChild()
|
||||
e2.Variables = make(map[string]cty.Value)
|
||||
if e != ectx {
|
||||
for k, v := range e.Variables {
|
||||
e2.Variables[k] = v
|
||||
}
|
||||
maps.Copy(e2.Variables, e.Variables)
|
||||
}
|
||||
e2.Variables[k] = v
|
||||
ectxs2 = append(ectxs2, e2)
|
||||
@@ -1434,9 +1506,7 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
|
||||
}
|
||||
bo.Ulimits = ulimits
|
||||
|
||||
for _, ent := range t.Entitlements {
|
||||
bo.Allow = append(bo.Allow, entitlements.Entitlement(ent))
|
||||
}
|
||||
bo.Allow = append(bo.Allow, t.Entitlements...)
|
||||
|
||||
return bo, nil
|
||||
}
|
||||
|
@@ -34,6 +34,18 @@ target "webapp" {
|
||||
args = {
|
||||
VAR_BOTH = "webapp"
|
||||
}
|
||||
annotations = [
|
||||
"index,manifest:org.opencontainers.image.authors=dvdksn"
|
||||
]
|
||||
attest = [
|
||||
"type=provenance,mode=max"
|
||||
]
|
||||
platforms = [
|
||||
"linux/amd64"
|
||||
]
|
||||
secret = [
|
||||
"id=FOO,env=FOO"
|
||||
]
|
||||
inherits = ["webDEP"]
|
||||
}`),
|
||||
}
|
||||
@@ -115,6 +127,31 @@ target "webapp" {
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("AnnotationsOverrides", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m, g, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.annotations=index,manifest:org.opencontainers.image.vendor=docker"}, nil, &EntitlementConf{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []string{"index,manifest:org.opencontainers.image.authors=dvdksn", "index,manifest:org.opencontainers.image.vendor=docker"}, m["webapp"].Annotations)
|
||||
require.Equal(t, 1, len(g))
|
||||
require.Equal(t, []string{"webapp"}, g["default"].Targets)
|
||||
})
|
||||
|
||||
t.Run("AttestOverride", func(t *testing.T) {
|
||||
m, _, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.attest=type=sbom"}, nil, &EntitlementConf{})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, m["webapp"].Attest, 2)
|
||||
require.Equal(t, "provenance", m["webapp"].Attest[0].Type)
|
||||
require.Equal(t, "sbom", m["webapp"].Attest[1].Type)
|
||||
})
|
||||
|
||||
t.Run("AttestAppend", func(t *testing.T) {
|
||||
m, _, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.attest+=type=sbom"}, nil, &EntitlementConf{})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, m["webapp"].Attest, 2)
|
||||
require.Equal(t, "provenance", m["webapp"].Attest[0].Type)
|
||||
require.Equal(t, "sbom", m["webapp"].Attest[1].Type)
|
||||
})
|
||||
|
||||
t.Run("ContextOverride", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, _, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.context"}, nil, &EntitlementConf{})
|
||||
@@ -136,6 +173,49 @@ target "webapp" {
|
||||
require.Equal(t, []string{"webapp"}, g["default"].Targets)
|
||||
})
|
||||
|
||||
t.Run("PlatformOverride", func(t *testing.T) {
|
||||
m, _, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.platform=linux/arm64"}, nil, &EntitlementConf{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []string{"linux/arm64"}, m["webapp"].Platforms)
|
||||
})
|
||||
|
||||
t.Run("PlatformAppend", func(t *testing.T) {
|
||||
m, _, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.platform+=linux/arm64"}, nil, &EntitlementConf{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []string{"linux/amd64", "linux/arm64"}, m["webapp"].Platforms)
|
||||
})
|
||||
|
||||
t.Run("PlatformAppendMulti", func(t *testing.T) {
|
||||
m, _, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.platform+=linux/arm64", "webapp.platform+=linux/riscv64"}, nil, &EntitlementConf{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []string{"linux/amd64", "linux/arm64", "linux/riscv64"}, m["webapp"].Platforms)
|
||||
})
|
||||
|
||||
t.Run("PlatformAppendMultiLastOverride", func(t *testing.T) {
|
||||
m, _, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.platform+=linux/arm64", "webapp.platform=linux/riscv64"}, nil, &EntitlementConf{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []string{"linux/arm64", "linux/riscv64"}, m["webapp"].Platforms)
|
||||
})
|
||||
|
||||
t.Run("SecretsOverride", func(t *testing.T) {
|
||||
t.Setenv("FOO", "foo")
|
||||
t.Setenv("BAR", "bar")
|
||||
m, _, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.secrets=id=BAR,env=BAR"}, nil, &EntitlementConf{})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, m["webapp"].Secrets, 1)
|
||||
require.Equal(t, "BAR", m["webapp"].Secrets[0].ID)
|
||||
})
|
||||
|
||||
t.Run("SecretsAppend", func(t *testing.T) {
|
||||
t.Setenv("FOO", "foo")
|
||||
t.Setenv("BAR", "bar")
|
||||
m, _, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.secrets+=id=BAR,env=BAR"}, nil, &EntitlementConf{})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, m["webapp"].Secrets, 2)
|
||||
require.Equal(t, "FOO", m["webapp"].Secrets[0].ID)
|
||||
require.Equal(t, "BAR", m["webapp"].Secrets[1].ID)
|
||||
})
|
||||
|
||||
t.Run("ShmSizeOverride", func(t *testing.T) {
|
||||
m, _, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.shm-size=256m"}, nil, &EntitlementConf{})
|
||||
require.NoError(t, err)
|
||||
@@ -1806,8 +1886,8 @@ func TestHCLEntitlements(t *testing.T) {
|
||||
require.Equal(t, "network.host", m["app"].Entitlements[1])
|
||||
|
||||
require.Len(t, bo["app"].Allow, 2)
|
||||
require.Equal(t, entitlements.EntitlementSecurityInsecure, bo["app"].Allow[0])
|
||||
require.Equal(t, entitlements.EntitlementNetworkHost, bo["app"].Allow[1])
|
||||
require.Equal(t, entitlements.EntitlementSecurityInsecure.String(), bo["app"].Allow[0])
|
||||
require.Equal(t, entitlements.EntitlementNetworkHost.String(), bo["app"].Allow[1])
|
||||
}
|
||||
|
||||
func TestEntitlementsForNetHostCompose(t *testing.T) {
|
||||
@@ -1846,7 +1926,7 @@ func TestEntitlementsForNetHostCompose(t *testing.T) {
|
||||
require.Equal(t, "host", *m["app"].NetworkMode)
|
||||
|
||||
require.Len(t, bo["app"].Allow, 1)
|
||||
require.Equal(t, entitlements.EntitlementNetworkHost, bo["app"].Allow[0])
|
||||
require.Equal(t, entitlements.EntitlementNetworkHost.String(), bo["app"].Allow[0])
|
||||
require.Equal(t, "host", bo["app"].NetworkMode)
|
||||
}
|
||||
|
||||
@@ -1877,7 +1957,7 @@ func TestEntitlementsForNetHost(t *testing.T) {
|
||||
require.Equal(t, "host", *m["app"].NetworkMode)
|
||||
|
||||
require.Len(t, bo["app"].Allow, 1)
|
||||
require.Equal(t, entitlements.EntitlementNetworkHost, bo["app"].Allow[0])
|
||||
require.Equal(t, entitlements.EntitlementNetworkHost.String(), bo["app"].Allow[0])
|
||||
require.Equal(t, "host", bo["app"].NetworkMode)
|
||||
}
|
||||
|
||||
@@ -2062,6 +2142,73 @@ target "app" {
|
||||
})
|
||||
}
|
||||
|
||||
func TestVariableValidationConditionNull(t *testing.T) {
|
||||
fp := File{
|
||||
Name: "docker-bake.hcl",
|
||||
Data: []byte(`
|
||||
variable "PORT" {
|
||||
default = 3000
|
||||
validation {}
|
||||
}
|
||||
target "app" {
|
||||
args = {
|
||||
PORT = PORT
|
||||
}
|
||||
}
|
||||
`),
|
||||
}
|
||||
|
||||
_, _, err := ReadTargets(context.TODO(), []File{fp}, []string{"app"}, nil, nil, &EntitlementConf{})
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "Condition expression must return either true or false, not null")
|
||||
}
|
||||
|
||||
func TestVariableValidationConditionUnknownValue(t *testing.T) {
|
||||
fp := File{
|
||||
Name: "docker-bake.hcl",
|
||||
Data: []byte(`
|
||||
variable "PORT" {
|
||||
default = 3000
|
||||
validation {
|
||||
condition = "foo"
|
||||
}
|
||||
}
|
||||
target "app" {
|
||||
args = {
|
||||
PORT = PORT
|
||||
}
|
||||
}
|
||||
`),
|
||||
}
|
||||
|
||||
_, _, err := ReadTargets(context.TODO(), []File{fp}, []string{"app"}, nil, nil, &EntitlementConf{})
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "Invalid condition result value: a bool is required")
|
||||
}
|
||||
|
||||
func TestVariableValidationInvalidErrorMessage(t *testing.T) {
|
||||
fp := File{
|
||||
Name: "docker-bake.hcl",
|
||||
Data: []byte(`
|
||||
variable "FOO" {
|
||||
default = 0
|
||||
validation {
|
||||
condition = FOO > 5
|
||||
}
|
||||
}
|
||||
target "app" {
|
||||
args = {
|
||||
FOO = FOO
|
||||
}
|
||||
}
|
||||
`),
|
||||
}
|
||||
|
||||
_, _, err := ReadTargets(context.TODO(), []File{fp}, []string{"app"}, nil, nil, &EntitlementConf{})
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "This check failed, but has an invalid error message")
|
||||
}
|
||||
|
||||
// https://github.com/docker/buildx/issues/2822
|
||||
func TestVariableEmpty(t *testing.T) {
|
||||
fp := File{
|
||||
|
@@ -92,6 +92,9 @@ func ParseCompose(cfgs []composetypes.ConfigFile, envs map[string]string) (*Conf
|
||||
if s.Build.AdditionalContexts != nil {
|
||||
additionalContexts = map[string]string{}
|
||||
for k, v := range s.Build.AdditionalContexts {
|
||||
if strings.HasPrefix(v, "service:") {
|
||||
v = strings.Replace(v, "service:", "target:", 1)
|
||||
}
|
||||
additionalContexts[k] = v
|
||||
}
|
||||
}
|
||||
@@ -174,6 +177,7 @@ func ParseCompose(cfgs []composetypes.ConfigFile, envs map[string]string) (*Conf
|
||||
CacheFrom: cacheFrom,
|
||||
CacheTo: cacheTo,
|
||||
NetworkMode: networkModeP,
|
||||
Platforms: s.Build.Platforms,
|
||||
SSH: ssh,
|
||||
Secrets: secrets,
|
||||
ShmSize: shmSize,
|
||||
@@ -214,7 +218,7 @@ func validateComposeFile(dt []byte, fn string) (bool, error) {
|
||||
}
|
||||
|
||||
func validateCompose(dt []byte, envs map[string]string) error {
|
||||
_, err := loader.Load(composetypes.ConfigDetails{
|
||||
_, err := loader.LoadWithContext(context.Background(), composetypes.ConfigDetails{
|
||||
ConfigFiles: []composetypes.ConfigFile{
|
||||
{
|
||||
Content: dt,
|
||||
@@ -315,7 +319,7 @@ type (
|
||||
stringArray []string
|
||||
)
|
||||
|
||||
func (sa *stringArray) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
func (sa *stringArray) UnmarshalYAML(unmarshal func(any) error) error {
|
||||
var multi []string
|
||||
err := unmarshal(&multi)
|
||||
if err != nil {
|
||||
@@ -332,7 +336,7 @@ func (sa *stringArray) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
|
||||
// composeExtTarget converts Compose build extension x-bake to bake Target
|
||||
// https://github.com/compose-spec/compose-spec/blob/master/spec.md#extension
|
||||
func (t *Target) composeExtTarget(exts map[string]interface{}) error {
|
||||
func (t *Target) composeExtTarget(exts map[string]any) error {
|
||||
var xb xbake
|
||||
|
||||
ext, ok := exts["x-bake"]
|
||||
|
@@ -463,6 +463,21 @@ services:
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestPlatforms(t *testing.T) {
|
||||
dt := []byte(`
|
||||
services:
|
||||
foo:
|
||||
build:
|
||||
context: .
|
||||
platforms:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
`)
|
||||
c, err := ParseCompose([]composetypes.ConfigFile{{Content: dt}}, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []string{"linux/amd64", "linux/arm64"}, c.Targets[0].Platforms)
|
||||
}
|
||||
|
||||
func newBool(val bool) *bool {
|
||||
b := val
|
||||
return &b
|
||||
@@ -798,6 +813,37 @@ services:
|
||||
})
|
||||
}
|
||||
|
||||
func TestServiceContext(t *testing.T) {
|
||||
dt := []byte(`
|
||||
services:
|
||||
base:
|
||||
build:
|
||||
dockerfile: baseapp.Dockerfile
|
||||
command: ./entrypoint.sh
|
||||
webapp:
|
||||
build:
|
||||
context: ./dir
|
||||
additional_contexts:
|
||||
base: service:base
|
||||
`)
|
||||
|
||||
c, err := ParseCompose([]composetypes.ConfigFile{{Content: dt}}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(c.Groups))
|
||||
require.Equal(t, "default", c.Groups[0].Name)
|
||||
sort.Strings(c.Groups[0].Targets)
|
||||
require.Equal(t, []string{"base", "webapp"}, c.Groups[0].Targets)
|
||||
|
||||
require.Equal(t, 2, len(c.Targets))
|
||||
sort.Slice(c.Targets, func(i, j int) bool {
|
||||
return c.Targets[i].Name < c.Targets[j].Name
|
||||
})
|
||||
|
||||
require.Equal(t, "webapp", c.Targets[1].Name)
|
||||
require.Equal(t, map[string]string{"base": "target:base"}, c.Targets[1].Contexts)
|
||||
}
|
||||
|
||||
// chdir changes the current working directory to the named directory,
|
||||
// and then restore the original working directory at the end of the test.
|
||||
func chdir(t *testing.T, dir string) {
|
||||
|
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/moby/buildkit/util/entitlements"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/tonistiigi/go-csvvalue"
|
||||
)
|
||||
|
||||
type EntitlementKey string
|
||||
@@ -27,6 +28,7 @@ type EntitlementKey string
|
||||
const (
|
||||
EntitlementKeyNetworkHost EntitlementKey = "network.host"
|
||||
EntitlementKeySecurityInsecure EntitlementKey = "security.insecure"
|
||||
EntitlementKeyDevice EntitlementKey = "device"
|
||||
EntitlementKeyFSRead EntitlementKey = "fs.read"
|
||||
EntitlementKeyFSWrite EntitlementKey = "fs.write"
|
||||
EntitlementKeyFS EntitlementKey = "fs"
|
||||
@@ -39,6 +41,7 @@ const (
|
||||
type EntitlementConf struct {
|
||||
NetworkHost bool
|
||||
SecurityInsecure bool
|
||||
Devices *EntitlementsDevicesConf
|
||||
FSRead []string
|
||||
FSWrite []string
|
||||
ImagePush []string
|
||||
@@ -46,6 +49,11 @@ type EntitlementConf struct {
|
||||
SSH bool
|
||||
}
|
||||
|
||||
type EntitlementsDevicesConf struct {
|
||||
All bool
|
||||
Devices map[string]struct{}
|
||||
}
|
||||
|
||||
func ParseEntitlements(in []string) (EntitlementConf, error) {
|
||||
var conf EntitlementConf
|
||||
for _, e := range in {
|
||||
@@ -59,6 +67,22 @@ func ParseEntitlements(in []string) (EntitlementConf, error) {
|
||||
default:
|
||||
k, v, _ := strings.Cut(e, "=")
|
||||
switch k {
|
||||
case string(EntitlementKeyDevice):
|
||||
if v == "" {
|
||||
conf.Devices = &EntitlementsDevicesConf{All: true}
|
||||
continue
|
||||
}
|
||||
fields, err := csvvalue.Fields(v, nil)
|
||||
if err != nil {
|
||||
return EntitlementConf{}, errors.Wrapf(err, "failed to parse device entitlement %q", v)
|
||||
}
|
||||
if conf.Devices == nil {
|
||||
conf.Devices = &EntitlementsDevicesConf{}
|
||||
}
|
||||
if conf.Devices.Devices == nil {
|
||||
conf.Devices.Devices = make(map[string]struct{}, 0)
|
||||
}
|
||||
conf.Devices.Devices[fields[0]] = struct{}{}
|
||||
case string(EntitlementKeyFSRead):
|
||||
conf.FSRead = append(conf.FSRead, v)
|
||||
case string(EntitlementKeyFSWrite):
|
||||
@@ -95,12 +119,34 @@ func (c EntitlementConf) Validate(m map[string]build.Options) (EntitlementConf,
|
||||
|
||||
func (c EntitlementConf) check(bo build.Options, expected *EntitlementConf) error {
|
||||
for _, e := range bo.Allow {
|
||||
k, rest, _ := strings.Cut(e, "=")
|
||||
switch k {
|
||||
case entitlements.EntitlementDevice.String():
|
||||
if rest == "" {
|
||||
if c.Devices == nil || !c.Devices.All {
|
||||
expected.Devices = &EntitlementsDevicesConf{All: true}
|
||||
}
|
||||
continue
|
||||
}
|
||||
fields, err := csvvalue.Fields(rest, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse device entitlement %q", rest)
|
||||
}
|
||||
if expected.Devices == nil {
|
||||
expected.Devices = &EntitlementsDevicesConf{}
|
||||
}
|
||||
if expected.Devices.Devices == nil {
|
||||
expected.Devices.Devices = make(map[string]struct{}, 0)
|
||||
}
|
||||
expected.Devices.Devices[fields[0]] = struct{}{}
|
||||
}
|
||||
|
||||
switch e {
|
||||
case entitlements.EntitlementNetworkHost:
|
||||
case entitlements.EntitlementNetworkHost.String():
|
||||
if !c.NetworkHost {
|
||||
expected.NetworkHost = true
|
||||
}
|
||||
case entitlements.EntitlementSecurityInsecure:
|
||||
case entitlements.EntitlementSecurityInsecure.String():
|
||||
if !c.SecurityInsecure {
|
||||
expected.SecurityInsecure = true
|
||||
}
|
||||
@@ -187,6 +233,18 @@ func (c EntitlementConf) Prompt(ctx context.Context, isRemote bool, out io.Write
|
||||
flags = append(flags, string(EntitlementKeySecurityInsecure))
|
||||
}
|
||||
|
||||
if c.Devices != nil {
|
||||
if c.Devices.All {
|
||||
msgs = append(msgs, " - Access to CDI devices")
|
||||
flags = append(flags, string(EntitlementKeyDevice))
|
||||
} else {
|
||||
for d := range c.Devices.Devices {
|
||||
msgs = append(msgs, fmt.Sprintf(" - Access to device %s", d))
|
||||
flags = append(flags, string(EntitlementKeyDevice)+"="+d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if c.SSH {
|
||||
msgsFS = append(msgsFS, " - Forwarding default SSH agent socket")
|
||||
flagsFS = append(flagsFS, string(EntitlementKeySSH))
|
||||
@@ -248,7 +306,7 @@ func (c EntitlementConf) Prompt(ctx context.Context, isRemote bool, out io.Write
|
||||
fmt.Fprintf(out, "\nPass %q to grant requested privileges.\n", strings.Join(slices.Concat(flags, flagsFS), " "))
|
||||
}
|
||||
|
||||
args := append([]string(nil), os.Args...)
|
||||
args := slices.Clone(os.Args)
|
||||
if v, ok := os.LookupEnv("DOCKER_CLI_PLUGIN_ORIGINAL_CLI_COMMAND"); ok && v != "" {
|
||||
args[0] = v
|
||||
}
|
||||
|
@@ -208,8 +208,8 @@ func TestValidateEntitlements(t *testing.T) {
|
||||
{
|
||||
name: "NetworkHostMissing",
|
||||
opt: build.Options{
|
||||
Allow: []entitlements.Entitlement{
|
||||
entitlements.EntitlementNetworkHost,
|
||||
Allow: []string{
|
||||
entitlements.EntitlementNetworkHost.String(),
|
||||
},
|
||||
},
|
||||
expected: EntitlementConf{
|
||||
@@ -223,8 +223,8 @@ func TestValidateEntitlements(t *testing.T) {
|
||||
NetworkHost: true,
|
||||
},
|
||||
opt: build.Options{
|
||||
Allow: []entitlements.Entitlement{
|
||||
entitlements.EntitlementNetworkHost,
|
||||
Allow: []string{
|
||||
entitlements.EntitlementNetworkHost.String(),
|
||||
},
|
||||
},
|
||||
expected: EntitlementConf{
|
||||
@@ -234,9 +234,9 @@ func TestValidateEntitlements(t *testing.T) {
|
||||
{
|
||||
name: "SecurityAndNetworkHostMissing",
|
||||
opt: build.Options{
|
||||
Allow: []entitlements.Entitlement{
|
||||
entitlements.EntitlementNetworkHost,
|
||||
entitlements.EntitlementSecurityInsecure,
|
||||
Allow: []string{
|
||||
entitlements.EntitlementNetworkHost.String(),
|
||||
entitlements.EntitlementSecurityInsecure.String(),
|
||||
},
|
||||
},
|
||||
expected: EntitlementConf{
|
||||
@@ -251,9 +251,9 @@ func TestValidateEntitlements(t *testing.T) {
|
||||
NetworkHost: true,
|
||||
},
|
||||
opt: build.Options{
|
||||
Allow: []entitlements.Entitlement{
|
||||
entitlements.EntitlementNetworkHost,
|
||||
entitlements.EntitlementSecurityInsecure,
|
||||
Allow: []string{
|
||||
entitlements.EntitlementNetworkHost.String(),
|
||||
entitlements.EntitlementSecurityInsecure.String(),
|
||||
},
|
||||
},
|
||||
expected: EntitlementConf{
|
||||
|
@@ -608,7 +608,7 @@ func TestHCLAttrsCapsuleType(t *testing.T) {
|
||||
target "app" {
|
||||
attest = [
|
||||
{ type = "provenance", mode = "max" },
|
||||
"type=sbom,disabled=true",
|
||||
"type=sbom,disabled=true,generator=foo,\"ENV1=bar,baz\",ENV2=hello",
|
||||
]
|
||||
|
||||
cache-from = [
|
||||
@@ -641,7 +641,7 @@ func TestHCLAttrsCapsuleType(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(c.Targets))
|
||||
require.Equal(t, []string{"type=provenance,mode=max", "type=sbom,disabled=true"}, stringify(c.Targets[0].Attest))
|
||||
require.Equal(t, []string{"type=provenance,mode=max", "type=sbom,disabled=true,\"ENV1=bar,baz\",ENV2=hello,generator=foo"}, stringify(c.Targets[0].Attest))
|
||||
require.Equal(t, []string{"type=local,dest=../out", "type=oci,dest=../out.tar"}, stringify(c.Targets[0].Outputs))
|
||||
require.Equal(t, []string{"type=local,src=path/to/cache", "user/app:cache"}, stringify(c.Targets[0].CacheFrom))
|
||||
require.Equal(t, []string{"type=local,dest=path/to/cache"}, stringify(c.Targets[0].CacheTo))
|
||||
@@ -1645,7 +1645,7 @@ func TestHCLIndexOfFunc(t *testing.T) {
|
||||
require.Empty(t, c.Targets[1].Tags[1])
|
||||
}
|
||||
|
||||
func ptrstr(s interface{}) *string {
|
||||
func ptrstr(s any) *string {
|
||||
var n *string
|
||||
if reflect.ValueOf(s).Kind() == reflect.String {
|
||||
ss := s.(string)
|
||||
|
@@ -15,11 +15,11 @@ import (
|
||||
|
||||
// DecodeOptions allows customizing sections of the decoding process.
|
||||
type DecodeOptions struct {
|
||||
ImpliedType func(gv interface{}) (cty.Type, error)
|
||||
ImpliedType func(gv any) (cty.Type, error)
|
||||
Convert func(in cty.Value, want cty.Type) (cty.Value, error)
|
||||
}
|
||||
|
||||
func (o DecodeOptions) DecodeBody(body hcl.Body, ctx *hcl.EvalContext, val interface{}) hcl.Diagnostics {
|
||||
func (o DecodeOptions) DecodeBody(body hcl.Body, ctx *hcl.EvalContext, val any) hcl.Diagnostics {
|
||||
o = o.withDefaults()
|
||||
|
||||
rv := reflect.ValueOf(val)
|
||||
@@ -46,7 +46,7 @@ func (o DecodeOptions) DecodeBody(body hcl.Body, ctx *hcl.EvalContext, val inter
|
||||
// are returned then the given value may have been partially-populated but
|
||||
// may still be accessed by a careful caller for static analysis and editor
|
||||
// integration use-cases.
|
||||
func DecodeBody(body hcl.Body, ctx *hcl.EvalContext, val interface{}) hcl.Diagnostics {
|
||||
func DecodeBody(body hcl.Body, ctx *hcl.EvalContext, val any) hcl.Diagnostics {
|
||||
return DecodeOptions{}.DecodeBody(body, ctx, val)
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ func (o DecodeOptions) decodeBlockToValue(block *hcl.Block, ctx *hcl.EvalContext
|
||||
return diags
|
||||
}
|
||||
|
||||
func (o DecodeOptions) DecodeExpression(expr hcl.Expression, ctx *hcl.EvalContext, val interface{}) hcl.Diagnostics {
|
||||
func (o DecodeOptions) DecodeExpression(expr hcl.Expression, ctx *hcl.EvalContext, val any) hcl.Diagnostics {
|
||||
o = o.withDefaults()
|
||||
|
||||
srcVal, diags := expr.Value(ctx)
|
||||
@@ -332,7 +332,7 @@ func (o DecodeOptions) DecodeExpression(expr hcl.Expression, ctx *hcl.EvalContex
|
||||
// are returned then the given value may have been partially-populated but
|
||||
// may still be accessed by a careful caller for static analysis and editor
|
||||
// integration use-cases.
|
||||
func DecodeExpression(expr hcl.Expression, ctx *hcl.EvalContext, val interface{}) hcl.Diagnostics {
|
||||
func DecodeExpression(expr hcl.Expression, ctx *hcl.EvalContext, val any) hcl.Diagnostics {
|
||||
return DecodeOptions{}.DecodeExpression(expr, ctx, val)
|
||||
}
|
||||
|
||||
|
@@ -16,8 +16,8 @@ import (
|
||||
)
|
||||
|
||||
func TestDecodeBody(t *testing.T) {
|
||||
deepEquals := func(other interface{}) func(v interface{}) bool {
|
||||
return func(v interface{}) bool {
|
||||
deepEquals := func(other any) func(v any) bool {
|
||||
return func(v any) bool {
|
||||
return reflect.DeepEqual(v, other)
|
||||
}
|
||||
}
|
||||
@@ -45,19 +45,19 @@ func TestDecodeBody(t *testing.T) {
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
Body map[string]interface{}
|
||||
Target func() interface{}
|
||||
Check func(v interface{}) bool
|
||||
Body map[string]any
|
||||
Target func() any
|
||||
Check func(v any) bool
|
||||
DiagCount int
|
||||
}{
|
||||
{
|
||||
map[string]interface{}{},
|
||||
map[string]any{},
|
||||
makeInstantiateType(struct{}{}),
|
||||
deepEquals(struct{}{}),
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{},
|
||||
map[string]any{},
|
||||
makeInstantiateType(struct {
|
||||
Name string `hcl:"name"`
|
||||
}{}),
|
||||
@@ -67,7 +67,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
1, // name is required
|
||||
},
|
||||
{
|
||||
map[string]interface{}{},
|
||||
map[string]any{},
|
||||
makeInstantiateType(struct {
|
||||
Name *string `hcl:"name"`
|
||||
}{}),
|
||||
@@ -77,7 +77,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
}, // name nil
|
||||
{
|
||||
map[string]interface{}{},
|
||||
map[string]any{},
|
||||
makeInstantiateType(struct {
|
||||
Name string `hcl:"name,optional"`
|
||||
}{}),
|
||||
@@ -87,9 +87,9 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
}, // name optional
|
||||
{
|
||||
map[string]interface{}{},
|
||||
map[string]any{},
|
||||
makeInstantiateType(withNameExpression{}),
|
||||
func(v interface{}) bool {
|
||||
func(v any) bool {
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
@@ -109,11 +109,11 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"name": "Ermintrude",
|
||||
},
|
||||
makeInstantiateType(withNameExpression{}),
|
||||
func(v interface{}) bool {
|
||||
func(v any) bool {
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
@@ -133,7 +133,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"name": "Ermintrude",
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
@@ -145,7 +145,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"name": "Ermintrude",
|
||||
"age": 23,
|
||||
},
|
||||
@@ -158,7 +158,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
1, // Extraneous "age" property
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"name": "Ermintrude",
|
||||
"age": 50,
|
||||
},
|
||||
@@ -166,7 +166,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
Name string `hcl:"name"`
|
||||
Attrs hcl.Attributes `hcl:",remain"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
got := gotI.(struct {
|
||||
Name string `hcl:"name"`
|
||||
Attrs hcl.Attributes `hcl:",remain"`
|
||||
@@ -176,7 +176,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"name": "Ermintrude",
|
||||
"age": 50,
|
||||
},
|
||||
@@ -184,7 +184,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
Name string `hcl:"name"`
|
||||
Remain hcl.Body `hcl:",remain"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
got := gotI.(struct {
|
||||
Name string `hcl:"name"`
|
||||
Remain hcl.Body `hcl:",remain"`
|
||||
@@ -197,7 +197,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"name": "Ermintrude",
|
||||
"living": true,
|
||||
},
|
||||
@@ -217,7 +217,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"name": "Ermintrude",
|
||||
"age": 50,
|
||||
},
|
||||
@@ -226,7 +226,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
Body hcl.Body `hcl:",body"`
|
||||
Remain hcl.Body `hcl:",remain"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
got := gotI.(struct {
|
||||
Name string `hcl:"name"`
|
||||
Body hcl.Body `hcl:",body"`
|
||||
@@ -241,76 +241,76 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": map[string]interface{}{},
|
||||
map[string]any{
|
||||
"noodle": map[string]any{},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
Noodle struct{} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
// Generating no diagnostics is good enough for this one.
|
||||
return true
|
||||
},
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": []map[string]interface{}{{}},
|
||||
map[string]any{
|
||||
"noodle": []map[string]any{{}},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
Noodle struct{} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
// Generating no diagnostics is good enough for this one.
|
||||
return true
|
||||
},
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": []map[string]interface{}{{}, {}},
|
||||
map[string]any{
|
||||
"noodle": []map[string]any{{}, {}},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
Noodle struct{} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
// Generating one diagnostic is good enough for this one.
|
||||
return true
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{},
|
||||
map[string]any{},
|
||||
makeInstantiateType(struct {
|
||||
Noodle struct{} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
// Generating one diagnostic is good enough for this one.
|
||||
return true
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": []map[string]interface{}{},
|
||||
map[string]any{
|
||||
"noodle": []map[string]any{},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
Noodle struct{} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
// Generating one diagnostic is good enough for this one.
|
||||
return true
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": map[string]interface{}{},
|
||||
map[string]any{
|
||||
"noodle": map[string]any{},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
Noodle *struct{} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
return gotI.(struct {
|
||||
Noodle *struct{} `hcl:"noodle,block"`
|
||||
}).Noodle != nil
|
||||
@@ -318,13 +318,13 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": []map[string]interface{}{{}},
|
||||
map[string]any{
|
||||
"noodle": []map[string]any{{}},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
Noodle *struct{} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
return gotI.(struct {
|
||||
Noodle *struct{} `hcl:"noodle,block"`
|
||||
}).Noodle != nil
|
||||
@@ -332,13 +332,13 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": []map[string]interface{}{},
|
||||
map[string]any{
|
||||
"noodle": []map[string]any{},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
Noodle *struct{} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
return gotI.(struct {
|
||||
Noodle *struct{} `hcl:"noodle,block"`
|
||||
}).Noodle == nil
|
||||
@@ -346,26 +346,26 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": []map[string]interface{}{{}, {}},
|
||||
map[string]any{
|
||||
"noodle": []map[string]any{{}, {}},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
Noodle *struct{} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
// Generating one diagnostic is good enough for this one.
|
||||
return true
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": []map[string]interface{}{},
|
||||
map[string]any{
|
||||
"noodle": []map[string]any{},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
Noodle []struct{} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
noodle := gotI.(struct {
|
||||
Noodle []struct{} `hcl:"noodle,block"`
|
||||
}).Noodle
|
||||
@@ -374,13 +374,13 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": []map[string]interface{}{{}},
|
||||
map[string]any{
|
||||
"noodle": []map[string]any{{}},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
Noodle []struct{} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
noodle := gotI.(struct {
|
||||
Noodle []struct{} `hcl:"noodle,block"`
|
||||
}).Noodle
|
||||
@@ -389,13 +389,13 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": []map[string]interface{}{{}, {}},
|
||||
map[string]any{
|
||||
"noodle": []map[string]any{{}, {}},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
Noodle []struct{} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
noodle := gotI.(struct {
|
||||
Noodle []struct{} `hcl:"noodle,block"`
|
||||
}).Noodle
|
||||
@@ -404,15 +404,15 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": map[string]interface{}{},
|
||||
map[string]any{
|
||||
"noodle": map[string]any{},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
Noodle struct {
|
||||
Name string `hcl:"name,label"`
|
||||
} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
//nolint:misspell
|
||||
// Generating two diagnostics is good enough for this one.
|
||||
// (one for the missing noodle block and the other for
|
||||
@@ -423,9 +423,9 @@ func TestDecodeBody(t *testing.T) {
|
||||
2,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": map[string]interface{}{
|
||||
"foo_foo": map[string]interface{}{},
|
||||
map[string]any{
|
||||
"noodle": map[string]any{
|
||||
"foo_foo": map[string]any{},
|
||||
},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
@@ -433,7 +433,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
Name string `hcl:"name,label"`
|
||||
} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
noodle := gotI.(struct {
|
||||
Noodle struct {
|
||||
Name string `hcl:"name,label"`
|
||||
@@ -444,10 +444,10 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": map[string]interface{}{
|
||||
"foo_foo": map[string]interface{}{},
|
||||
"bar_baz": map[string]interface{}{},
|
||||
map[string]any{
|
||||
"noodle": map[string]any{
|
||||
"foo_foo": map[string]any{},
|
||||
"bar_baz": map[string]any{},
|
||||
},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
@@ -455,17 +455,17 @@ func TestDecodeBody(t *testing.T) {
|
||||
Name string `hcl:"name,label"`
|
||||
} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
// One diagnostic is enough for this one.
|
||||
return true
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": map[string]interface{}{
|
||||
"foo_foo": map[string]interface{}{},
|
||||
"bar_baz": map[string]interface{}{},
|
||||
map[string]any{
|
||||
"noodle": map[string]any{
|
||||
"foo_foo": map[string]any{},
|
||||
"bar_baz": map[string]any{},
|
||||
},
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
@@ -473,7 +473,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
Name string `hcl:"name,label"`
|
||||
} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
noodles := gotI.(struct {
|
||||
Noodles []struct {
|
||||
Name string `hcl:"name,label"`
|
||||
@@ -484,9 +484,9 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": map[string]interface{}{
|
||||
"foo_foo": map[string]interface{}{
|
||||
map[string]any{
|
||||
"noodle": map[string]any{
|
||||
"foo_foo": map[string]any{
|
||||
"type": "rice",
|
||||
},
|
||||
},
|
||||
@@ -497,7 +497,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
Type string `hcl:"type"`
|
||||
} `hcl:"noodle,block"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
noodle := gotI.(struct {
|
||||
Noodle struct {
|
||||
Name string `hcl:"name,label"`
|
||||
@@ -510,7 +510,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"name": "Ermintrude",
|
||||
"age": 34,
|
||||
},
|
||||
@@ -522,31 +522,31 @@ func TestDecodeBody(t *testing.T) {
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"name": "Ermintrude",
|
||||
"age": 89,
|
||||
},
|
||||
makeInstantiateType(map[string]*hcl.Attribute(nil)),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
got := gotI.(map[string]*hcl.Attribute)
|
||||
return len(got) == 2 && got["name"] != nil && got["age"] != nil
|
||||
},
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"name": "Ermintrude",
|
||||
"age": 13,
|
||||
},
|
||||
makeInstantiateType(map[string]hcl.Expression(nil)),
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
got := gotI.(map[string]hcl.Expression)
|
||||
return len(got) == 2 && got["name"] != nil && got["age"] != nil
|
||||
},
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"name": "Ermintrude",
|
||||
"living": true,
|
||||
},
|
||||
@@ -559,10 +559,10 @@ func TestDecodeBody(t *testing.T) {
|
||||
},
|
||||
{
|
||||
// Retain "nested" block while decoding
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"plain": "foo",
|
||||
},
|
||||
func() interface{} {
|
||||
func() any {
|
||||
return &withNestedBlock{
|
||||
Plain: "bar",
|
||||
Nested: &withTwoAttributes{
|
||||
@@ -570,7 +570,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
},
|
||||
}
|
||||
},
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
foo := gotI.(withNestedBlock)
|
||||
return foo.Plain == "foo" && foo.Nested != nil && foo.Nested.A == "bar"
|
||||
},
|
||||
@@ -578,19 +578,19 @@ func TestDecodeBody(t *testing.T) {
|
||||
},
|
||||
{
|
||||
// Retain values in "nested" block while decoding
|
||||
map[string]interface{}{
|
||||
"nested": map[string]interface{}{
|
||||
map[string]any{
|
||||
"nested": map[string]any{
|
||||
"a": "foo",
|
||||
},
|
||||
},
|
||||
func() interface{} {
|
||||
func() any {
|
||||
return &withNestedBlock{
|
||||
Nested: &withTwoAttributes{
|
||||
B: "bar",
|
||||
},
|
||||
}
|
||||
},
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
foo := gotI.(withNestedBlock)
|
||||
return foo.Nested.A == "foo" && foo.Nested.B == "bar"
|
||||
},
|
||||
@@ -598,14 +598,14 @@ func TestDecodeBody(t *testing.T) {
|
||||
},
|
||||
{
|
||||
// Retain values in "nested" block list while decoding
|
||||
map[string]interface{}{
|
||||
"nested": []map[string]interface{}{
|
||||
map[string]any{
|
||||
"nested": []map[string]any{
|
||||
{
|
||||
"a": "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
func() interface{} {
|
||||
func() any {
|
||||
return &withListofNestedBlocks{
|
||||
Nested: []*withTwoAttributes{
|
||||
{
|
||||
@@ -614,7 +614,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
},
|
||||
}
|
||||
},
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
n := gotI.(withListofNestedBlocks)
|
||||
return n.Nested[0].A == "foo" && n.Nested[0].B == "bar"
|
||||
},
|
||||
@@ -622,14 +622,14 @@ func TestDecodeBody(t *testing.T) {
|
||||
},
|
||||
{
|
||||
// Remove additional elements from the list while decoding nested blocks
|
||||
map[string]interface{}{
|
||||
"nested": []map[string]interface{}{
|
||||
map[string]any{
|
||||
"nested": []map[string]any{
|
||||
{
|
||||
"a": "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
func() interface{} {
|
||||
func() any {
|
||||
return &withListofNestedBlocks{
|
||||
Nested: []*withTwoAttributes{
|
||||
{
|
||||
@@ -641,7 +641,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
},
|
||||
}
|
||||
},
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
n := gotI.(withListofNestedBlocks)
|
||||
return len(n.Nested) == 1
|
||||
},
|
||||
@@ -649,8 +649,8 @@ func TestDecodeBody(t *testing.T) {
|
||||
},
|
||||
{
|
||||
// Make sure decoding value slices works the same as pointer slices.
|
||||
map[string]interface{}{
|
||||
"nested": []map[string]interface{}{
|
||||
map[string]any{
|
||||
"nested": []map[string]any{
|
||||
{
|
||||
"b": "bar",
|
||||
},
|
||||
@@ -659,7 +659,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
func() interface{} {
|
||||
func() any {
|
||||
return &withListofNestedBlocksNoPointers{
|
||||
Nested: []withTwoAttributes{
|
||||
{
|
||||
@@ -668,7 +668,7 @@ func TestDecodeBody(t *testing.T) {
|
||||
},
|
||||
}
|
||||
},
|
||||
func(gotI interface{}) bool {
|
||||
func(gotI any) bool {
|
||||
n := gotI.(withListofNestedBlocksNoPointers)
|
||||
return n.Nested[0].B == "bar" && len(n.Nested) == 2
|
||||
},
|
||||
@@ -710,8 +710,8 @@ func TestDecodeBody(t *testing.T) {
|
||||
func TestDecodeExpression(t *testing.T) {
|
||||
tests := []struct {
|
||||
Value cty.Value
|
||||
Target interface{}
|
||||
Want interface{}
|
||||
Target any
|
||||
Want any
|
||||
DiagCount int
|
||||
}{
|
||||
{
|
||||
@@ -799,8 +799,8 @@ func (e *fixedExpression) Variables() []hcl.Traversal {
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeInstantiateType(target interface{}) func() interface{} {
|
||||
return func() interface{} {
|
||||
func makeInstantiateType(target any) func() any {
|
||||
return func() any {
|
||||
return reflect.New(reflect.TypeOf(target)).Interface()
|
||||
}
|
||||
}
|
||||
|
@@ -34,9 +34,9 @@ import (
|
||||
// The layout of the resulting HCL source is derived from the ordering of
|
||||
// the struct fields, with blank lines around nested blocks of different types.
|
||||
// Fields representing attributes should usually precede those representing
|
||||
// blocks so that the attributes can group togather in the result. For more
|
||||
// blocks so that the attributes can group together in the result. For more
|
||||
// control, use the hclwrite API directly.
|
||||
func EncodeIntoBody(val interface{}, dst *hclwrite.Body) {
|
||||
func EncodeIntoBody(val any, dst *hclwrite.Body) {
|
||||
rv := reflect.ValueOf(val)
|
||||
ty := rv.Type()
|
||||
if ty.Kind() == reflect.Ptr {
|
||||
@@ -60,7 +60,7 @@ func EncodeIntoBody(val interface{}, dst *hclwrite.Body) {
|
||||
//
|
||||
// This function has the same constraints as EncodeIntoBody and will panic
|
||||
// if they are violated.
|
||||
func EncodeAsBlock(val interface{}, blockType string) *hclwrite.Block {
|
||||
func EncodeAsBlock(val any, blockType string) *hclwrite.Block {
|
||||
rv := reflect.ValueOf(val)
|
||||
ty := rv.Type()
|
||||
if ty.Kind() == reflect.Ptr {
|
||||
@@ -158,7 +158,7 @@ func populateBody(rv reflect.Value, ty reflect.Type, tags *fieldTags, dst *hclwr
|
||||
|
||||
if isSeq {
|
||||
l := fieldVal.Len()
|
||||
for i := 0; i < l; i++ {
|
||||
for i := range l {
|
||||
elemVal := fieldVal.Index(i)
|
||||
if !elemVal.IsValid() {
|
||||
continue // ignore (elem value is nil pointer)
|
||||
|
@@ -22,7 +22,7 @@ import (
|
||||
// This uses the tags on the fields of the struct to discover how each
|
||||
// field's value should be expressed within configuration. If an invalid
|
||||
// mapping is attempted, this function will panic.
|
||||
func ImpliedBodySchema(val interface{}) (schema *hcl.BodySchema, partial bool) {
|
||||
func ImpliedBodySchema(val any) (schema *hcl.BodySchema, partial bool) {
|
||||
ty := reflect.TypeOf(val)
|
||||
|
||||
if ty.Kind() == reflect.Ptr {
|
||||
@@ -134,7 +134,7 @@ func getFieldTags(ty reflect.Type) *fieldTags {
|
||||
}
|
||||
|
||||
ct := ty.NumField()
|
||||
for i := 0; i < ct; i++ {
|
||||
for i := range ct {
|
||||
field := ty.Field(i)
|
||||
tag := field.Tag.Get("hcl")
|
||||
if tag == "" {
|
||||
|
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
func TestImpliedBodySchema(t *testing.T) {
|
||||
tests := []struct {
|
||||
val interface{}
|
||||
val any
|
||||
wantSchema *hcl.BodySchema
|
||||
wantPartial bool
|
||||
}{
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
"math"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/convert"
|
||||
)
|
||||
|
||||
type Opt struct {
|
||||
@@ -554,27 +556,57 @@ func (p *parser) resolveBlockNames(block *hcl.Block) ([]string, error) {
|
||||
func (p *parser) validateVariables(vars map[string]*variable, ectx *hcl.EvalContext) hcl.Diagnostics {
|
||||
var diags hcl.Diagnostics
|
||||
for _, v := range vars {
|
||||
for _, validation := range v.Validations {
|
||||
condition, condDiags := validation.Condition.Value(ectx)
|
||||
for _, rule := range v.Validations {
|
||||
resultVal, condDiags := rule.Condition.Value(ectx)
|
||||
if condDiags.HasErrors() {
|
||||
diags = append(diags, condDiags...)
|
||||
continue
|
||||
}
|
||||
if !condition.True() {
|
||||
message, msgDiags := validation.ErrorMessage.Value(ectx)
|
||||
|
||||
if resultVal.IsNull() {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid condition result",
|
||||
Detail: "Condition expression must return either true or false, not null.",
|
||||
Subject: rule.Condition.Range().Ptr(),
|
||||
Expression: rule.Condition,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
var err error
|
||||
resultVal, err = convert.Convert(resultVal, cty.Bool)
|
||||
if err != nil {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid condition result",
|
||||
Detail: fmt.Sprintf("Invalid condition result value: %s", err),
|
||||
Subject: rule.Condition.Range().Ptr(),
|
||||
Expression: rule.Condition,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
if !resultVal.True() {
|
||||
message, msgDiags := rule.ErrorMessage.Value(ectx)
|
||||
if msgDiags.HasErrors() {
|
||||
diags = append(diags, msgDiags...)
|
||||
continue
|
||||
}
|
||||
errorMessage := "This check failed, but has an invalid error message."
|
||||
if !message.IsNull() {
|
||||
errorMessage = message.AsString()
|
||||
}
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Validation failed",
|
||||
Detail: message.AsString(),
|
||||
Subject: validation.Condition.Range().Ptr(),
|
||||
Detail: errorMessage,
|
||||
Subject: rule.Condition.Range().Ptr(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return diags
|
||||
}
|
||||
|
||||
@@ -589,7 +621,7 @@ type ParseMeta struct {
|
||||
AllVariables []*Variable
|
||||
}
|
||||
|
||||
func Parse(b hcl.Body, opt Opt, val interface{}) (*ParseMeta, hcl.Diagnostics) {
|
||||
func Parse(b hcl.Body, opt Opt, val any) (*ParseMeta, hcl.Diagnostics) {
|
||||
reserved := map[string]struct{}{}
|
||||
schema, _ := gohcl.ImpliedBodySchema(val)
|
||||
|
||||
@@ -763,7 +795,7 @@ func Parse(b hcl.Body, opt Opt, val interface{}) (*ParseMeta, hcl.Diagnostics) {
|
||||
types := map[string]field{}
|
||||
renamed := map[string]map[string][]string{}
|
||||
vt := reflect.ValueOf(val).Elem().Type()
|
||||
for i := 0; i < vt.NumField(); i++ {
|
||||
for i := range vt.NumField() {
|
||||
tags := strings.Split(vt.Field(i).Tag.Get("hcl"), ",")
|
||||
|
||||
p.blockTypes[tags[0]] = vt.Field(i).Type.Elem().Elem()
|
||||
@@ -831,7 +863,7 @@ func Parse(b hcl.Body, opt Opt, val interface{}) (*ParseMeta, hcl.Diagnostics) {
|
||||
oldValue, exists := t.values[lblName]
|
||||
if !exists && lblExists {
|
||||
if v.Elem().Field(t.idx).Type().Kind() == reflect.Slice {
|
||||
for i := 0; i < v.Elem().Field(t.idx).Len(); i++ {
|
||||
for i := range v.Elem().Field(t.idx).Len() {
|
||||
if lblName == v.Elem().Field(t.idx).Index(i).Elem().Field(lblIndex).String() {
|
||||
exists = true
|
||||
oldValue = value{Value: v.Elem().Field(t.idx).Index(i), idx: i}
|
||||
@@ -898,7 +930,7 @@ func wrapErrorDiagnostic(message string, err error, subject *hcl.Range, context
|
||||
|
||||
func setName(v reflect.Value, name string) {
|
||||
numFields := v.Elem().Type().NumField()
|
||||
for i := 0; i < numFields; i++ {
|
||||
for i := range numFields {
|
||||
parts := strings.Split(v.Elem().Type().Field(i).Tag.Get("hcl"), ",")
|
||||
for _, t := range parts[1:] {
|
||||
if t == "label" {
|
||||
@@ -910,12 +942,10 @@ func setName(v reflect.Value, name string) {
|
||||
|
||||
func getName(v reflect.Value) (string, bool) {
|
||||
numFields := v.Elem().Type().NumField()
|
||||
for i := 0; i < numFields; i++ {
|
||||
for i := range numFields {
|
||||
parts := strings.Split(v.Elem().Type().Field(i).Tag.Get("hcl"), ",")
|
||||
for _, t := range parts[1:] {
|
||||
if t == "label" {
|
||||
return v.Elem().Field(i).String(), true
|
||||
}
|
||||
if slices.Contains(parts[1:], "label") {
|
||||
return v.Elem().Field(i).String(), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
@@ -923,12 +953,10 @@ func getName(v reflect.Value) (string, bool) {
|
||||
|
||||
func getNameIndex(v reflect.Value) (int, bool) {
|
||||
numFields := v.Elem().Type().NumField()
|
||||
for i := 0; i < numFields; i++ {
|
||||
for i := range numFields {
|
||||
parts := strings.Split(v.Elem().Type().Field(i).Tag.Get("hcl"), ",")
|
||||
for _, t := range parts[1:] {
|
||||
if t == "label" {
|
||||
return i, true
|
||||
}
|
||||
if slices.Contains(parts[1:], "label") {
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
@@ -988,7 +1016,7 @@ func key(ks ...any) uint64 {
|
||||
return hash.Sum64()
|
||||
}
|
||||
|
||||
func decodeBody(body hcl.Body, ctx *hcl.EvalContext, val interface{}) hcl.Diagnostics {
|
||||
func decodeBody(body hcl.Body, ctx *hcl.EvalContext, val any) hcl.Diagnostics {
|
||||
dec := gohcl.DecodeOptions{ImpliedType: ImpliedType}
|
||||
return dec.DecodeBody(body, ctx, val)
|
||||
}
|
||||
|
@@ -43,7 +43,7 @@ import (
|
||||
// In particular, ImpliedType will never use capsule types in its returned
|
||||
// type, because it cannot know the capsule types supported by the calling
|
||||
// program.
|
||||
func ImpliedType(gv interface{}) (cty.Type, error) {
|
||||
func ImpliedType(gv any) (cty.Type, error) {
|
||||
rt := reflect.TypeOf(gv)
|
||||
var path cty.Path
|
||||
return impliedType(rt, path)
|
||||
@@ -148,7 +148,7 @@ func structTagIndices(st reflect.Type) map[string]int {
|
||||
ct := st.NumField()
|
||||
ret := make(map[string]int, ct)
|
||||
|
||||
for i := 0; i < ct; i++ {
|
||||
for i := range ct {
|
||||
field := st.Field(i)
|
||||
attrName := field.Tag.Get("cty")
|
||||
if attrName != "" {
|
||||
|
@@ -8,6 +8,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"maps"
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
@@ -40,7 +41,6 @@ import (
|
||||
"github.com/moby/buildkit/solver/errdefs"
|
||||
"github.com/moby/buildkit/solver/pb"
|
||||
spb "github.com/moby/buildkit/sourcepolicy/pb"
|
||||
"github.com/moby/buildkit/util/entitlements"
|
||||
"github.com/moby/buildkit/util/progress/progresswriter"
|
||||
"github.com/moby/buildkit/util/tracing"
|
||||
"github.com/opencontainers/go-digest"
|
||||
@@ -63,7 +63,7 @@ type Options struct {
|
||||
Inputs Inputs
|
||||
|
||||
Ref string
|
||||
Allow []entitlements.Entitlement
|
||||
Allow []string
|
||||
Attests map[string]*string
|
||||
BuildArgs map[string]string
|
||||
CacheFrom []client.CacheOptionsEntry
|
||||
@@ -432,9 +432,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opts map[
|
||||
FrontendInputs: frontendInputs,
|
||||
FrontendOpt: make(map[string]string),
|
||||
}
|
||||
for k, v := range so.FrontendAttrs {
|
||||
req.FrontendOpt[k] = v
|
||||
}
|
||||
maps.Copy(req.FrontendOpt, so.FrontendAttrs)
|
||||
so.Frontend = ""
|
||||
so.FrontendInputs = nil
|
||||
|
||||
@@ -540,7 +538,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opts map[
|
||||
node := dp.Node().Driver
|
||||
if node.IsMobyDriver() {
|
||||
for _, e := range so.Exports {
|
||||
if e.Type == "moby" && e.Attrs["push"] != "" {
|
||||
if e.Type == "moby" && e.Attrs["push"] != "" && !node.Features(ctx)[driver.DirectPush] {
|
||||
if ok, _ := strconv.ParseBool(e.Attrs["push"]); ok {
|
||||
pushNames = e.Attrs["name"]
|
||||
if pushNames == "" {
|
||||
@@ -623,7 +621,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opts map[
|
||||
// This is fallback for some very old buildkit versions.
|
||||
// Note that the mediatype isn't really correct as most of the time it is image manifest and
|
||||
// not manifest list but actually both are handled because for Docker mediatypes the
|
||||
// mediatype value in the Accpet header does not seem to matter.
|
||||
// mediatype value in the Accept header does not seem to matter.
|
||||
s, ok = r.ExporterResponse[exptypes.ExporterImageDigestKey]
|
||||
if ok {
|
||||
descs = append(descs, specs.Descriptor{
|
||||
@@ -835,7 +833,7 @@ func remoteDigestWithMoby(ctx context.Context, d *driver.DriverHandle, name stri
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
img, _, err := api.ImageInspectWithRaw(ctx, name)
|
||||
img, err := api.ImageInspect(ctx, name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
stderrors "errors"
|
||||
"net"
|
||||
"slices"
|
||||
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/buildx/builder"
|
||||
@@ -37,15 +38,7 @@ func Dial(ctx context.Context, nodes []builder.Node, pw progress.Writer, platfor
|
||||
for _, ls := range resolved {
|
||||
for _, rn := range ls {
|
||||
if platform != nil {
|
||||
p := *platform
|
||||
var found bool
|
||||
for _, pp := range rn.platforms {
|
||||
if platforms.Only(p).Match(pp) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
if !slices.ContainsFunc(rn.platforms, platforms.Only(*platform).Match) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package build
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/platforms"
|
||||
@@ -221,7 +222,7 @@ func (r *nodeResolver) get(p specs.Platform, matcher matchMaker, additionalPlatf
|
||||
for i, node := range r.nodes {
|
||||
platforms := node.Platforms
|
||||
if additionalPlatforms != nil {
|
||||
platforms = append([]specs.Platform{}, platforms...)
|
||||
platforms = slices.Clone(platforms)
|
||||
platforms = append(platforms, additionalPlatforms(i, node)...)
|
||||
}
|
||||
for _, p2 := range platforms {
|
||||
|
@@ -2,6 +2,7 @@ package build
|
||||
|
||||
import (
|
||||
"context"
|
||||
"maps"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -127,9 +128,7 @@ func getGitAttributes(ctx context.Context, contextPath, dockerfilePath string) (
|
||||
if so.FrontendAttrs == nil {
|
||||
so.FrontendAttrs = make(map[string]string)
|
||||
}
|
||||
for k, v := range res {
|
||||
so.FrontendAttrs[k] = v
|
||||
}
|
||||
maps.Copy(so.FrontendAttrs, res)
|
||||
|
||||
if !setGitInfo || root == "" {
|
||||
return
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/buildx/util/gitutil"
|
||||
"github.com/docker/buildx/util/gitutil/gittestutil"
|
||||
"github.com/moby/buildkit/client"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -16,18 +17,18 @@ import (
|
||||
)
|
||||
|
||||
func setupTest(tb testing.TB) {
|
||||
gitutil.Mktmp(tb)
|
||||
gittestutil.Mktmp(tb)
|
||||
|
||||
c, err := gitutil.New()
|
||||
require.NoError(tb, err)
|
||||
gitutil.GitInit(c, tb)
|
||||
gittestutil.GitInit(c, tb)
|
||||
|
||||
df := []byte("FROM alpine:latest\n")
|
||||
require.NoError(tb, os.WriteFile("Dockerfile", df, 0644))
|
||||
|
||||
gitutil.GitAdd(c, tb, "Dockerfile")
|
||||
gitutil.GitCommit(c, tb, "initial commit")
|
||||
gitutil.GitSetRemote(c, tb, "origin", "git@github.com:docker/buildx.git")
|
||||
gittestutil.GitAdd(c, tb, "Dockerfile")
|
||||
gittestutil.GitCommit(c, tb, "initial commit")
|
||||
gittestutil.GitSetRemote(c, tb, "origin", "git@github.com:docker/buildx.git")
|
||||
}
|
||||
|
||||
func TestGetGitAttributesNotGitRepo(t *testing.T) {
|
||||
@@ -188,19 +189,19 @@ func TestLocalDirs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLocalDirsSub(t *testing.T) {
|
||||
gitutil.Mktmp(t)
|
||||
gittestutil.Mktmp(t)
|
||||
|
||||
c, err := gitutil.New()
|
||||
require.NoError(t, err)
|
||||
gitutil.GitInit(c, t)
|
||||
gittestutil.GitInit(c, t)
|
||||
|
||||
df := []byte("FROM alpine:latest\n")
|
||||
require.NoError(t, os.MkdirAll("app", 0755))
|
||||
require.NoError(t, os.WriteFile("app/Dockerfile", df, 0644))
|
||||
|
||||
gitutil.GitAdd(c, t, "app/Dockerfile")
|
||||
gitutil.GitCommit(c, t, "initial commit")
|
||||
gitutil.GitSetRemote(c, t, "origin", "git@github.com:docker/buildx.git")
|
||||
gittestutil.GitAdd(c, t, "app/Dockerfile")
|
||||
gittestutil.GitCommit(c, t, "initial commit")
|
||||
gittestutil.GitSetRemote(c, t, "origin", "git@github.com:docker/buildx.git")
|
||||
|
||||
so := &client.SolveOpt{
|
||||
FrontendAttrs: map[string]string{},
|
||||
|
@@ -318,7 +318,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt *O
|
||||
switch opt.NetworkMode {
|
||||
case "host":
|
||||
so.FrontendAttrs["force-network-mode"] = opt.NetworkMode
|
||||
so.AllowedEntitlements = append(so.AllowedEntitlements, entitlements.EntitlementNetworkHost)
|
||||
so.AllowedEntitlements = append(so.AllowedEntitlements, entitlements.EntitlementNetworkHost.String())
|
||||
case "none":
|
||||
so.FrontendAttrs["force-network-mode"] = opt.NetworkMode
|
||||
case "", "default":
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"maps"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@@ -40,9 +41,7 @@ func setRecordProvenance(ctx context.Context, c *client.Client, sr *client.Solve
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range res {
|
||||
sr.ExporterResponse[k] = v
|
||||
}
|
||||
maps.Copy(sr.ExporterResponse, res)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
@@ -28,11 +28,11 @@ func TestSyncMultiReaderParallel(t *testing.T) {
|
||||
|
||||
readers := make([]io.ReadCloser, numReaders)
|
||||
|
||||
for i := 0; i < numReaders; i++ {
|
||||
for i := range numReaders {
|
||||
readers[i] = mr.NewReadCloser()
|
||||
}
|
||||
|
||||
for i := 0; i < numReaders; i++ {
|
||||
for i := range numReaders {
|
||||
wg.Add(1)
|
||||
go func(readerId int) {
|
||||
defer wg.Done()
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"os"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -199,7 +200,7 @@ func (b *Builder) Boot(ctx context.Context) (bool, error) {
|
||||
err = err1
|
||||
}
|
||||
|
||||
if err == nil && len(errCh) == len(toBoot) {
|
||||
if err == nil && len(errCh) > 0 {
|
||||
return false, <-errCh
|
||||
}
|
||||
return true, err
|
||||
@@ -656,13 +657,7 @@ func parseBuildkitdFlags(inp string, driver string, driverOpts map[string]string
|
||||
flags.StringArrayVar(&allowInsecureEntitlements, "allow-insecure-entitlement", nil, "")
|
||||
_ = flags.Parse(res)
|
||||
|
||||
var hasNetworkHostEntitlement bool
|
||||
for _, e := range allowInsecureEntitlements {
|
||||
if e == "network.host" {
|
||||
hasNetworkHostEntitlement = true
|
||||
break
|
||||
}
|
||||
}
|
||||
hasNetworkHostEntitlement := slices.Contains(allowInsecureEntitlements, "network.host")
|
||||
|
||||
var hasNetworkHostEntitlementInConf bool
|
||||
if buildkitdConfigFile != "" {
|
||||
@@ -671,11 +666,8 @@ func parseBuildkitdFlags(inp string, driver string, driverOpts map[string]string
|
||||
return nil, err
|
||||
} else if btoml != nil {
|
||||
if ies := btoml.GetArray("insecure-entitlements"); ies != nil {
|
||||
for _, e := range ies.([]string) {
|
||||
if e == "network.host" {
|
||||
hasNetworkHostEntitlementInConf = true
|
||||
break
|
||||
}
|
||||
if slices.Contains(ies.([]string), "network.host") {
|
||||
hasNetworkHostEntitlementInConf = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -169,7 +169,7 @@ func (b *Builder) LoadNodes(ctx context.Context, opts ...LoadNodesOption) (_ []N
|
||||
// dynamic nodes are used in Kubernetes driver.
|
||||
// Kubernetes' pods are dynamically mapped to BuildKit Nodes.
|
||||
if di.DriverInfo != nil && len(di.DriverInfo.DynamicNodes) > 0 {
|
||||
for i := 0; i < len(di.DriverInfo.DynamicNodes); i++ {
|
||||
for i := range di.DriverInfo.DynamicNodes {
|
||||
diClone := di
|
||||
if pl := di.DriverInfo.DynamicNodes[i].Platforms; len(pl) > 0 {
|
||||
diClone.Platforms = pl
|
||||
|
@@ -11,11 +11,10 @@ import (
|
||||
"github.com/docker/buildx/util/desktop"
|
||||
"github.com/docker/buildx/version"
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli-plugins/manager"
|
||||
"github.com/docker/cli/cli-plugins/metadata"
|
||||
"github.com/docker/cli/cli-plugins/plugin"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/debug"
|
||||
cliflags "github.com/docker/cli/cli/flags"
|
||||
"github.com/moby/buildkit/solver/errdefs"
|
||||
"github.com/moby/buildkit/util/stack"
|
||||
"github.com/pkg/errors"
|
||||
@@ -37,11 +36,7 @@ func init() {
|
||||
}
|
||||
|
||||
func runStandalone(cmd *command.DockerCli) error {
|
||||
if err := cmd.Initialize(cliflags.NewClientOptions()); err != nil {
|
||||
return err
|
||||
}
|
||||
defer flushMetrics(cmd)
|
||||
|
||||
executable := os.Args[0]
|
||||
rootCmd := commands.NewRootCmd(filepath.Base(executable), false, cmd)
|
||||
return rootCmd.Execute()
|
||||
@@ -64,7 +59,7 @@ func flushMetrics(cmd *command.DockerCli) {
|
||||
|
||||
func runPlugin(cmd *command.DockerCli) error {
|
||||
rootCmd := commands.NewRootCmd("buildx", true, cmd)
|
||||
return plugin.RunPlugin(cmd, rootCmd, manager.Metadata{
|
||||
return plugin.RunPlugin(cmd, rootCmd, metadata.Metadata{
|
||||
SchemaVersion: "0.1.0",
|
||||
Vendor: "Docker Inc.",
|
||||
Version: version.Version,
|
||||
|
@@ -66,7 +66,11 @@ type bakeOptions struct {
|
||||
func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in bakeOptions, cFlags commonFlags) (err error) {
|
||||
mp := dockerCli.MeterProvider()
|
||||
|
||||
ctx, end, err := tracing.TraceCurrentCommand(ctx, "bake")
|
||||
ctx, end, err := tracing.TraceCurrentCommand(ctx, append([]string{"bake"}, targets...),
|
||||
attribute.String("builder", in.builder),
|
||||
attribute.StringSlice("targets", targets),
|
||||
attribute.StringSlice("files", in.files),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -283,7 +287,7 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
|
||||
}
|
||||
}
|
||||
|
||||
if err := saveLocalStateGroup(dockerCli, in, targets, bo, overrides, def); err != nil {
|
||||
if err := saveLocalStateGroup(dockerCli, in, targets, bo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -305,7 +309,7 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
|
||||
desktop.PrintBuildDetails(os.Stderr, printer.BuildRefs(), term)
|
||||
}
|
||||
if len(in.metadataFile) > 0 {
|
||||
dt := make(map[string]interface{})
|
||||
dt := make(map[string]any)
|
||||
for t, r := range resp {
|
||||
dt[t] = decodeExporterResponse(r.ExporterResponse)
|
||||
}
|
||||
@@ -420,6 +424,14 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
|
||||
fmt.Fprintln(dockerCli.Out(), string(dt))
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
if sp, ok := resp[name]; ok {
|
||||
if v, ok := sp.ExporterResponse["frontend.result.inlinemessage"]; ok {
|
||||
fmt.Fprintf(dockerCli.Out(), "\n# %s\n%s\n", name, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if exitCode != 0 {
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
@@ -488,7 +500,14 @@ func bakeCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func saveLocalStateGroup(dockerCli command.Cli, in bakeOptions, targets []string, bo map[string]build.Options, overrides []string, def any) error {
|
||||
func saveLocalStateGroup(dockerCli command.Cli, in bakeOptions, targets []string, bo map[string]build.Options) error {
|
||||
l, err := localstate.New(confutil.NewConfig(dockerCli))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer l.MigrateIfNeeded()
|
||||
|
||||
prm := confutil.MetadataProvenance()
|
||||
if len(in.metadataFile) == 0 {
|
||||
prm = confutil.MetadataProvenanceModeDisabled
|
||||
@@ -508,19 +527,10 @@ func saveLocalStateGroup(dockerCli command.Cli, in bakeOptions, targets []string
|
||||
if len(refs) == 0 {
|
||||
return nil
|
||||
}
|
||||
l, err := localstate.New(confutil.NewConfig(dockerCli))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dtdef, err := json.MarshalIndent(def, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return l.SaveGroup(groupRef, localstate.StateGroup{
|
||||
Definition: dtdef,
|
||||
Targets: targets,
|
||||
Inputs: overrides,
|
||||
Refs: refs,
|
||||
Refs: refs,
|
||||
Targets: targets,
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -41,7 +42,7 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
dockeropts "github.com/docker/cli/opts"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/atomicwriter"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/exporter/containerimage/exptypes"
|
||||
"github.com/moby/buildkit/frontend/subrequests"
|
||||
@@ -156,7 +157,7 @@ func (o *buildOptions) toControllerOptions() (*controllerapi.BuildOptions, error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
inAttests := append([]string{}, o.attests...)
|
||||
inAttests := slices.Clone(o.attests)
|
||||
if o.provenance != "" {
|
||||
inAttests = append(inAttests, buildflags.CanonicalizeAttest("provenance", o.provenance))
|
||||
}
|
||||
@@ -285,7 +286,11 @@ func (o *buildOptionsHash) String() string {
|
||||
func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions) (err error) {
|
||||
mp := dockerCli.MeterProvider()
|
||||
|
||||
ctx, end, err := tracing.TraceCurrentCommand(ctx, "build")
|
||||
ctx, end, err := tracing.TraceCurrentCommand(ctx, []string{"build", options.contextPath},
|
||||
attribute.String("builder", options.builder),
|
||||
attribute.String("context", options.contextPath),
|
||||
attribute.String("dockerfile", options.dockerfileName),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -399,6 +404,10 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions)
|
||||
os.Exit(exitcode)
|
||||
}
|
||||
}
|
||||
if v, ok := resp.ExporterResponse["frontend.result.inlinemessage"]; ok {
|
||||
fmt.Fprintf(dockerCli.Out(), "\n%s\n", v)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -593,7 +602,7 @@ func buildCmd(dockerCli command.Cli, rootOpts *rootOptions, debugConfig *debug.D
|
||||
|
||||
flags.StringSliceVar(&options.extraHosts, "add-host", []string{}, `Add a custom host-to-IP mapping (format: "host:ip")`)
|
||||
|
||||
flags.StringSliceVar(&options.allow, "allow", []string{}, `Allow extra privileged entitlement (e.g., "network.host", "security.insecure")`)
|
||||
flags.StringArrayVar(&options.allow, "allow", []string{}, `Allow extra privileged entitlement (e.g., "network.host", "security.insecure")`)
|
||||
|
||||
flags.StringArrayVarP(&options.annotations, "annotation", "", []string{}, "Add annotation to the image")
|
||||
|
||||
@@ -740,15 +749,15 @@ func checkWarnedFlags(f *pflag.Flag) {
|
||||
}
|
||||
}
|
||||
|
||||
func writeMetadataFile(filename string, dt interface{}) error {
|
||||
func writeMetadataFile(filename string, dt any) error {
|
||||
b, err := json.MarshalIndent(dt, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutils.AtomicWriteFile(filename, b, 0644)
|
||||
return atomicwriter.WriteFile(filename, b, 0644)
|
||||
}
|
||||
|
||||
func decodeExporterResponse(exporterResponse map[string]string) map[string]interface{} {
|
||||
func decodeExporterResponse(exporterResponse map[string]string) map[string]any {
|
||||
decFunc := func(k, v string) ([]byte, error) {
|
||||
if k == "result.json" {
|
||||
// result.json is part of metadata response for subrequests which
|
||||
@@ -757,16 +766,16 @@ func decodeExporterResponse(exporterResponse map[string]string) map[string]inter
|
||||
}
|
||||
return base64.StdEncoding.DecodeString(v)
|
||||
}
|
||||
out := make(map[string]interface{})
|
||||
out := make(map[string]any)
|
||||
for k, v := range exporterResponse {
|
||||
dt, err := decFunc(k, v)
|
||||
if err != nil {
|
||||
out[k] = v
|
||||
continue
|
||||
}
|
||||
var raw map[string]interface{}
|
||||
var raw map[string]any
|
||||
if err = json.Unmarshal(dt, &raw); err != nil || len(raw) == 0 {
|
||||
var rawList []map[string]interface{}
|
||||
var rawList []map[string]any
|
||||
if err = json.Unmarshal(dt, &rawList); err != nil || len(rawList) == 0 {
|
||||
out[k] = v
|
||||
continue
|
||||
|
@@ -124,7 +124,7 @@ func duCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func printKV(w io.Writer, k string, v interface{}) {
|
||||
func printKV(w io.Writer, k string, v any) {
|
||||
fmt.Fprintf(w, "%s:\t%v\n", k, v)
|
||||
}
|
||||
|
||||
|
160
commands/history/export.go
Normal file
160
commands/history/export.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package history
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"slices"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/buildx/builder"
|
||||
"github.com/docker/buildx/localstate"
|
||||
"github.com/docker/buildx/util/cobrautil/completion"
|
||||
"github.com/docker/buildx/util/confutil"
|
||||
"github.com/docker/buildx/util/desktop/bundle"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type exportOptions struct {
|
||||
builder string
|
||||
refs []string
|
||||
output string
|
||||
all bool
|
||||
}
|
||||
|
||||
func runExport(ctx context.Context, dockerCli command.Cli, opts exportOptions) error {
|
||||
b, err := builder.New(dockerCli, builder.WithName(opts.builder))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodes, err := b.LoadNodes(ctx, builder.WithData())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, node := range nodes {
|
||||
if node.Err != nil {
|
||||
return node.Err
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts.refs) == 0 {
|
||||
opts.refs = []string{""}
|
||||
}
|
||||
|
||||
var res []historyRecord
|
||||
for _, ref := range opts.refs {
|
||||
recs, err := queryRecords(ctx, ref, nodes, &queryOptions{
|
||||
CompletedOnly: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(recs) == 0 {
|
||||
if ref == "" {
|
||||
return errors.New("no records found")
|
||||
}
|
||||
return errors.Errorf("no record found for ref %q", ref)
|
||||
}
|
||||
|
||||
if ref == "" {
|
||||
slices.SortFunc(recs, func(a, b historyRecord) int {
|
||||
return b.CreatedAt.AsTime().Compare(a.CreatedAt.AsTime())
|
||||
})
|
||||
}
|
||||
|
||||
if opts.all {
|
||||
res = append(res, recs...)
|
||||
break
|
||||
} else {
|
||||
res = append(res, recs[0])
|
||||
}
|
||||
}
|
||||
|
||||
ls, err := localstate.New(confutil.NewConfig(dockerCli))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
visited := map[*builder.Node]struct{}{}
|
||||
var clients []*client.Client
|
||||
for _, rec := range res {
|
||||
if _, ok := visited[rec.node]; ok {
|
||||
continue
|
||||
}
|
||||
c, err := rec.node.Driver.Client(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clients = append(clients, c)
|
||||
}
|
||||
|
||||
toExport := make([]*bundle.Record, 0, len(res))
|
||||
for _, rec := range res {
|
||||
var defaultPlatform string
|
||||
if p := rec.node.Platforms; len(p) > 0 {
|
||||
defaultPlatform = platforms.FormatAll(platforms.Normalize(p[0]))
|
||||
}
|
||||
|
||||
var stg *localstate.StateGroup
|
||||
st, _ := ls.ReadRef(rec.node.Builder, rec.node.Name, rec.Ref)
|
||||
if st != nil && st.GroupRef != "" {
|
||||
stg, err = ls.ReadGroup(st.GroupRef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
toExport = append(toExport, &bundle.Record{
|
||||
BuildHistoryRecord: rec.BuildHistoryRecord,
|
||||
DefaultPlatform: defaultPlatform,
|
||||
LocalState: st,
|
||||
StateGroup: stg,
|
||||
})
|
||||
}
|
||||
|
||||
var w io.Writer = os.Stdout
|
||||
if opts.output != "" {
|
||||
f, err := os.Create(opts.output)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to create output file %q", opts.output)
|
||||
}
|
||||
defer f.Close()
|
||||
w = f
|
||||
} else {
|
||||
if _, err := console.ConsoleFromFile(os.Stdout); err == nil {
|
||||
return errors.Errorf("refusing to write to console, use --output to specify a file")
|
||||
}
|
||||
}
|
||||
|
||||
return bundle.Export(ctx, clients, w, toExport)
|
||||
}
|
||||
|
||||
func exportCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
|
||||
var options exportOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "export [OPTIONS] [REF]",
|
||||
Short: "Export a build into Docker Desktop bundle",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if options.all && len(args) > 0 {
|
||||
return errors.New("cannot specify refs when using --all")
|
||||
}
|
||||
options.refs = args
|
||||
options.builder = *rootOpts.Builder
|
||||
return runExport(cmd.Context(), dockerCli, options)
|
||||
},
|
||||
ValidArgsFunction: completion.Disable,
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
flags.StringVarP(&options.output, "output", "o", "", "Output file path")
|
||||
flags.BoolVar(&options.all, "all", false, "Export all records for the builder")
|
||||
|
||||
return cmd
|
||||
}
|
135
commands/history/import.go
Normal file
135
commands/history/import.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package history
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
remoteutil "github.com/docker/buildx/driver/remote/util"
|
||||
"github.com/docker/buildx/util/cobrautil/completion"
|
||||
"github.com/docker/buildx/util/desktop"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/pkg/browser"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type importOptions struct {
|
||||
file []string
|
||||
}
|
||||
|
||||
func runImport(ctx context.Context, dockerCli command.Cli, opts importOptions) error {
|
||||
sock, err := desktop.BuildServerAddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tr := http.DefaultTransport.(*http.Transport).Clone()
|
||||
tr.DialContext = func(ctx context.Context, _, _ string) (net.Conn, error) {
|
||||
network, addr, ok := strings.Cut(sock, "://")
|
||||
if !ok {
|
||||
return nil, errors.Errorf("invalid endpoint address: %s", sock)
|
||||
}
|
||||
return remoteutil.DialContext(ctx, network, addr)
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Transport: tr,
|
||||
}
|
||||
|
||||
var urls []string
|
||||
|
||||
if len(opts.file) == 0 {
|
||||
u, err := importFrom(ctx, client, os.Stdin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
urls = append(urls, u...)
|
||||
} else {
|
||||
for _, fn := range opts.file {
|
||||
var f *os.File
|
||||
var rdr io.Reader = os.Stdin
|
||||
if fn != "-" {
|
||||
f, err = os.Open(fn)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to open file %s", fn)
|
||||
}
|
||||
rdr = f
|
||||
}
|
||||
u, err := importFrom(ctx, client, rdr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
urls = append(urls, u...)
|
||||
if f != nil {
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(urls) == 0 {
|
||||
return errors.New("no build records found in the bundle")
|
||||
}
|
||||
|
||||
for i, url := range urls {
|
||||
fmt.Fprintln(dockerCli.Err(), url)
|
||||
if i == 0 {
|
||||
err = browser.OpenURL(url)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func importFrom(ctx context.Context, c *http.Client, rdr io.Reader) ([]string, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, "http://docker-desktop/upload", rdr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create request")
|
||||
}
|
||||
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to send request, check if Docker Desktop is running")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
return nil, errors.Errorf("failed to import build: %s", string(body))
|
||||
}
|
||||
|
||||
var refs []string
|
||||
dec := json.NewDecoder(resp.Body)
|
||||
if err := dec.Decode(&refs); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to decode response")
|
||||
}
|
||||
|
||||
var urls []string
|
||||
for _, ref := range refs {
|
||||
urls = append(urls, desktop.BuildURL(fmt.Sprintf(".imported/_/%s", ref)))
|
||||
}
|
||||
return urls, err
|
||||
}
|
||||
|
||||
func importCmd(dockerCli command.Cli, _ RootOptions) *cobra.Command {
|
||||
var options importOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "import [OPTIONS] < bundle.dockerbuild",
|
||||
Short: "Import a build into Docker Desktop",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runImport(cmd.Context(), dockerCli, options)
|
||||
},
|
||||
ValidArgsFunction: completion.Disable,
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
flags.StringArrayVarP(&options.file, "file", "f", nil, "Import from a file path")
|
||||
|
||||
return cmd
|
||||
}
|
@@ -173,7 +173,7 @@ func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions)
|
||||
}
|
||||
}
|
||||
|
||||
recs, err := queryRecords(ctx, opts.ref, nodes)
|
||||
recs, err := queryRecords(ctx, opts.ref, nodes, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -185,14 +185,7 @@ func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions)
|
||||
return errors.Errorf("no record found for ref %q", opts.ref)
|
||||
}
|
||||
|
||||
if opts.ref == "" {
|
||||
slices.SortFunc(recs, func(a, b historyRecord) int {
|
||||
return b.CreatedAt.AsTime().Compare(a.CreatedAt.AsTime())
|
||||
})
|
||||
}
|
||||
|
||||
rec := &recs[0]
|
||||
|
||||
c, err := rec.node.Driver.Client(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -353,7 +346,7 @@ workers0:
|
||||
out.Error.Name = name
|
||||
out.Error.Logs = logs
|
||||
}
|
||||
out.Error.Stack = []byte(fmt.Sprintf("%+v", stack.Formatter(retErr)))
|
||||
out.Error.Stack = fmt.Appendf(nil, "%+v", stack.Formatter(retErr))
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,6 @@ package history
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"slices"
|
||||
|
||||
"github.com/containerd/containerd/v2/core/content/proxy"
|
||||
"github.com/containerd/platforms"
|
||||
@@ -42,7 +41,7 @@ func runAttachment(ctx context.Context, dockerCli command.Cli, opts attachmentOp
|
||||
}
|
||||
}
|
||||
|
||||
recs, err := queryRecords(ctx, opts.ref, nodes)
|
||||
recs, err := queryRecords(ctx, opts.ref, nodes, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -54,12 +53,6 @@ func runAttachment(ctx context.Context, dockerCli command.Cli, opts attachmentOp
|
||||
return errors.Errorf("no record found for ref %q", opts.ref)
|
||||
}
|
||||
|
||||
if opts.ref == "" {
|
||||
slices.SortFunc(recs, func(a, b historyRecord) int {
|
||||
return b.CreatedAt.AsTime().Compare(a.CreatedAt.AsTime())
|
||||
})
|
||||
}
|
||||
|
||||
rec := &recs[0]
|
||||
|
||||
c, err := rec.node.Driver.Client(ctx)
|
||||
|
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"slices"
|
||||
|
||||
"github.com/docker/buildx/builder"
|
||||
"github.com/docker/buildx/util/cobrautil/completion"
|
||||
@@ -39,7 +38,7 @@ func runLogs(ctx context.Context, dockerCli command.Cli, opts logsOptions) error
|
||||
}
|
||||
}
|
||||
|
||||
recs, err := queryRecords(ctx, opts.ref, nodes)
|
||||
recs, err := queryRecords(ctx, opts.ref, nodes, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -51,12 +50,6 @@ func runLogs(ctx context.Context, dockerCli command.Cli, opts logsOptions) error
|
||||
return errors.Errorf("no record found for ref %q", opts.ref)
|
||||
}
|
||||
|
||||
if opts.ref == "" {
|
||||
slices.SortFunc(recs, func(a, b historyRecord) int {
|
||||
return b.CreatedAt.AsTime().Compare(a.CreatedAt.AsTime())
|
||||
})
|
||||
}
|
||||
|
||||
rec := &recs[0]
|
||||
c, err := rec.node.Driver.Client(ctx)
|
||||
if err != nil {
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
@@ -14,10 +15,12 @@ import (
|
||||
"github.com/docker/buildx/util/cobrautil/completion"
|
||||
"github.com/docker/buildx/util/confutil"
|
||||
"github.com/docker/buildx/util/desktop"
|
||||
"github.com/docker/buildx/util/gitutil"
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -38,6 +41,9 @@ type lsOptions struct {
|
||||
builder string
|
||||
format string
|
||||
noTrunc bool
|
||||
|
||||
filters []string
|
||||
local bool
|
||||
}
|
||||
|
||||
func runLs(ctx context.Context, dockerCli command.Cli, opts lsOptions) error {
|
||||
@@ -56,7 +62,29 @@ func runLs(ctx context.Context, dockerCli command.Cli, opts lsOptions) error {
|
||||
}
|
||||
}
|
||||
|
||||
out, err := queryRecords(ctx, "", nodes)
|
||||
queryOptions := &queryOptions{}
|
||||
|
||||
if opts.local {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gitc, err := gitutil.New(gitutil.WithContext(ctx), gitutil.WithWorkingDir(wd))
|
||||
if err != nil {
|
||||
if st, err1 := os.Stat(path.Join(wd, ".git")); err1 == nil && st.IsDir() {
|
||||
return errors.Wrap(err, "git was not found in the system")
|
||||
}
|
||||
return errors.Wrapf(err, "could not find git repository for local filter")
|
||||
}
|
||||
remote, err := gitc.RemoteURL()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get remote URL for local filter")
|
||||
}
|
||||
queryOptions.Filters = append(queryOptions.Filters, fmt.Sprintf("repository=%s", remote))
|
||||
}
|
||||
queryOptions.Filters = append(queryOptions.Filters, opts.filters...)
|
||||
|
||||
out, err := queryRecords(ctx, "", nodes, queryOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -92,6 +120,8 @@ func lsCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
|
||||
flags := cmd.Flags()
|
||||
flags.StringVar(&options.format, "format", formatter.TableFormatKey, "Format the output")
|
||||
flags.BoolVar(&options.noTrunc, "no-trunc", false, "Don't truncate output")
|
||||
flags.StringArrayVar(&options.filters, "filter", nil, `Provide filter values (e.g., "status=error")`)
|
||||
flags.BoolVar(&options.local, "local", false, "List records for current repository only")
|
||||
|
||||
return cmd
|
||||
}
|
||||
@@ -161,7 +191,7 @@ type lsContext struct {
|
||||
}
|
||||
|
||||
func (c *lsContext) MarshalJSON() ([]byte, error) {
|
||||
m := map[string]interface{}{
|
||||
m := map[string]any{
|
||||
"ref": c.FullRef(),
|
||||
"name": c.Name(),
|
||||
"status": c.Status(),
|
||||
|
@@ -3,7 +3,6 @@ package history
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/docker/buildx/builder"
|
||||
"github.com/docker/buildx/util/cobrautil/completion"
|
||||
@@ -35,7 +34,7 @@ func runOpen(ctx context.Context, dockerCli command.Cli, opts openOptions) error
|
||||
}
|
||||
}
|
||||
|
||||
recs, err := queryRecords(ctx, opts.ref, nodes)
|
||||
recs, err := queryRecords(ctx, opts.ref, nodes, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -47,12 +46,6 @@ func runOpen(ctx context.Context, dockerCli command.Cli, opts openOptions) error
|
||||
return errors.Errorf("no record found for ref %q", opts.ref)
|
||||
}
|
||||
|
||||
if opts.ref == "" {
|
||||
slices.SortFunc(recs, func(a, b historyRecord) int {
|
||||
return b.CreatedAt.AsTime().Compare(a.CreatedAt.AsTime())
|
||||
})
|
||||
}
|
||||
|
||||
rec := &recs[0]
|
||||
|
||||
url := desktop.BuildURL(fmt.Sprintf("%s/%s/%s", rec.node.Builder, rec.node.Name, rec.Ref))
|
||||
|
@@ -25,6 +25,8 @@ func RootCmd(rootcmd *cobra.Command, dockerCli command.Cli, opts RootOptions) *c
|
||||
inspectCmd(dockerCli, opts),
|
||||
openCmd(dockerCli, opts),
|
||||
traceCmd(dockerCli, opts),
|
||||
importCmd(dockerCli, opts),
|
||||
exportCmd(dockerCli, opts),
|
||||
)
|
||||
|
||||
return cmd
|
||||
|
@@ -8,9 +8,6 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/console"
|
||||
@@ -37,51 +34,20 @@ type traceOptions struct {
|
||||
}
|
||||
|
||||
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)
|
||||
recs, err := queryRecords(ctx, ref, nodes, &queryOptions{
|
||||
CompletedOnly: true,
|
||||
})
|
||||
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 len(recs) == 0 {
|
||||
if ref == "" {
|
||||
return "", nil, errors.New("no records found")
|
||||
}
|
||||
return "", nil, errors.Errorf("no record found for ref %q", ref)
|
||||
}
|
||||
rec := &recs[0]
|
||||
|
||||
if rec.CompletedAt == nil {
|
||||
return "", nil, errors.Errorf("build %q is not completed, only completed builds can be traced", rec.Ref)
|
||||
@@ -103,7 +69,9 @@ func loadTrace(ctx context.Context, ref string, nodes []builder.Node) (string, [
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
recs, err := queryRecords(ctx, rec.Ref, []builder.Node{*rec.node})
|
||||
recs, err := queryRecords(ctx, rec.Ref, []builder.Node{*rec.node}, &queryOptions{
|
||||
CompletedOnly: true,
|
||||
})
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
@@ -1,10 +1,14 @@
|
||||
package history
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -13,10 +17,13 @@ import (
|
||||
"github.com/docker/buildx/builder"
|
||||
"github.com/docker/buildx/localstate"
|
||||
controlapi "github.com/moby/buildkit/api/services/control"
|
||||
"github.com/moby/buildkit/util/gitutil"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
const recordsLimit = 50
|
||||
|
||||
func buildName(fattrs map[string]string, ls *localstate.State) string {
|
||||
var res string
|
||||
|
||||
@@ -106,10 +113,30 @@ type historyRecord struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func queryRecords(ctx context.Context, ref string, nodes []builder.Node) ([]historyRecord, error) {
|
||||
type queryOptions struct {
|
||||
CompletedOnly bool
|
||||
Filters []string
|
||||
}
|
||||
|
||||
func queryRecords(ctx context.Context, ref string, nodes []builder.Node, opts *queryOptions) ([]historyRecord, error) {
|
||||
var mu sync.Mutex
|
||||
var out []historyRecord
|
||||
|
||||
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 = ""
|
||||
}
|
||||
|
||||
var filters []string
|
||||
if opts != nil {
|
||||
filters = opts.Filters
|
||||
}
|
||||
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
for _, node := range nodes {
|
||||
node := node
|
||||
@@ -122,9 +149,25 @@ func queryRecords(ctx context.Context, ref string, nodes []builder.Node) ([]hist
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var matchers []matchFunc
|
||||
if len(filters) > 0 {
|
||||
filters, matchers, err = dockerFiltersToBuildkit(filters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sb := bytes.NewBuffer(nil)
|
||||
w := csv.NewWriter(sb)
|
||||
w.Write(filters)
|
||||
w.Flush()
|
||||
filters = []string{strings.TrimSuffix(sb.String(), "\n")}
|
||||
}
|
||||
|
||||
serv, err := c.ControlClient().ListenBuildHistory(ctx, &controlapi.BuildHistoryRequest{
|
||||
EarlyExit: true,
|
||||
Ref: ref,
|
||||
Limit: recordsLimit,
|
||||
Filter: filters,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -142,6 +185,7 @@ func queryRecords(ctx context.Context, ref string, nodes []builder.Node) ([]hist
|
||||
ts = &t
|
||||
}
|
||||
defer serv.CloseSend()
|
||||
loop0:
|
||||
for {
|
||||
he, err := serv.Recv()
|
||||
if err != nil {
|
||||
@@ -153,6 +197,17 @@ func queryRecords(ctx context.Context, ref string, nodes []builder.Node) ([]hist
|
||||
if he.Type == controlapi.BuildHistoryEventType_DELETED || he.Record == nil {
|
||||
continue
|
||||
}
|
||||
if opts != nil && opts.CompletedOnly && he.Type != controlapi.BuildHistoryEventType_COMPLETE {
|
||||
continue
|
||||
}
|
||||
|
||||
// for older buildkit that don't support filters apply local filters
|
||||
for _, matcher := range matchers {
|
||||
if !matcher(he.Record) {
|
||||
continue loop0
|
||||
}
|
||||
}
|
||||
|
||||
records = append(records, historyRecord{
|
||||
BuildHistoryRecord: he.Record,
|
||||
currentTimestamp: ts,
|
||||
@@ -169,6 +224,27 @@ func queryRecords(ctx context.Context, ref string, nodes []builder.Node) ([]hist
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
slices.SortFunc(out, func(a, b historyRecord) int {
|
||||
return b.CreatedAt.AsTime().Compare(a.CreatedAt.AsTime())
|
||||
})
|
||||
|
||||
if offset != nil {
|
||||
var filtered []historyRecord
|
||||
for _, r := range out {
|
||||
if *offset > 0 {
|
||||
*offset--
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, r)
|
||||
break
|
||||
}
|
||||
if *offset > 0 {
|
||||
return nil, errors.Errorf("no completed build found with offset %d", *offset)
|
||||
}
|
||||
out = filtered
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@@ -178,3 +254,150 @@ func formatDuration(d time.Duration) string {
|
||||
}
|
||||
return fmt.Sprintf("%dm %2ds", int(d.Minutes()), int(d.Seconds())%60)
|
||||
}
|
||||
|
||||
type matchFunc func(*controlapi.BuildHistoryRecord) bool
|
||||
|
||||
func dockerFiltersToBuildkit(in []string) ([]string, []matchFunc, error) {
|
||||
out := []string{}
|
||||
matchers := []matchFunc{}
|
||||
for _, f := range in {
|
||||
key, value, sep, found := cutAny(f, "!=", "=", "<=", "<", ">=", ">")
|
||||
if !found {
|
||||
return nil, nil, errors.Errorf("invalid filter %q", f)
|
||||
}
|
||||
switch key {
|
||||
case "ref", "repository", "status":
|
||||
if sep != "=" && sep != "!=" {
|
||||
return nil, nil, errors.Errorf("invalid separator for %q, expected = or !=", f)
|
||||
}
|
||||
matchers = append(matchers, valueFiler(key, value, sep))
|
||||
if sep == "=" {
|
||||
if key == "status" {
|
||||
sep = "=="
|
||||
} else {
|
||||
sep = "~="
|
||||
}
|
||||
}
|
||||
case "startedAt", "completedAt", "duration":
|
||||
if sep == "=" || sep == "!=" {
|
||||
return nil, nil, errors.Errorf("invalid separator for %q, expected <=, <, >= or >", f)
|
||||
}
|
||||
matcher, err := timeBasedFilter(key, value, sep)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
matchers = append(matchers, matcher)
|
||||
default:
|
||||
return nil, nil, errors.Errorf("unsupported filter %q", f)
|
||||
}
|
||||
out = append(out, key+sep+value)
|
||||
}
|
||||
return out, matchers, nil
|
||||
}
|
||||
|
||||
func valueFiler(key, value, sep string) matchFunc {
|
||||
return func(rec *controlapi.BuildHistoryRecord) bool {
|
||||
var recValue string
|
||||
switch key {
|
||||
case "ref":
|
||||
recValue = rec.Ref
|
||||
case "repository":
|
||||
v, ok := rec.FrontendAttrs["vcs:source"]
|
||||
if ok {
|
||||
recValue = v
|
||||
} else {
|
||||
if context, ok := rec.FrontendAttrs["context"]; ok {
|
||||
if ref, err := gitutil.ParseGitRef(context); err == nil {
|
||||
recValue = ref.Remote
|
||||
}
|
||||
}
|
||||
}
|
||||
case "status":
|
||||
if rec.CompletedAt != nil {
|
||||
if rec.Error != nil {
|
||||
if strings.Contains(rec.Error.Message, "context canceled") {
|
||||
recValue = "canceled"
|
||||
} else {
|
||||
recValue = "error"
|
||||
}
|
||||
} else {
|
||||
recValue = "completed"
|
||||
}
|
||||
} else {
|
||||
recValue = "running"
|
||||
}
|
||||
}
|
||||
switch sep {
|
||||
case "=":
|
||||
if key == "status" {
|
||||
return recValue == value
|
||||
}
|
||||
return strings.Contains(recValue, value)
|
||||
case "!=":
|
||||
return recValue != value
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func timeBasedFilter(key, value, sep string) (matchFunc, error) {
|
||||
var cmp int64
|
||||
switch key {
|
||||
case "startedAt", "completedAt":
|
||||
v, err := time.ParseDuration(value)
|
||||
if err == nil {
|
||||
tm := time.Now().Add(-v)
|
||||
cmp = tm.Unix()
|
||||
} else {
|
||||
tm, err := time.Parse(time.RFC3339, value)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("invalid time %s", value)
|
||||
}
|
||||
cmp = tm.Unix()
|
||||
}
|
||||
case "duration":
|
||||
v, err := time.ParseDuration(value)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("invalid duration %s", value)
|
||||
}
|
||||
cmp = int64(v)
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return func(rec *controlapi.BuildHistoryRecord) bool {
|
||||
var val int64
|
||||
switch key {
|
||||
case "startedAt":
|
||||
val = rec.CreatedAt.AsTime().Unix()
|
||||
case "completedAt":
|
||||
if rec.CompletedAt != nil {
|
||||
val = rec.CompletedAt.AsTime().Unix()
|
||||
}
|
||||
case "duration":
|
||||
if rec.CompletedAt != nil {
|
||||
val = int64(rec.CompletedAt.AsTime().Sub(rec.CreatedAt.AsTime()))
|
||||
}
|
||||
}
|
||||
switch sep {
|
||||
case ">=":
|
||||
return val >= cmp
|
||||
case "<=":
|
||||
return val <= cmp
|
||||
case ">":
|
||||
return val > cmp
|
||||
default:
|
||||
return val < cmp
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func cutAny(s string, seps ...string) (before, after, sep string, found bool) {
|
||||
for _, sep := range seps {
|
||||
if idx := strings.Index(s, sep); idx != -1 {
|
||||
return s[:idx], s[idx+len(sep):], sep, true
|
||||
}
|
||||
}
|
||||
return s, "", "", false
|
||||
}
|
||||
|
@@ -194,7 +194,7 @@ func runCreate(ctx context.Context, dockerCli command.Cli, in createOptions, arg
|
||||
}
|
||||
s := s
|
||||
eg2.Go(func() error {
|
||||
sub.Log(1, []byte(fmt.Sprintf("copying %s from %s to %s\n", s.Desc.Digest.String(), s.Ref.String(), t.String())))
|
||||
sub.Log(1, fmt.Appendf(nil, "copying %s from %s to %s\n", s.Desc.Digest.String(), s.Ref.String(), t.String()))
|
||||
return r.Copy(ctx, s, t)
|
||||
})
|
||||
}
|
||||
@@ -202,7 +202,7 @@ func runCreate(ctx context.Context, dockerCli command.Cli, in createOptions, arg
|
||||
if err := eg2.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
sub.Log(1, []byte(fmt.Sprintf("pushing %s to %s\n", desc.Digest.String(), t.String())))
|
||||
sub.Log(1, fmt.Appendf(nil, "pushing %s to %s\n", desc.Digest.String(), t.String()))
|
||||
return r.Push(ctx, t, desc, dt)
|
||||
})
|
||||
})
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"maps"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -409,9 +410,7 @@ func truncPlatforms(pfs []string, max int) truncatedPlatforms {
|
||||
left[ppf] = append(left[ppf], pf)
|
||||
}
|
||||
}
|
||||
for k, v := range left {
|
||||
res[k] = v
|
||||
}
|
||||
maps.Copy(res, left)
|
||||
return truncatedPlatforms{
|
||||
res: res,
|
||||
input: pfs,
|
||||
|
@@ -16,13 +16,14 @@ import (
|
||||
"github.com/docker/cli/cli-plugins/plugin"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/debug"
|
||||
cliflags "github.com/docker/cli/cli/flags"
|
||||
"github.com/moby/buildkit/util/appcontext"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Command {
|
||||
func NewRootCmd(name string, isPlugin bool, dockerCli *command.DockerCli) *cobra.Command {
|
||||
var opt rootOptions
|
||||
cmd := &cobra.Command{
|
||||
Short: "Docker Buildx",
|
||||
@@ -40,7 +41,17 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
|
||||
}
|
||||
cmd.SetContext(appcontext.Context())
|
||||
if !isPlugin {
|
||||
return nil
|
||||
// InstallFlags and SetDefaultOptions are necessary to match
|
||||
// the plugin mode behavior to handle env vars such as
|
||||
// DOCKER_TLS, DOCKER_TLS_VERIFY, ... and we also need to use a
|
||||
// new flagset to avoid conflict with the global debug flag
|
||||
// that we already handle in the root command otherwise it
|
||||
// would panic.
|
||||
nflags := pflag.NewFlagSet(cmd.DisplayName(), pflag.ContinueOnError)
|
||||
options := cliflags.NewClientOptions()
|
||||
options.InstallFlags(nflags)
|
||||
options.SetDefaultOptions(nflags)
|
||||
return dockerCli.Initialize(options)
|
||||
}
|
||||
return plugin.PersistentPreRunE(cmd, args)
|
||||
},
|
||||
|
@@ -13,8 +13,8 @@ import (
|
||||
type BuildxController interface {
|
||||
Build(ctx context.Context, options *controllerapi.BuildOptions, in io.ReadCloser, progress progress.Writer) (ref string, resp *client.SolveResponse, inputs *build.Inputs, err error)
|
||||
// Invoke starts an IO session into the specified process.
|
||||
// If pid doesn't matche to any running processes, it starts a new process with the specified config.
|
||||
// If there is no container running or InvokeConfig.Rollback is speicfied, the process will start in a newly created container.
|
||||
// If pid doesn't match to any running processes, it starts a new process with the specified config.
|
||||
// If there is no container running or InvokeConfig.Rollback is specified, the process will start in a newly created container.
|
||||
// NOTE: If needed, in the future, we can split this API into three APIs (NewContainer, NewProcess and Attach).
|
||||
Invoke(ctx context.Context, ref, pid string, options *controllerapi.InvokeConfig, ioIn io.ReadCloser, ioOut io.WriteCloser, ioErr io.WriteCloser) error
|
||||
Kill(ctx context.Context) error
|
||||
|
@@ -1,6 +1,10 @@
|
||||
package pb
|
||||
|
||||
import "github.com/moby/buildkit/client"
|
||||
import (
|
||||
"maps"
|
||||
|
||||
"github.com/moby/buildkit/client"
|
||||
)
|
||||
|
||||
func CreateCaches(entries []*CacheOptionsEntry) []client.CacheOptionsEntry {
|
||||
var outs []client.CacheOptionsEntry
|
||||
@@ -12,9 +16,7 @@ func CreateCaches(entries []*CacheOptionsEntry) []client.CacheOptionsEntry {
|
||||
Type: entry.Type,
|
||||
Attrs: map[string]string{},
|
||||
}
|
||||
for k, v := range entry.Attrs {
|
||||
out.Attrs[k] = v
|
||||
}
|
||||
maps.Copy(out.Attrs, entry.Attrs)
|
||||
outs = append(outs, out)
|
||||
}
|
||||
return outs
|
||||
|
@@ -2,6 +2,7 @@ package pb
|
||||
|
||||
import (
|
||||
"io"
|
||||
"maps"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
@@ -26,9 +27,7 @@ func CreateExports(entries []*ExportEntry) ([]client.ExportEntry, []string, erro
|
||||
Type: entry.Type,
|
||||
Attrs: map[string]string{},
|
||||
}
|
||||
for k, v := range entry.Attrs {
|
||||
out.Attrs[k] = v
|
||||
}
|
||||
maps.Copy(out.Attrs, entry.Attrs)
|
||||
|
||||
supportFile := false
|
||||
supportDir := false
|
||||
|
@@ -24,11 +24,11 @@ func (w *writer) Write(status *client.SolveStatus) {
|
||||
|
||||
func (w *writer) WriteBuildRef(target string, ref string) {}
|
||||
|
||||
func (w *writer) ValidateLogSource(digest.Digest, interface{}) bool {
|
||||
func (w *writer) ValidateLogSource(digest.Digest, any) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *writer) ClearLogSource(interface{}) {}
|
||||
func (w *writer) ClearLogSource(any) {}
|
||||
|
||||
func ToControlStatus(s *client.SolveStatus) *StatusResponse {
|
||||
resp := StatusResponse{}
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package pb
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"github.com/moby/buildkit/session"
|
||||
"github.com/moby/buildkit/session/sshforward/sshprovider"
|
||||
)
|
||||
@@ -10,7 +12,7 @@ func CreateSSH(ssh []*SSH) (session.Attachable, error) {
|
||||
for _, ssh := range ssh {
|
||||
cfg := sshprovider.AgentConfig{
|
||||
ID: ssh.ID,
|
||||
Paths: append([]string{}, ssh.Paths...),
|
||||
Paths: slices.Clone(ssh.Paths),
|
||||
}
|
||||
configs = append(configs, cfg)
|
||||
}
|
||||
|
@@ -39,7 +39,7 @@ func (p *Process) Done() <-chan error {
|
||||
return p.errCh
|
||||
}
|
||||
|
||||
// Manager manages a set of proceses.
|
||||
// Manager manages a set of processes.
|
||||
type Manager struct {
|
||||
container atomic.Value
|
||||
processes sync.Map
|
||||
|
@@ -140,7 +140,7 @@ func serveCmd(dockerCli command.Cli) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
pidF := filepath.Join(root, defaultPIDFilename)
|
||||
if err := os.WriteFile(pidF, []byte(fmt.Sprintf("%d", os.Getpid())), 0600); err != nil {
|
||||
if err := os.WriteFile(pidF, fmt.Appendf(nil, "%d", os.Getpid()), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
|
@@ -48,6 +48,8 @@ target "lint" {
|
||||
"linux/s390x",
|
||||
"linux/ppc64le",
|
||||
"linux/riscv64",
|
||||
"netbsd/amd64",
|
||||
"netbsd/arm64",
|
||||
"openbsd/amd64",
|
||||
"openbsd/arm64",
|
||||
"windows/amd64",
|
||||
@@ -167,6 +169,8 @@ target "binaries-cross" {
|
||||
"linux/ppc64le",
|
||||
"linux/riscv64",
|
||||
"linux/s390x",
|
||||
"netbsd/amd64",
|
||||
"netbsd/arm64",
|
||||
"openbsd/amd64",
|
||||
"openbsd/arm64",
|
||||
"windows/amd64",
|
||||
|
@@ -347,18 +347,22 @@ is defined in https://golang.org/pkg/path/#Match.
|
||||
```console
|
||||
$ docker buildx bake --set target.args.mybuildarg=value
|
||||
$ docker buildx bake --set target.platform=linux/arm64
|
||||
$ docker buildx bake --set foo*.args.mybuildarg=value # overrides build arg for all targets starting with 'foo'
|
||||
$ docker buildx bake --set *.platform=linux/arm64 # overrides platform for all targets
|
||||
$ docker buildx bake --set foo*.no-cache # bypass caching only for targets starting with 'foo'
|
||||
$ docker buildx bake --set foo*.args.mybuildarg=value # overrides build arg for all targets starting with 'foo'
|
||||
$ docker buildx bake --set *.platform=linux/arm64 # overrides platform for all targets
|
||||
$ docker buildx bake --set foo*.no-cache # bypass caching only for targets starting with 'foo'
|
||||
$ docker buildx bake --set target.platform+=linux/arm64 # appends 'linux/arm64' to the platform list
|
||||
```
|
||||
|
||||
You can override the following fields:
|
||||
|
||||
* `annotations`
|
||||
* `attest`
|
||||
* `args`
|
||||
* `cache-from`
|
||||
* `cache-to`
|
||||
* `context`
|
||||
* `dockerfile`
|
||||
* `entitlements`
|
||||
* `labels`
|
||||
* `load`
|
||||
* `no-cache`
|
||||
@@ -371,3 +375,20 @@ You can override the following fields:
|
||||
* `ssh`
|
||||
* `tags`
|
||||
* `target`
|
||||
|
||||
You can append using `+=` operator for the following fields:
|
||||
|
||||
* `annotations`¹
|
||||
* `attest`¹
|
||||
* `cache-from`
|
||||
* `cache-to`
|
||||
* `entitlements`¹
|
||||
* `no-cache-filter`
|
||||
* `output`
|
||||
* `platform`
|
||||
* `secrets`
|
||||
* `ssh`
|
||||
* `tags`
|
||||
|
||||
> [!NOTE]
|
||||
> ¹ These fields already append by default.
|
||||
|
@@ -16,7 +16,7 @@ Start a build
|
||||
| Name | Type | Default | Description |
|
||||
|:----------------------------------------|:--------------|:----------|:-------------------------------------------------------------------------------------------------------------|
|
||||
| [`--add-host`](#add-host) | `stringSlice` | | Add a custom host-to-IP mapping (format: `host:ip`) |
|
||||
| [`--allow`](#allow) | `stringSlice` | | Allow extra privileged entitlement (e.g., `network.host`, `security.insecure`) |
|
||||
| [`--allow`](#allow) | `stringArray` | | Allow extra privileged entitlement (e.g., `network.host`, `security.insecure`) |
|
||||
| [`--annotation`](#annotation) | `stringArray` | | Add annotation to the image |
|
||||
| [`--attest`](#attest) | `stringArray` | | Attestation parameters (format: `type=sbom,generator=image`) |
|
||||
| [`--build-arg`](#build-arg) | `stringArray` | | Set build-time variables |
|
||||
@@ -944,7 +944,7 @@ $ docker buildx build --secret [type=file,]id=<ID>[,src=<FILEPATH>] .
|
||||
###### `type=file` usage
|
||||
|
||||
In the following example, `type=file` is automatically detected because no
|
||||
environment variable mathing `aws` (the ID) is set.
|
||||
environment variable matching `aws` (the ID) is set.
|
||||
|
||||
```console
|
||||
$ docker buildx build --secret id=aws,src=$HOME/.aws/credentials .
|
||||
|
@@ -12,7 +12,7 @@ Start a build
|
||||
| Name | Type | Default | Description |
|
||||
|:--------------------|:--------------|:----------|:-------------------------------------------------------------------------------------------------------------|
|
||||
| `--add-host` | `stringSlice` | | Add a custom host-to-IP mapping (format: `host:ip`) |
|
||||
| `--allow` | `stringSlice` | | Allow extra privileged entitlement (e.g., `network.host`, `security.insecure`) |
|
||||
| `--allow` | `stringArray` | | Allow extra privileged entitlement (e.g., `network.host`, `security.insecure`) |
|
||||
| `--annotation` | `stringArray` | | Add annotation to the image |
|
||||
| `--attest` | `stringArray` | | Attestation parameters (format: `type=sbom,generator=image`) |
|
||||
| `--build-arg` | `stringArray` | | Set build-time variables |
|
||||
|
@@ -7,6 +7,8 @@ Commands to work on build records
|
||||
|
||||
| Name | Description |
|
||||
|:---------------------------------------|:-----------------------------------------------|
|
||||
| [`export`](buildx_history_export.md) | Export a build into Docker Desktop bundle |
|
||||
| [`import`](buildx_history_import.md) | Import a build into Docker Desktop |
|
||||
| [`inspect`](buildx_history_inspect.md) | Inspect a build |
|
||||
| [`logs`](buildx_history_logs.md) | Print the logs of a build |
|
||||
| [`ls`](buildx_history_ls.md) | List build records |
|
||||
|
17
docs/reference/buildx_history_export.md
Normal file
17
docs/reference/buildx_history_export.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# docker buildx history export
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Export a build into Docker Desktop bundle
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:-----------------|:---------|:--------|:-----------------------------------------|
|
||||
| `--all` | `bool` | | Export all records for the builder |
|
||||
| `--builder` | `string` | | Override the configured builder instance |
|
||||
| `-D`, `--debug` | `bool` | | Enable debug logging |
|
||||
| `-o`, `--output` | `string` | | Output file path |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
16
docs/reference/buildx_history_import.md
Normal file
16
docs/reference/buildx_history_import.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# docker buildx history import
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Import a build into Docker Desktop
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:----------------|:--------------|:--------|:-----------------------------------------|
|
||||
| `--builder` | `string` | | Override the configured builder instance |
|
||||
| `-D`, `--debug` | `bool` | | Enable debug logging |
|
||||
| `-f`, `--file` | `stringArray` | | Import from a file path |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
@@ -5,12 +5,14 @@ List build records
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:----------------|:---------|:--------|:-----------------------------------------|
|
||||
| `--builder` | `string` | | Override the configured builder instance |
|
||||
| `-D`, `--debug` | `bool` | | Enable debug logging |
|
||||
| `--format` | `string` | `table` | Format the output |
|
||||
| `--no-trunc` | `bool` | | Don't truncate output |
|
||||
| Name | Type | Default | Description |
|
||||
|:----------------|:--------------|:--------|:---------------------------------------------|
|
||||
| `--builder` | `string` | | Override the configured builder instance |
|
||||
| `-D`, `--debug` | `bool` | | Enable debug logging |
|
||||
| `--filter` | `stringArray` | | Provide filter values (e.g., `status=error`) |
|
||||
| `--format` | `string` | `table` | Format the output |
|
||||
| `--local` | `bool` | | List records for current repository only |
|
||||
| `--no-trunc` | `bool` | | Don't truncate output |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
@@ -56,6 +56,7 @@ type Driver struct {
|
||||
restartPolicy container.RestartPolicy
|
||||
env []string
|
||||
defaultLoad bool
|
||||
gpus []container.DeviceRequest
|
||||
}
|
||||
|
||||
func (d *Driver) IsMobyDriver() bool {
|
||||
@@ -106,8 +107,9 @@ func (d *Driver) create(ctx context.Context, l progress.SubLogger) error {
|
||||
}); err != nil {
|
||||
// image pulling failed, check if it exists in local image store.
|
||||
// if not, return pulling error. otherwise log it.
|
||||
_, _, errInspect := d.DockerAPI.ImageInspectWithRaw(ctx, imageName)
|
||||
if errInspect != nil {
|
||||
_, errInspect := d.DockerAPI.ImageInspect(ctx, imageName)
|
||||
found := errInspect == nil
|
||||
if !found {
|
||||
return err
|
||||
}
|
||||
l.Wrap("pulling failed, using local image "+imageName, func() error { return nil })
|
||||
@@ -157,6 +159,9 @@ func (d *Driver) create(ctx context.Context, l progress.SubLogger) error {
|
||||
if d.cpusetMems != "" {
|
||||
hc.Resources.CpusetMems = d.cpusetMems
|
||||
}
|
||||
if len(d.gpus) > 0 && d.hasGPUCapability(ctx, cfg.Image, d.gpus) {
|
||||
hc.Resources.DeviceRequests = d.gpus
|
||||
}
|
||||
if info, err := d.DockerAPI.Info(ctx); err == nil {
|
||||
if info.CgroupDriver == "cgroupfs" {
|
||||
// Place all buildkit containers inside this cgroup by default so limits can be attached
|
||||
@@ -419,6 +424,7 @@ func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
|
||||
driver.DockerExporter: true,
|
||||
driver.CacheExport: true,
|
||||
driver.MultiPlatform: true,
|
||||
driver.DirectPush: true,
|
||||
driver.DefaultLoad: d.defaultLoad,
|
||||
}
|
||||
}
|
||||
@@ -427,6 +433,31 @@ func (d *Driver) HostGatewayIP(ctx context.Context) (net.IP, error) {
|
||||
return nil, errors.New("host-gateway is not supported by the docker-container driver")
|
||||
}
|
||||
|
||||
// hasGPUCapability checks if docker daemon has GPU capability. We need to run
|
||||
// a dummy container with GPU device to check if the daemon has this capability
|
||||
// because there is no API to check it yet.
|
||||
func (d *Driver) hasGPUCapability(ctx context.Context, image string, gpus []container.DeviceRequest) bool {
|
||||
cfg := &container.Config{
|
||||
Image: image,
|
||||
Entrypoint: []string{"/bin/true"},
|
||||
}
|
||||
hc := &container.HostConfig{
|
||||
NetworkMode: container.NetworkMode(container.IPCModeNone),
|
||||
AutoRemove: true,
|
||||
Resources: container.Resources{
|
||||
DeviceRequests: gpus,
|
||||
},
|
||||
}
|
||||
resp, err := d.DockerAPI.ContainerCreate(ctx, cfg, hc, &network.NetworkingConfig{}, nil, "")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if err := d.DockerAPI.ContainerStart(ctx, resp.ID, container.StartOptions{}); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func demuxConn(c net.Conn) net.Conn {
|
||||
pr, pw := io.Pipe()
|
||||
// TODO: rewrite parser with Reader() to avoid goroutine switch
|
||||
|
@@ -51,6 +51,12 @@ func (f *factory) New(ctx context.Context, cfg driver.InitConfig) (driver.Driver
|
||||
InitConfig: cfg,
|
||||
restartPolicy: rp,
|
||||
}
|
||||
var gpus dockeropts.GpuOpts
|
||||
if err := gpus.Set("all"); err == nil {
|
||||
if v := gpus.Value(); len(v) > 0 {
|
||||
d.gpus = v
|
||||
}
|
||||
}
|
||||
for k, v := range cfg.DriverOpts {
|
||||
switch {
|
||||
case k == "network":
|
||||
|
@@ -93,6 +93,7 @@ func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
|
||||
driver.DockerExporter: useContainerdSnapshotter,
|
||||
driver.CacheExport: useContainerdSnapshotter,
|
||||
driver.MultiPlatform: useContainerdSnapshotter,
|
||||
driver.DirectPush: useContainerdSnapshotter,
|
||||
driver.DefaultLoad: true,
|
||||
}
|
||||
})
|
||||
|
@@ -7,5 +7,6 @@ const DockerExporter Feature = "Docker exporter"
|
||||
|
||||
const CacheExport Feature = "Cache export"
|
||||
const MultiPlatform Feature = "Multi-platform build"
|
||||
const DirectPush Feature = "Direct push"
|
||||
|
||||
const DefaultLoad Feature = "Automatically load images to the Docker Engine image store"
|
||||
|
@@ -35,10 +35,10 @@ func testEndpoint(server, defaultNamespace string, ca, cert, key []byte, skipTLS
|
||||
}
|
||||
|
||||
var testStoreCfg = store.NewConfig(
|
||||
func() interface{} {
|
||||
return &map[string]interface{}{}
|
||||
func() any {
|
||||
return &map[string]any{}
|
||||
},
|
||||
store.EndpointTypeGetter(KubernetesEndpoint, func() interface{} { return &EndpointMeta{} }),
|
||||
store.EndpointTypeGetter(KubernetesEndpoint, func() any { return &EndpointMeta{} }),
|
||||
)
|
||||
|
||||
func TestSaveLoadContexts(t *testing.T) {
|
||||
@@ -197,7 +197,7 @@ func checkClientConfig(t *testing.T, ep Endpoint, server, namespace string, ca,
|
||||
|
||||
func save(s store.Writer, ep Endpoint, name string) error {
|
||||
meta := store.Metadata{
|
||||
Endpoints: map[string]interface{}{
|
||||
Endpoints: map[string]any{
|
||||
KubernetesEndpoint: ep.EndpointMeta,
|
||||
},
|
||||
Name: name,
|
||||
|
@@ -43,7 +43,7 @@ type Endpoint struct {
|
||||
|
||||
func init() {
|
||||
command.RegisterDefaultStoreEndpoints(
|
||||
store.EndpointTypeGetter(KubernetesEndpoint, func() interface{} { return &EndpointMeta{} }),
|
||||
store.EndpointTypeGetter(KubernetesEndpoint, func() any { return &EndpointMeta{} }),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ func (c *Endpoint) KubernetesConfig() clientcmd.ClientConfig {
|
||||
|
||||
// ResolveDefault returns endpoint metadata for the default Kubernetes
|
||||
// endpoint, which is derived from the env-based kubeconfig.
|
||||
func (c *EndpointMeta) ResolveDefault() (interface{}, *store.EndpointTLSData, error) {
|
||||
func (c *EndpointMeta) ResolveDefault() (any, *store.EndpointTLSData, error) {
|
||||
kubeconfig := os.Getenv("KUBECONFIG")
|
||||
if kubeconfig == "" {
|
||||
kubeconfig = filepath.Join(homedir.Get(), ".kube/config")
|
||||
|
@@ -238,6 +238,7 @@ func (d *Driver) Features(_ context.Context) map[driver.Feature]bool {
|
||||
driver.DockerExporter: d.DockerAPI != nil,
|
||||
driver.CacheExport: true,
|
||||
driver.MultiPlatform: true, // Untested (needs multiple Driver instances)
|
||||
driver.DirectPush: true,
|
||||
driver.DefaultLoad: d.defaultLoad,
|
||||
}
|
||||
}
|
||||
|
@@ -90,7 +90,7 @@ func ListRunningPods(ctx context.Context, client clientcorev1.PodInterface, depl
|
||||
for i := range podList.Items {
|
||||
pod := &podList.Items[i]
|
||||
if pod.Status.Phase == corev1.PodRunning {
|
||||
logrus.Debugf("pod runnning: %q", pod.Name)
|
||||
logrus.Debugf("pod running: %q", pod.Name)
|
||||
runningPods = append(runningPods, pod)
|
||||
}
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@ func GenerateNodeName(builderName string, txn *store.Txn) (string, error) {
|
||||
}
|
||||
|
||||
var name string
|
||||
for i := 0; i < 6; i++ {
|
||||
for range 6 {
|
||||
name, err = randomName()
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@@ -28,7 +28,7 @@ type Driver struct {
|
||||
*tlsOpts
|
||||
defaultLoad bool
|
||||
|
||||
// remote driver caches the client because its Bootstap/Info methods reuse it internally
|
||||
// remote driver caches the client because its Bootstrap/Info methods reuse it internally
|
||||
clientOnce sync.Once
|
||||
client *client.Client
|
||||
err error
|
||||
@@ -164,6 +164,7 @@ func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
|
||||
driver.DockerExporter: true,
|
||||
driver.CacheExport: true,
|
||||
driver.MultiPlatform: true,
|
||||
driver.DirectPush: true,
|
||||
driver.DefaultLoad: d.defaultLoad,
|
||||
}
|
||||
}
|
||||
|
57
go.mod
57
go.mod
@@ -1,14 +1,14 @@
|
||||
module github.com/docker/buildx
|
||||
|
||||
go 1.22.0
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
github.com/Masterminds/semver/v3 v3.2.1
|
||||
github.com/Microsoft/go-winio v0.6.2
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.27
|
||||
github.com/compose-spec/compose-go/v2 v2.4.7
|
||||
github.com/compose-spec/compose-go/v2 v2.6.0
|
||||
github.com/containerd/console v1.0.4
|
||||
github.com/containerd/containerd/v2 v2.0.2
|
||||
github.com/containerd/containerd/v2 v2.0.4
|
||||
github.com/containerd/continuity v0.4.5
|
||||
github.com/containerd/errdefs v1.0.0
|
||||
github.com/containerd/log v0.1.0
|
||||
@@ -17,9 +17,9 @@ require (
|
||||
github.com/creack/pty v1.1.24
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/distribution/reference v0.6.0
|
||||
github.com/docker/cli v27.5.1+incompatible
|
||||
github.com/docker/cli v28.0.4+incompatible
|
||||
github.com/docker/cli-docs-tool v0.9.0
|
||||
github.com/docker/docker v27.5.1+incompatible
|
||||
github.com/docker/docker v28.0.4+incompatible
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/gofrs/flock v0.12.1
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
@@ -29,35 +29,35 @@ require (
|
||||
github.com/hashicorp/hcl/v2 v2.23.0
|
||||
github.com/in-toto/in-toto-golang v0.5.0
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
github.com/moby/buildkit v0.20.0-rc2
|
||||
github.com/moby/buildkit v0.21.0-rc2
|
||||
github.com/moby/sys/mountinfo v0.7.2
|
||||
github.com/moby/sys/signal v0.7.1
|
||||
github.com/morikuni/aec v1.0.0
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/opencontainers/image-spec v1.1.0
|
||||
github.com/opencontainers/image-spec v1.1.1
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10
|
||||
github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/spf13/pflag v1.0.6
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250410151801-5b74a7ad7583
|
||||
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4
|
||||
github.com/tonistiigi/jaeger-ui-rest v0.0.0-20250211190051-7d4944a45bb6
|
||||
github.com/tonistiigi/jaeger-ui-rest v0.0.0-20250408171107-3dd17559e117
|
||||
github.com/zclconf/go-cty v1.16.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/sdk v1.31.0
|
||||
go.opentelemetry.io/otel/trace v1.31.0
|
||||
golang.org/x/mod v0.22.0
|
||||
golang.org/x/sync v0.10.0
|
||||
golang.org/x/sys v0.29.0
|
||||
golang.org/x/term v0.27.0
|
||||
golang.org/x/text v0.21.0
|
||||
golang.org/x/mod v0.24.0
|
||||
golang.org/x/sync v0.13.0
|
||||
golang.org/x/sys v0.32.0
|
||||
golang.org/x/term v0.31.0
|
||||
golang.org/x/text v0.24.0
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38
|
||||
google.golang.org/grpc v1.69.4
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1
|
||||
@@ -71,7 +71,6 @@ require (
|
||||
require (
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // 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/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/apparentlymart/go-cidr v1.0.1 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
@@ -95,10 +94,10 @@ require (
|
||||
github.com/containerd/ttrpc v1.2.7 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.2 // indirect
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
||||
github.com/docker/docker-credential-helpers v0.9.3 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-metrics v0.0.1 // indirect
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fvbommel/sortorder v1.0.1 // indirect
|
||||
@@ -112,7 +111,7 @@ require (
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
@@ -123,19 +122,17 @@ require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/mattn/go-shellwords v1.0.12 // indirect
|
||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||
github.com/moby/spdystream v0.4.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.4.0 // indirect
|
||||
github.com/moby/sys/userns v0.1.0 // indirect
|
||||
github.com/moby/term v0.5.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
@@ -152,13 +149,14 @@ require (
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
|
||||
github.com/shibumi/go-pathspec v1.3.0 // indirect
|
||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||
github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205 // indirect
|
||||
github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323 // indirect
|
||||
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
|
||||
github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.56.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect
|
||||
@@ -169,12 +167,11 @@ require (
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.31.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/oauth2 v0.23.0 // indirect
|
||||
golang.org/x/time v0.6.0 // indirect
|
||||
golang.org/x/tools v0.27.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.32.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
132
go.sum
132
go.sum
@@ -4,7 +4,6 @@ github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2 h1:dIS
|
||||
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-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||
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/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
@@ -13,8 +12,6 @@ github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA
|
||||
github.com/Microsoft/hcsshim v0.12.9 h1:2zJy5KA+l0loz1HzEGqyNnjd3fyZA31ZBCGKacp6lLg=
|
||||
github.com/Microsoft/hcsshim v0.12.9/go.mod h1:fJ0gkFAna6ukt0bLdKB8djt4XIJhF/vEPuoIWYVvZ8Y=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
|
||||
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
|
||||
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
@@ -63,30 +60,26 @@ github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENU
|
||||
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
|
||||
github.com/bmatcuk/doublestar v1.1.5/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0 h1:s7+5BfS4WFJoVF9pnB8kBk03S7pZXRdKamnV0FOl5Sc=
|
||||
github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ=
|
||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e85keuznYcH5rqI438v41pKcBl4ZxQ=
|
||||
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
|
||||
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
|
||||
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/go.mod h1:lFN0DrMxIncJGYAXTfWuajfwj5haBJqrBkarHcnjJKc=
|
||||
github.com/compose-spec/compose-go/v2 v2.6.0 h1:/+oBD2ixSENOeN/TlJqWZmUak0xM8A7J08w/z661Wd4=
|
||||
github.com/compose-spec/compose-go/v2 v2.6.0/go.mod h1:vPlkN0i+0LjLf9rv52lodNMUTJF5YHVfHVGLLIP67NA=
|
||||
github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo=
|
||||
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/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/go.mod h1:dFv4lt6S20wTu/hMcP4350RL87qPWLVa/OHOwmmdnYc=
|
||||
github.com/containerd/containerd/v2 v2.0.2 h1:GmH/tRBlTvrXOLwSpWE2vNAm8+MqI6nmxKpKBNKY8Wc=
|
||||
github.com/containerd/containerd/v2 v2.0.2/go.mod h1:wIqEvQ/6cyPFUGJ5yMFanspPabMLor+bF865OHvNTTI=
|
||||
github.com/containerd/containerd/v2 v2.0.4 h1:+r7yJMwhTfMm3CDyiBjMBQO8a9CTBxL2Bg/JtqtIwB8=
|
||||
github.com/containerd/containerd/v2 v2.0.4/go.mod h1:5j9QUUaV/cy9ZeAx4S+8n9ffpf+iYnEj4jiExgcbuLY=
|
||||
github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
|
||||
github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
|
||||
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
||||
@@ -110,7 +103,6 @@ github.com/containerd/ttrpc v1.2.7 h1:qIrroQvuOL9HQ1X6KHe2ohc7p+HP/0VE6XPU7elJRq
|
||||
github.com/containerd/ttrpc v1.2.7/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o=
|
||||
github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40=
|
||||
github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
@@ -122,17 +114,17 @@ 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/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/docker/cli v27.5.1+incompatible h1:JB9cieUT9YNiMITtIsguaN55PLOHhBSz3LKVc6cqWaY=
|
||||
github.com/docker/cli v27.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v28.0.4+incompatible h1:pBJSJeNd9QeIWPjRcV91RVJihd/TXB77q1ef64XEu4A=
|
||||
github.com/docker/cli v28.0.4+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/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.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/docker v27.5.1+incompatible h1:4PYU5dnBYqRQi0294d1FBECqT9ECWeQAIfE8q4YnPY8=
|
||||
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/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||
github.com/docker/docker v28.0.4+incompatible h1:JNNkBctYKurkw6FrHfKqY0nKIDf5nrbxjVBtS+cdcok=
|
||||
github.com/docker/docker v28.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
|
||||
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
|
||||
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/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
@@ -152,8 +144,6 @@ github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/fvbommel/sortorder v1.0.1 h1:dSnXLt4mJYH25uDDGa3biZNQsozaUWDSWeKJ0qqFfzE=
|
||||
github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
@@ -173,7 +163,6 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
|
||||
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-sql-driver/mysql v1.3.0 h1:pgwjLi/dvffoP9aabwkT3AKpXQM93QARkjFhDDqC1UE=
|
||||
github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
@@ -198,15 +187,14 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93 h1:jc2UWq7CbdszqeH6qu1ougXMIUBfSy8Pbh/anURYbGI=
|
||||
github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
||||
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
||||
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -224,7 +212,6 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
@@ -245,9 +232,7 @@ github.com/in-toto/in-toto-golang v0.5.0/go.mod h1:/Rq0IZHLV7Ku5gielPT4wPHJfH1Gd
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8 h1:CZkYfurY6KGhVtlalI4QwQ6T0Cu6iuY3e0x5RLu96WE=
|
||||
github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
|
||||
github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d h1:jRQLvyVGL+iVtDElaEIDdKwpPqUIZJfzkNLV34htpEc=
|
||||
github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
@@ -260,8 +245,8 @@ github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVE
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
@@ -276,7 +261,6 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.5.3 h1:C8fxWnhYyME3n0klPOhVM7PtYUB3eV1W3DeFmN3j53Y=
|
||||
github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
@@ -295,10 +279,8 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZX
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||
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/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moby/buildkit v0.20.0-rc2 h1:QjACghvG0pSAp7dk9aQMYWioDEOljDWyyoUjyg35qfg=
|
||||
github.com/moby/buildkit v0.20.0-rc2/go.mod h1:kMXf90l/f3zygRK8bYbyetfyzoJYntb6Bpi2VsLfXgQ=
|
||||
github.com/moby/buildkit v0.21.0-rc2 h1:JxocuYzqoGLPzftFiDi/Afb85RbXWqt3ObEADRdFFE0=
|
||||
github.com/moby/buildkit v0.21.0-rc2/go.mod h1:mBq0D44uCyz2PdX8T/qym5LBbkBO3GGv0wqgX9ABYYw=
|
||||
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/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
|
||||
@@ -313,8 +295,8 @@ github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7z
|
||||
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||
github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0=
|
||||
github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8=
|
||||
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.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
|
||||
github.com/moby/sys/user v0.4.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/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
|
||||
@@ -347,15 +329,12 @@ github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
|
||||
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 h1:DmNGcqH3WDbV5k8OJ+esPWbqUOX5rMLR2PMvziDMJi0=
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626/go.mod h1:BRHJJd0E+cx42OybVYSgUvZmU0B8P9gZuRXlZUP7TKI=
|
||||
github.com/opencontainers/selinux v1.11.1 h1:nHFvthhM0qY8/m+vfhJylliSshm8G1jJ2jDMcgULaH8=
|
||||
github.com/opencontainers/selinux v1.11.1/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
|
||||
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
@@ -410,17 +389,14 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spdx/tools-golang v0.5.3 h1:ialnHeEYUC4+hkm5vJm4qz2x+oEJbS0mAMFrNXdQraY=
|
||||
github.com/spdx/tools-golang v0.5.3/go.mod h1:/ETOahiAo96Ob0/RAIBmFZw6XN0yTnyr/uFZm2NTMhI=
|
||||
github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94 h1:JmfC365KywYwHB946TTiQWEb8kqPY+pybPLoGE9GgVk=
|
||||
github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
|
||||
github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431 h1:XTHrT015sxHyJ5FnQ0AeemSspZWaDq7DoTRW0EVsDCE=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v0.0.0-20150530192845-be5ff3e4840c h1:2EejZtjFjKJGk71ANb+wtFK5EjUzUkEM3R0xnp559xg=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v0.0.0-20150530192845-be5ff3e4840c/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -437,18 +413,16 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c=
|
||||
github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
|
||||
github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205 h1:eUk79E1w8yMtXeHSzjKorxuC8qJOnyXQnLaJehxpJaI=
|
||||
github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205/go.mod h1:3Iuxbr0P7D3zUzBMAZB+ois3h/et0shEz0qApgHYGpY=
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a h1:EfGw4G0x/8qXWgtcZ6KVaPS+wpWOQMaypczzP8ojkMY=
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a/go.mod h1:Dl/9oEjK7IqnjAm21Okx/XIxUCFJzvh+XdVHUlBwXTw=
|
||||
github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323 h1:r0p7fK56l8WPequOaR3i9LBqfPtEdXIQbUTzT55iqT4=
|
||||
github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323/go.mod h1:3Iuxbr0P7D3zUzBMAZB+ois3h/et0shEz0qApgHYGpY=
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250410151801-5b74a7ad7583 h1:mK+ZskNt7SG4dxfKIi27C7qHAQzyjAVt1iyTf0hmsNc=
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250410151801-5b74a7ad7583/go.mod h1:BKdcez7BiVtBvIcef90ZPc6ebqIWr4JWD7+EvLm6J98=
|
||||
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/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/jaeger-ui-rest v0.0.0-20250408171107-3dd17559e117 h1:XFwyh2JZwR5aiKLXHX2C1n0v5F11dCJpyGL1W/Cpl3U=
|
||||
github.com/tonistiigi/jaeger-ui-rest v0.0.0-20250408171107-3dd17559e117/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/go.mod h1:WPnis/6cRcDZSUvVmezrxJPkiO87ThFYsoUiMwWNDJk=
|
||||
github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab h1:H6aJ0yKQ0gF49Qb2z5hI1UHxSQt4JMyxebFR15KnApw=
|
||||
@@ -465,6 +439,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ=
|
||||
@@ -514,14 +490,12 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20200422194213-44a606286825/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
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/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
|
||||
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
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.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@@ -529,8 +503,8 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
||||
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -539,8 +513,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -553,24 +527,24 @@ 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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
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/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
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-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
|
||||
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
|
||||
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
|
||||
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
|
||||
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -589,7 +563,6 @@ google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8i
|
||||
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
|
||||
gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -600,7 +573,6 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
|
||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1 h1:d4KQkxAaAiRY2h5Zqis161Pv91A37uZyJOx73duwUwM=
|
||||
gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1/go.mod h1:WbjuEoo1oadwzQ4apSDU+JTvmllEHtsNHS6y7vFc7iw=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
@@ -632,7 +604,3 @@ sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+s
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
tags.cncf.io/container-device-interface v0.8.0 h1:8bCFo/g9WODjWx3m6EYl3GfUG31eKJbaggyBDxEldRc=
|
||||
tags.cncf.io/container-device-interface v0.8.0/go.mod h1:Apb7N4VdILW0EVdEMRYXIDVRZfNJZ+kmEUss2kRRQ6Y=
|
||||
tags.cncf.io/container-device-interface/specs-go v0.8.0 h1:QYGFzGxvYK/ZLMrjhvY0RjpUavIn4KcmRmVP/JjdBTA=
|
||||
tags.cncf.io/container-device-interface/specs-go v0.8.0/go.mod h1:BhJIkjjPh4qpys+qm4DAYtUyryaTDg9zris+AczXyws=
|
||||
|
@@ -9,10 +9,13 @@ Vagrant.configure("2") do |config|
|
||||
|
||||
config.vm.provision "init", type: "shell", run: "once" do |sh|
|
||||
sh.inline = <<~SHELL
|
||||
set -x
|
||||
pkg bootstrap
|
||||
pkg install -y go123 git
|
||||
ln -s /usr/local/bin/go123 /usr/local/bin/go
|
||||
go install gotest.tools/gotestsum@#{ENV['GOTESTSUM_VERSION']}
|
||||
pkg install -y git
|
||||
|
||||
fetch https://go.dev/dl/go#{ENV['GO_VERSION']}.freebsd-amd64.tar.gz
|
||||
tar -C /usr/local -xzf go#{ENV['GO_VERSION']}.freebsd-amd64.tar.gz
|
||||
ln -s /usr/local/go/bin/go /usr/local/bin/go
|
||||
SHELL
|
||||
end
|
||||
end
|
||||
|
32
hack/Vagrantfile.netbsd
Normal file
32
hack/Vagrantfile.netbsd
Normal file
@@ -0,0 +1,32 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "generic/netbsd9"
|
||||
config.vm.boot_timeout = 900
|
||||
config.vm.synced_folder ".", "/vagrant", type: "rsync"
|
||||
config.ssh.keep_alive = true
|
||||
|
||||
config.vm.provision "init", type: "shell", run: "once" do |sh|
|
||||
sh.inline = <<~SHELL
|
||||
set -x
|
||||
mkdir -p /var/tmp
|
||||
chmod 1777 /var/tmp
|
||||
|
||||
pkgin -y install git mozilla-rootcerts
|
||||
mozilla-rootcerts install
|
||||
|
||||
ftp https://go.dev/dl/go#{ENV['GO_VERSION']}.netbsd-amd64.tar.gz
|
||||
tar -C /var/tmp -xzf go#{ENV['GO_VERSION']}.netbsd-amd64.tar.gz
|
||||
|
||||
cat << 'EOF' > /usr/bin/go-wrapper
|
||||
#!/bin/sh
|
||||
export TMPDIR="/var/tmp"
|
||||
exec /var/tmp/go/bin/go "$@"
|
||||
EOF
|
||||
chmod +x /usr/bin/go-wrapper
|
||||
|
||||
ln -s /usr/bin/go-wrapper /usr/bin/go
|
||||
SHELL
|
||||
end
|
||||
end
|
@@ -10,12 +10,12 @@ Vagrant.configure("2") do |config|
|
||||
|
||||
config.vm.provision "init", type: "shell", run: "once" do |sh|
|
||||
sh.inline = <<~SHELL
|
||||
set -x
|
||||
pkg_add -x git
|
||||
|
||||
ftp https://go.dev/dl/go1.23.3.openbsd-amd64.tar.gz
|
||||
tar -C /usr/local -xzf go1.23.3.openbsd-amd64.tar.gz
|
||||
ftp https://go.dev/dl/go#{ENV['GO_VERSION']}.openbsd-amd64.tar.gz
|
||||
tar -C /usr/local -xzf go#{ENV['GO_VERSION']}.openbsd-amd64.tar.gz
|
||||
ln -s /usr/local/go/bin/go /usr/local/bin/go
|
||||
go install gotest.tools/gotestsum@#{ENV['GOTESTSUM_VERSION']}
|
||||
SHELL
|
||||
end
|
||||
end
|
||||
|
@@ -5,9 +5,10 @@ ARG ALPINE_VERSION=3.21
|
||||
ARG XX_VERSION=1.6.1
|
||||
|
||||
ARG GOLANGCI_LINT_VERSION=1.62.0
|
||||
ARG GOPLS_VERSION=v0.26.0
|
||||
# v0.31 requires go1.24
|
||||
ARG GOPLS_VERSION=v0.30.0
|
||||
# disabled: deprecated unusedvariable simplifyrange
|
||||
ARG GOPLS_ANALYZERS="embeddirective fillreturns infertypeargs nonewvars noresultvalues simplifycompositelit simplifyslice undeclaredname unusedparams useany"
|
||||
ARG GOPLS_ANALYZERS="embeddirective fillreturns hostport infertypeargs modernize nonewvars noresultvalues simplifycompositelit simplifyslice unusedparams yield"
|
||||
|
||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
||||
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/buildx/util/confutil"
|
||||
@@ -14,6 +15,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
version = 2
|
||||
refsDir = "refs"
|
||||
groupDir = "__group__"
|
||||
)
|
||||
@@ -31,12 +33,8 @@ type State struct {
|
||||
}
|
||||
|
||||
type StateGroup struct {
|
||||
// Definition is the raw representation of the group (bake definition)
|
||||
Definition []byte
|
||||
// Targets are the targets invoked
|
||||
Targets []string `json:",omitempty"`
|
||||
// Inputs are the user inputs (bake overrides)
|
||||
Inputs []string `json:",omitempty"`
|
||||
// Refs are used to track all the refs that belong to the same group
|
||||
Refs []string
|
||||
}
|
||||
@@ -52,9 +50,7 @@ func New(cfg *confutil.Config) (*LocalState, error) {
|
||||
if err := cfg.MkdirAll(refsDir, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &LocalState{
|
||||
cfg: cfg,
|
||||
}, nil
|
||||
return &LocalState{cfg: cfg}, nil
|
||||
}
|
||||
|
||||
func (ls *LocalState) ReadRef(builderName, nodeName, id string) (*State, error) {
|
||||
@@ -87,8 +83,12 @@ func (ls *LocalState) SaveRef(builderName, nodeName, id string, st State) error
|
||||
return ls.cfg.AtomicWriteFile(filepath.Join(refDir, id), dt, 0644)
|
||||
}
|
||||
|
||||
func (ls *LocalState) GroupDir() string {
|
||||
return filepath.Join(ls.cfg.Dir(), refsDir, groupDir)
|
||||
}
|
||||
|
||||
func (ls *LocalState) ReadGroup(id string) (*StateGroup, error) {
|
||||
dt, err := os.ReadFile(filepath.Join(ls.cfg.Dir(), refsDir, groupDir, id))
|
||||
dt, err := os.ReadFile(filepath.Join(ls.GroupDir(), id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -208,7 +208,7 @@ func (ls *LocalState) removeGroup(id string) error {
|
||||
if id == "" {
|
||||
return errors.Errorf("group ref empty")
|
||||
}
|
||||
f := filepath.Join(ls.cfg.Dir(), refsDir, groupDir, id)
|
||||
f := filepath.Join(ls.GroupDir(), id)
|
||||
if _, err := os.Lstat(f); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
@@ -230,3 +230,16 @@ func (ls *LocalState) validate(builderName, nodeName, id string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ls *LocalState) readVersion() int {
|
||||
if vdt, err := os.ReadFile(filepath.Join(ls.cfg.Dir(), refsDir, "version")); err == nil {
|
||||
if v, err := strconv.Atoi(string(vdt)); err == nil {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func (ls *LocalState) writeVersion(version int) error {
|
||||
return ls.cfg.AtomicWriteFile(filepath.Join(refsDir, "version"), []byte(strconv.Itoa(version)), 0600)
|
||||
}
|
||||
|
@@ -68,10 +68,8 @@ var (
|
||||
|
||||
testStateGroupID = "kvqs0sgly2rmitz84r25u9qd0"
|
||||
testStateGroup = StateGroup{
|
||||
Definition: []byte(`{"group":{"default":{"targets":["pre-checkin"]},"pre-checkin":{"targets":["vendor-update","format","build"]}},"target":{"build":{"context":".","dockerfile":"dev.Dockerfile","target":"build-update","platforms":["linux/amd64"],"output":["."]},"format":{"context":".","dockerfile":"dev.Dockerfile","target":"format-update","platforms":["linux/amd64"],"output":["."]},"vendor-update":{"context":".","dockerfile":"dev.Dockerfile","target":"vendor-update","platforms":["linux/amd64"],"output":["."]}}}`),
|
||||
Targets: []string{"pre-checkin"},
|
||||
Inputs: []string{"*.platform=linux/amd64"},
|
||||
Refs: []string{"builder/builder0/hx2qf1w11qvz1x3k471c5i8xw", "builder/builder0/968zj0g03jmlx0s8qslnvh6rl", "builder/builder0/naf44f9i1710lf7y12lv5hb1z"},
|
||||
Targets: []string{"pre-checkin"},
|
||||
Refs: []string{"builder/builder0/hx2qf1w11qvz1x3k471c5i8xw", "builder/builder0/968zj0g03jmlx0s8qslnvh6rl", "builder/builder0/naf44f9i1710lf7y12lv5hb1z"},
|
||||
}
|
||||
|
||||
testStateGroupRef1ID = "hx2qf1w11qvz1x3k471c5i8xw"
|
||||
|
56
localstate/migrate.go
Normal file
56
localstate/migrate.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package localstate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (ls *LocalState) MigrateIfNeeded() error {
|
||||
currentVersion := ls.readVersion()
|
||||
if currentVersion == version {
|
||||
return nil
|
||||
}
|
||||
migrations := map[int]func(*LocalState) error{
|
||||
2: (*LocalState).migration2,
|
||||
}
|
||||
for v := currentVersion + 1; v <= version; v++ {
|
||||
migration, found := migrations[v]
|
||||
if !found {
|
||||
return errors.Errorf("localstate migration v%d not found", v)
|
||||
}
|
||||
if err := migration(ls); err != nil {
|
||||
return errors.Wrapf(err, "localstate migration v%d failed", v)
|
||||
}
|
||||
}
|
||||
return ls.writeVersion(version)
|
||||
}
|
||||
|
||||
func (ls *LocalState) migration2() error {
|
||||
return filepath.Walk(ls.GroupDir(), func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
dt, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var stg StateGroup
|
||||
if err := json.Unmarshal(dt, &stg); err != nil {
|
||||
return err
|
||||
}
|
||||
mdt, err := json.Marshal(stg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.WriteFile(path, mdt, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"slices"
|
||||
|
||||
"github.com/docker/buildx/monitor/types"
|
||||
"github.com/pkg/errors"
|
||||
@@ -50,14 +51,7 @@ func (cm *AttachCmd) Exec(ctx context.Context, args []string) error {
|
||||
if err != nil {
|
||||
return errors.Errorf("failed to get the list of sessions: %v", err)
|
||||
}
|
||||
found := false
|
||||
for _, s := range refs {
|
||||
if s == ref {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
if !slices.Contains(refs, ref) {
|
||||
return errors.Errorf("unknown ID: %q", ref)
|
||||
}
|
||||
cm.m.Detach() // Finish existing attach
|
||||
|
@@ -2,6 +2,8 @@ package store
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/platforms"
|
||||
@@ -44,7 +46,7 @@ func (ng *NodeGroup) Leave(name string) error {
|
||||
if len(ng.Nodes) == 1 {
|
||||
return errors.Errorf("can not leave last node, do you want to rm instance instead?")
|
||||
}
|
||||
ng.Nodes = append(ng.Nodes[:i], ng.Nodes[i+1:]...)
|
||||
ng.Nodes = slices.Delete(ng.Nodes, i, i+1)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -92,9 +94,7 @@ func (ng *NodeGroup) Update(name, endpoint string, platforms []string, endpoints
|
||||
needsRestart = true
|
||||
}
|
||||
if buildkitdConfigFile != "" {
|
||||
for k, v := range files {
|
||||
n.Files[k] = v
|
||||
}
|
||||
maps.Copy(n.Files, files)
|
||||
needsRestart = true
|
||||
}
|
||||
if needsRestart {
|
||||
@@ -146,9 +146,7 @@ func (n *Node) Copy() *Node {
|
||||
buildkitdFlags := []string{}
|
||||
copy(buildkitdFlags, n.BuildkitdFlags)
|
||||
driverOpts := map[string]string{}
|
||||
for k, v := range n.DriverOpts {
|
||||
driverOpts[k] = v
|
||||
}
|
||||
maps.Copy(driverOpts, n.DriverOpts)
|
||||
files := map[string][]byte{}
|
||||
for k, v := range n.Files {
|
||||
vv := []byte{}
|
||||
|
@@ -39,7 +39,7 @@ func ValidateName(s string) (string, error) {
|
||||
|
||||
func GenerateName(txn *Txn) (string, error) {
|
||||
var name string
|
||||
for i := 0; i < 6; i++ {
|
||||
for i := range 6 {
|
||||
name = namesgenerator.GetRandomName(i)
|
||||
if _, err := txn.NodeGroupByName(name); err != nil {
|
||||
if !os.IsNotExist(errors.Cause(err)) {
|
||||
|
215
tests/bake.go
215
tests/bake.go
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/containerd/continuity/fs/fstest"
|
||||
"github.com/docker/buildx/bake"
|
||||
"github.com/docker/buildx/util/gitutil"
|
||||
"github.com/docker/buildx/util/gitutil/gittestutil"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/frontend/subrequests/lint"
|
||||
"github.com/moby/buildkit/identity"
|
||||
@@ -38,6 +39,8 @@ func bakeCmd(sb integration.Sandbox, opts ...cmdOpt) (string, error) {
|
||||
var bakeTests = []func(t *testing.T, sb integration.Sandbox){
|
||||
testBakePrint,
|
||||
testBakePrintSensitive,
|
||||
testBakePrintOverrideEmpty,
|
||||
testBakePrintKeepEscaped,
|
||||
testBakeLocal,
|
||||
testBakeLocalMulti,
|
||||
testBakeRemote,
|
||||
@@ -286,6 +289,107 @@ RUN echo "Hello ${HELLO}"
|
||||
}
|
||||
}
|
||||
|
||||
func testBakePrintOverrideEmpty(t *testing.T, sb integration.Sandbox) {
|
||||
dockerfile := []byte(`
|
||||
FROM scratch
|
||||
COPY foo /foo
|
||||
`)
|
||||
bakefile := []byte(`
|
||||
target "default" {
|
||||
cache-to = ["type=gha,mode=min,scope=integration-tests"]
|
||||
}
|
||||
`)
|
||||
dir := tmpdir(
|
||||
t,
|
||||
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
|
||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
||||
)
|
||||
|
||||
cmd := buildxCmd(sb, withDir(dir), withArgs("bake", "--print", "--set", "*.cache-to="))
|
||||
stdout := bytes.Buffer{}
|
||||
stderr := bytes.Buffer{}
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
require.NoError(t, cmd.Run(), stdout.String(), stderr.String())
|
||||
|
||||
require.JSONEq(t, `{
|
||||
"group": {
|
||||
"default": {
|
||||
"targets": [
|
||||
"default"
|
||||
]
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"default": {
|
||||
"context": ".",
|
||||
"dockerfile": "Dockerfile"
|
||||
}
|
||||
}
|
||||
}`, stdout.String())
|
||||
}
|
||||
|
||||
func testBakePrintKeepEscaped(t *testing.T, sb integration.Sandbox) {
|
||||
bakefile := []byte(`
|
||||
target "default" {
|
||||
dockerfile-inline = <<EOT
|
||||
ARG VERSION=latest
|
||||
FROM alpine:$${VERSION}
|
||||
EOT
|
||||
args = {
|
||||
VERSION = "3.21"
|
||||
}
|
||||
annotations = [
|
||||
"org.opencontainers.image.authors=$${user}"
|
||||
]
|
||||
labels = {
|
||||
foo = "hello %%{bar}"
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
dir := tmpdir(t, fstest.CreateFile("docker-bake.hcl", bakefile, 0600))
|
||||
cmd := buildxCmd(sb, withDir(dir), withArgs("bake", "--print"))
|
||||
stdout := bytes.Buffer{}
|
||||
stderr := bytes.Buffer{}
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
require.NoError(t, cmd.Run(), stdout.String(), stderr.String())
|
||||
|
||||
require.JSONEq(t, `{
|
||||
"group": {
|
||||
"default": {
|
||||
"targets": [
|
||||
"default"
|
||||
]
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"default": {
|
||||
"annotations": [
|
||||
"org.opencontainers.image.authors=$${user}"
|
||||
],
|
||||
"context": ".",
|
||||
"dockerfile": "Dockerfile",
|
||||
"dockerfile-inline": "ARG VERSION=latest\nFROM alpine:$${VERSION}\n",
|
||||
"args": {
|
||||
"VERSION": "3.21"
|
||||
},
|
||||
"labels": {
|
||||
"foo": "hello %%{bar}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}`, stdout.String())
|
||||
|
||||
// test build with definition from print output
|
||||
dir = tmpdir(t, fstest.CreateFile("docker-bake.json", stdout.Bytes(), 0600))
|
||||
cmd = buildxCmd(sb, withDir(dir), withArgs("bake"))
|
||||
out, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(out))
|
||||
}
|
||||
|
||||
func testBakeLocal(t *testing.T, sb integration.Sandbox) {
|
||||
dockerfile := []byte(`
|
||||
FROM scratch
|
||||
@@ -373,10 +477,10 @@ EOT
|
||||
git, err := gitutil.New(gitutil.WithWorkingDir(dir))
|
||||
require.NoError(t, err)
|
||||
|
||||
gitutil.GitInit(git, t)
|
||||
gitutil.GitAdd(git, t, "docker-bake.hcl", "foo")
|
||||
gitutil.GitCommit(git, t, "initial commit")
|
||||
addr := gitutil.GitServeHTTP(git, t)
|
||||
gittestutil.GitInit(git, t)
|
||||
gittestutil.GitAdd(git, t, "docker-bake.hcl", "foo")
|
||||
gittestutil.GitCommit(git, t, "initial commit")
|
||||
addr := gittestutil.GitServeHTTP(git, t)
|
||||
|
||||
out, err := bakeCmd(sb, withDir(dir), withArgs(addr, "--set", "*.output=type=local,dest="+dirDest))
|
||||
require.NoError(t, err, out)
|
||||
@@ -403,12 +507,12 @@ EOT
|
||||
git, err := gitutil.New(gitutil.WithWorkingDir(dir))
|
||||
require.NoError(t, err)
|
||||
|
||||
gitutil.GitInit(git, t)
|
||||
gitutil.GitAdd(git, t, "docker-bake.hcl", "foo")
|
||||
gitutil.GitCommit(git, t, "initial commit")
|
||||
gittestutil.GitInit(git, t)
|
||||
gittestutil.GitAdd(git, t, "docker-bake.hcl", "foo")
|
||||
gittestutil.GitCommit(git, t, "initial commit")
|
||||
|
||||
token := identity.NewID()
|
||||
addr := gitutil.GitServeHTTP(git, t, gitutil.WithAccessToken(token))
|
||||
addr := gittestutil.GitServeHTTP(git, t, gittestutil.WithAccessToken(token))
|
||||
|
||||
out, err := bakeCmd(sb, withDir(dir),
|
||||
withEnv("BUILDX_BAKE_GIT_AUTH_TOKEN="+token),
|
||||
@@ -450,10 +554,10 @@ EOT
|
||||
git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec))
|
||||
require.NoError(t, err)
|
||||
|
||||
gitutil.GitInit(git, t)
|
||||
gitutil.GitAdd(git, t, "docker-bake.hcl", "bar")
|
||||
gitutil.GitCommit(git, t, "initial commit")
|
||||
addr := gitutil.GitServeHTTP(git, t)
|
||||
gittestutil.GitInit(git, t)
|
||||
gittestutil.GitAdd(git, t, "docker-bake.hcl", "bar")
|
||||
gittestutil.GitCommit(git, t, "initial commit")
|
||||
addr := gittestutil.GitServeHTTP(git, t)
|
||||
|
||||
out, err := bakeCmd(sb, withDir(dirSrc), withArgs(addr, "--file", "cwd://local-docker-bake.hcl", "--set", "*.output=type=local,dest="+dirDest))
|
||||
require.NoError(t, err, out)
|
||||
@@ -519,10 +623,10 @@ EOT
|
||||
git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec))
|
||||
require.NoError(t, err)
|
||||
|
||||
gitutil.GitInit(git, t)
|
||||
gitutil.GitAdd(git, t, "docker-bake.hcl")
|
||||
gitutil.GitCommit(git, t, "initial commit")
|
||||
addr := gitutil.GitServeHTTP(git, t)
|
||||
gittestutil.GitInit(git, t)
|
||||
gittestutil.GitAdd(git, t, "docker-bake.hcl")
|
||||
gittestutil.GitCommit(git, t, "initial commit")
|
||||
addr := gittestutil.GitServeHTTP(git, t)
|
||||
|
||||
out, err := bakeCmd(sb, withDir(dirSrc), withArgs(addr, "--set", "*.output=type=local,dest="+dirDest))
|
||||
require.NoError(t, err, out)
|
||||
@@ -552,17 +656,17 @@ EOT
|
||||
|
||||
gitSpec, err := gitutil.New(gitutil.WithWorkingDir(dirSpec))
|
||||
require.NoError(t, err)
|
||||
gitutil.GitInit(gitSpec, t)
|
||||
gitutil.GitAdd(gitSpec, t, "docker-bake.hcl")
|
||||
gitutil.GitCommit(gitSpec, t, "initial commit")
|
||||
addrSpec := gitutil.GitServeHTTP(gitSpec, t)
|
||||
gittestutil.GitInit(gitSpec, t)
|
||||
gittestutil.GitAdd(gitSpec, t, "docker-bake.hcl")
|
||||
gittestutil.GitCommit(gitSpec, t, "initial commit")
|
||||
addrSpec := gittestutil.GitServeHTTP(gitSpec, t)
|
||||
|
||||
gitSrc, err := gitutil.New(gitutil.WithWorkingDir(dirSrc))
|
||||
require.NoError(t, err)
|
||||
gitutil.GitInit(gitSrc, t)
|
||||
gitutil.GitAdd(gitSrc, t, "foo")
|
||||
gitutil.GitCommit(gitSrc, t, "initial commit")
|
||||
addrSrc := gitutil.GitServeHTTP(gitSrc, t)
|
||||
gittestutil.GitInit(gitSrc, t)
|
||||
gittestutil.GitAdd(gitSrc, t, "foo")
|
||||
gittestutil.GitCommit(gitSrc, t, "initial commit")
|
||||
addrSrc := gittestutil.GitServeHTTP(gitSrc, t)
|
||||
|
||||
out, err := bakeCmd(sb, withDir("/tmp"), withArgs(addrSpec, addrSrc, "--set", "*.output=type=local,dest="+dirDest))
|
||||
require.NoError(t, err, out)
|
||||
@@ -593,10 +697,10 @@ COPY super-cool.txt /
|
||||
|
||||
git, err := gitutil.New(gitutil.WithWorkingDir(dir))
|
||||
require.NoError(t, err)
|
||||
gitutil.GitInit(git, t)
|
||||
gitutil.GitAdd(git, t, "docker-bake.hcl", "bar")
|
||||
gitutil.GitCommit(git, t, "initial commit")
|
||||
addr := gitutil.GitServeHTTP(git, t)
|
||||
gittestutil.GitInit(git, t)
|
||||
gittestutil.GitAdd(git, t, "docker-bake.hcl", "bar")
|
||||
gittestutil.GitCommit(git, t, "initial commit")
|
||||
addr := gittestutil.GitServeHTTP(git, t)
|
||||
|
||||
out, err := bakeCmd(sb, withDir("/tmp"), withArgs(addr, "--set", "*.output=type=local,dest="+dirDest))
|
||||
require.NoError(t, err, out)
|
||||
@@ -634,10 +738,10 @@ EOT
|
||||
git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec))
|
||||
require.NoError(t, err)
|
||||
|
||||
gitutil.GitInit(git, t)
|
||||
gitutil.GitAdd(git, t, "docker-bake.hcl")
|
||||
gitutil.GitCommit(git, t, "initial commit")
|
||||
addr := gitutil.GitServeHTTP(git, t)
|
||||
gittestutil.GitInit(git, t)
|
||||
gittestutil.GitAdd(git, t, "docker-bake.hcl")
|
||||
gittestutil.GitCommit(git, t, "initial commit")
|
||||
addr := gittestutil.GitServeHTTP(git, t)
|
||||
|
||||
out, err := bakeCmd(
|
||||
sb,
|
||||
@@ -682,10 +786,10 @@ EOT
|
||||
git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec))
|
||||
require.NoError(t, err)
|
||||
|
||||
gitutil.GitInit(git, t)
|
||||
gitutil.GitAdd(git, t, "docker-bake.hcl")
|
||||
gitutil.GitCommit(git, t, "initial commit")
|
||||
addr := gitutil.GitServeHTTP(git, t)
|
||||
gittestutil.GitInit(git, t)
|
||||
gittestutil.GitAdd(git, t, "docker-bake.hcl")
|
||||
gittestutil.GitCommit(git, t, "initial commit")
|
||||
addr := gittestutil.GitServeHTTP(git, t)
|
||||
|
||||
out, err := bakeCmd(
|
||||
sb,
|
||||
@@ -738,13 +842,13 @@ COPY foo /foo
|
||||
git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec))
|
||||
require.NoError(t, err)
|
||||
|
||||
gitutil.GitInit(git, t)
|
||||
gitutil.GitAdd(git, t, "docker-bake.hcl")
|
||||
gitutil.GitAdd(git, t, "Dockerfile")
|
||||
gitutil.GitAdd(git, t, "foo")
|
||||
gitutil.GitAdd(git, t, "bar")
|
||||
gitutil.GitCommit(git, t, "initial commit")
|
||||
addr := gitutil.GitServeHTTP(git, t)
|
||||
gittestutil.GitInit(git, t)
|
||||
gittestutil.GitAdd(git, t, "docker-bake.hcl")
|
||||
gittestutil.GitAdd(git, t, "Dockerfile")
|
||||
gittestutil.GitAdd(git, t, "foo")
|
||||
gittestutil.GitAdd(git, t, "bar")
|
||||
gittestutil.GitCommit(git, t, "initial commit")
|
||||
addr := gittestutil.GitServeHTTP(git, t)
|
||||
|
||||
out, err := bakeCmd(
|
||||
sb,
|
||||
@@ -790,10 +894,10 @@ COPY foo /foo
|
||||
git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec))
|
||||
require.NoError(t, err)
|
||||
|
||||
gitutil.GitInit(git, t)
|
||||
gitutil.GitAdd(git, t, "docker-bake.hcl")
|
||||
gitutil.GitCommit(git, t, "initial commit")
|
||||
addr := gitutil.GitServeHTTP(git, t)
|
||||
gittestutil.GitInit(git, t)
|
||||
gittestutil.GitAdd(git, t, "docker-bake.hcl")
|
||||
gittestutil.GitCommit(git, t, "initial commit")
|
||||
addr := gittestutil.GitServeHTTP(git, t)
|
||||
|
||||
out, err := bakeCmd(
|
||||
sb,
|
||||
@@ -871,6 +975,7 @@ target "default" {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testBakeSetNonExistingOutsideNoParallel(t *testing.T, sb integration.Sandbox) {
|
||||
for _, ent := range []bool{true, false} {
|
||||
t.Run(fmt.Sprintf("ent=%v", ent), func(t *testing.T) {
|
||||
@@ -973,11 +1078,11 @@ FROM scratch
|
||||
COPY foo /foo
|
||||
`)
|
||||
destDir := t.TempDir()
|
||||
bakefile := []byte(fmt.Sprintf(`
|
||||
bakefile := fmt.Appendf(nil, `
|
||||
target "default" {
|
||||
output = ["type=local,dest=%s/not/exists"]
|
||||
}
|
||||
`, destDir))
|
||||
`, destDir)
|
||||
dir := tmpdir(
|
||||
t,
|
||||
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
|
||||
@@ -1007,11 +1112,11 @@ FROM scratch
|
||||
COPY foo /foo
|
||||
`)
|
||||
destDir := t.TempDir()
|
||||
bakefile := []byte(fmt.Sprintf(`
|
||||
bakefile := fmt.Appendf(nil, `
|
||||
target "default" {
|
||||
output = ["type=local,dest=%s"]
|
||||
}
|
||||
`, destDir))
|
||||
`, destDir)
|
||||
dir := tmpdir(
|
||||
t,
|
||||
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
|
||||
@@ -1108,11 +1213,11 @@ COPY Dockerfile /foo
|
||||
keyDir := t.TempDir()
|
||||
err := writeTempPrivateKey(filepath.Join(keyDir, "id_rsa"))
|
||||
require.NoError(t, err)
|
||||
bakefile := []byte(fmt.Sprintf(`
|
||||
bakefile := fmt.Appendf(nil, `
|
||||
target "default" {
|
||||
ssh = ["key=%s"]
|
||||
}
|
||||
`, filepath.Join(keyDir, "id_rsa")))
|
||||
`, filepath.Join(keyDir, "id_rsa"))
|
||||
dir := tmpdir(
|
||||
t,
|
||||
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
|
||||
@@ -1271,8 +1376,8 @@ target "default" {
|
||||
|
||||
type mdT struct {
|
||||
Default struct {
|
||||
BuildRef string `json:"buildx.build.ref"`
|
||||
BuildProvenance map[string]interface{} `json:"buildx.build.provenance"`
|
||||
BuildRef string `json:"buildx.build.ref"`
|
||||
BuildProvenance map[string]any `json:"buildx.build.provenance"`
|
||||
} `json:"default"`
|
||||
}
|
||||
var md mdT
|
||||
|
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/docker/buildx/localstate"
|
||||
"github.com/docker/buildx/util/confutil"
|
||||
"github.com/docker/buildx/util/gitutil"
|
||||
"github.com/docker/buildx/util/gitutil/gittestutil"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/frontend/subrequests/lint"
|
||||
"github.com/moby/buildkit/frontend/subrequests/outline"
|
||||
@@ -126,10 +127,10 @@ COPY foo /foo
|
||||
git, err := gitutil.New(gitutil.WithWorkingDir(dir))
|
||||
require.NoError(t, err)
|
||||
|
||||
gitutil.GitInit(git, t)
|
||||
gitutil.GitAdd(git, t, "Dockerfile", "foo")
|
||||
gitutil.GitCommit(git, t, "initial commit")
|
||||
addr := gitutil.GitServeHTTP(git, t)
|
||||
gittestutil.GitInit(git, t)
|
||||
gittestutil.GitAdd(git, t, "Dockerfile", "foo")
|
||||
gittestutil.GitCommit(git, t, "initial commit")
|
||||
addr := gittestutil.GitServeHTTP(git, t)
|
||||
|
||||
out, err := buildCmd(sb, withDir(dir), withArgs("--output=type=local,dest="+dirDest, addr))
|
||||
require.NoError(t, err, out)
|
||||
@@ -238,10 +239,10 @@ COPY foo /foo
|
||||
git, err := gitutil.New(gitutil.WithWorkingDir(dir))
|
||||
require.NoError(t, err)
|
||||
|
||||
gitutil.GitInit(git, t)
|
||||
gitutil.GitAdd(git, t, "build.Dockerfile", "foo")
|
||||
gitutil.GitCommit(git, t, "initial commit")
|
||||
addr := gitutil.GitServeHTTP(git, t)
|
||||
gittestutil.GitInit(git, t)
|
||||
gittestutil.GitAdd(git, t, "build.Dockerfile", "foo")
|
||||
gittestutil.GitCommit(git, t, "initial commit")
|
||||
addr := gittestutil.GitServeHTTP(git, t)
|
||||
|
||||
out, err := buildCmd(sb, withDir(dir), withArgs(
|
||||
"-f", "build.Dockerfile",
|
||||
@@ -804,8 +805,8 @@ func buildMetadataProvenance(t *testing.T, sb integration.Sandbox, metadataMode
|
||||
require.NoError(t, err)
|
||||
|
||||
type mdT struct {
|
||||
BuildRef string `json:"buildx.build.ref"`
|
||||
BuildProvenance map[string]interface{} `json:"buildx.build.provenance"`
|
||||
BuildRef string `json:"buildx.build.ref"`
|
||||
BuildProvenance map[string]any `json:"buildx.build.provenance"`
|
||||
}
|
||||
var md mdT
|
||||
err = json.Unmarshal(dt, &md)
|
||||
|
@@ -50,7 +50,7 @@ func withDir(dir string) cmdOpt {
|
||||
|
||||
func buildxCmd(sb integration.Sandbox, opts ...cmdOpt) *exec.Cmd {
|
||||
cmd := exec.Command("buildx")
|
||||
cmd.Env = append([]string{}, os.Environ()...)
|
||||
cmd.Env = os.Environ()
|
||||
for _, opt := range opts {
|
||||
opt(cmd)
|
||||
}
|
||||
@@ -77,7 +77,7 @@ func buildxCmd(sb integration.Sandbox, opts ...cmdOpt) *exec.Cmd {
|
||||
|
||||
func dockerCmd(sb integration.Sandbox, opts ...cmdOpt) *exec.Cmd {
|
||||
cmd := exec.Command("docker")
|
||||
cmd.Env = append([]string{}, os.Environ()...)
|
||||
cmd.Env = os.Environ()
|
||||
for _, opt := range opts {
|
||||
opt(cmd)
|
||||
}
|
||||
@@ -214,7 +214,7 @@ func skipNoCompatBuildKit(t *testing.T, sb integration.Sandbox, constraint strin
|
||||
}
|
||||
}
|
||||
|
||||
func ptrstr(s interface{}) *string {
|
||||
func ptrstr(s any) *string {
|
||||
var n *string
|
||||
if reflect.ValueOf(s).Kind() == reflect.String {
|
||||
ss := s.(string)
|
||||
|
@@ -45,7 +45,7 @@ func testRmMulti(t *testing.T, sb integration.Sandbox) {
|
||||
}
|
||||
|
||||
var builderNames []string
|
||||
for i := 0; i < 3; i++ {
|
||||
for range 3 {
|
||||
out, err := createCmd(sb, withArgs("--driver", "docker-container"))
|
||||
require.NoError(t, err, out)
|
||||
builderName := strings.TrimSpace(out)
|
||||
|
@@ -2,6 +2,7 @@ package workers
|
||||
|
||||
import (
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/moby/buildkit/util/testutil/integration"
|
||||
@@ -49,23 +50,14 @@ func (s *backend) ExtraEnv() []string {
|
||||
|
||||
func (s backend) Supports(feature string) bool {
|
||||
if enabledFeatures := os.Getenv("BUILDKIT_TEST_ENABLE_FEATURES"); enabledFeatures != "" {
|
||||
for _, enabledFeature := range strings.Split(enabledFeatures, ",") {
|
||||
if feature == enabledFeature {
|
||||
return true
|
||||
}
|
||||
if slices.Contains(strings.Split(enabledFeatures, ","), feature) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if disabledFeatures := os.Getenv("BUILDKIT_TEST_DISABLE_FEATURES"); disabledFeatures != "" {
|
||||
for _, disabledFeature := range strings.Split(disabledFeatures, ",") {
|
||||
if feature == disabledFeature {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, unsupportedFeature := range s.unsupportedFeatures {
|
||||
if feature == unsupportedFeature {
|
||||
if slices.Contains(strings.Split(disabledFeatures, ","), feature) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
return !slices.Contains(s.unsupportedFeatures, feature)
|
||||
}
|
||||
|
@@ -90,7 +90,7 @@ func (a *Attest) ToPB() *controllerapi.Attest {
|
||||
}
|
||||
|
||||
func (a *Attest) MarshalJSON() ([]byte, error) {
|
||||
m := make(map[string]interface{}, len(a.Attrs)+2)
|
||||
m := make(map[string]any, len(a.Attrs)+2)
|
||||
for k, v := range a.Attrs {
|
||||
m[k] = v
|
||||
}
|
||||
@@ -102,7 +102,7 @@ func (a *Attest) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (a *Attest) UnmarshalJSON(data []byte) error {
|
||||
var m map[string]interface{}
|
||||
var m map[string]any
|
||||
if err := json.Unmarshal(data, &m); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -148,9 +148,8 @@ func (a *Attest) UnmarshalText(text []byte) error {
|
||||
if !ok {
|
||||
return errors.Errorf("invalid value %s", field)
|
||||
}
|
||||
key = strings.TrimSpace(strings.ToLower(key))
|
||||
|
||||
switch key {
|
||||
switch strings.TrimSpace(strings.ToLower(key)) {
|
||||
case "type":
|
||||
a.Type = value
|
||||
case "disabled":
|
||||
@@ -203,7 +202,7 @@ func ParseAttests(in []string) ([]*controllerapi.Attest, error) {
|
||||
func ConvertAttests(in []*Attest) ([]*controllerapi.Attest, error) {
|
||||
out := make([]*controllerapi.Attest, 0, len(in))
|
||||
|
||||
// Check for dupplicate attestations while we convert them
|
||||
// Check for duplicate attestations while we convert them
|
||||
// to the controller API.
|
||||
found := map[string]struct{}{}
|
||||
for _, attest := range in {
|
||||
|
@@ -13,16 +13,21 @@ func TestAttests(t *testing.T) {
|
||||
attests := Attests{
|
||||
{Type: "provenance", Attrs: map[string]string{"mode": "max"}},
|
||||
{Type: "sbom", Disabled: true},
|
||||
{Type: "sbom", Attrs: map[string]string{
|
||||
"generator": "scanner",
|
||||
"ENV1": `"foo,bar"`,
|
||||
"Env2": "hello",
|
||||
}},
|
||||
}
|
||||
|
||||
expected := `[{"type":"provenance","mode":"max"},{"type":"sbom","disabled":true}]`
|
||||
expected := `[{"type":"provenance","mode":"max"},{"type":"sbom","disabled":true},{"ENV1":"\"foo,bar\"","Env2":"hello","generator":"scanner","type":"sbom"}]`
|
||||
actual, err := json.Marshal(attests)
|
||||
require.NoError(t, err)
|
||||
require.JSONEq(t, expected, string(actual))
|
||||
})
|
||||
|
||||
t.Run("UnmarshalJSON", func(t *testing.T) {
|
||||
in := `[{"type":"provenance","mode":"max"},{"type":"sbom","disabled":true}]`
|
||||
in := `[{"type":"provenance","mode":"max"},{"type":"sbom","disabled":true},{"ENV1":"\"foo,bar\"","Env2":"hello","generator":"scanner","type":"sbom"}]`
|
||||
|
||||
var actual Attests
|
||||
err := json.Unmarshal([]byte(in), &actual)
|
||||
@@ -31,6 +36,11 @@ func TestAttests(t *testing.T) {
|
||||
expected := Attests{
|
||||
{Type: "provenance", Attrs: map[string]string{"mode": "max"}},
|
||||
{Type: "sbom", Disabled: true, Attrs: map[string]string{}},
|
||||
{Type: "sbom", Disabled: false, Attrs: map[string]string{
|
||||
"generator": "scanner",
|
||||
"ENV1": `"foo,bar"`,
|
||||
"Env2": "hello",
|
||||
}},
|
||||
}
|
||||
require.Equal(t, expected, actual)
|
||||
})
|
||||
@@ -41,7 +51,14 @@ func TestAttests(t *testing.T) {
|
||||
"type": cty.StringVal("provenance"),
|
||||
"mode": cty.StringVal("max"),
|
||||
}),
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"type": cty.StringVal("sbom"),
|
||||
"generator": cty.StringVal("scan"),
|
||||
"ENV1": cty.StringVal(`foo,bar`),
|
||||
"Env2": cty.StringVal(`hello`),
|
||||
}),
|
||||
cty.StringVal("type=sbom,disabled=true"),
|
||||
cty.StringVal(`type=sbom,generator=scan,"FOO=bar,baz",Hello=World`),
|
||||
})
|
||||
|
||||
var actual Attests
|
||||
@@ -50,7 +67,17 @@ func TestAttests(t *testing.T) {
|
||||
|
||||
expected := Attests{
|
||||
{Type: "provenance", Attrs: map[string]string{"mode": "max"}},
|
||||
{Type: "sbom", Attrs: map[string]string{
|
||||
"generator": "scan",
|
||||
"ENV1": "foo,bar",
|
||||
"Env2": "hello",
|
||||
}},
|
||||
{Type: "sbom", Disabled: true, Attrs: map[string]string{}},
|
||||
{Type: "sbom", Attrs: map[string]string{
|
||||
"generator": "scan",
|
||||
"FOO": "bar,baz",
|
||||
"Hello": "World",
|
||||
}},
|
||||
}
|
||||
require.Equal(t, expected, actual)
|
||||
})
|
||||
@@ -59,6 +86,11 @@ func TestAttests(t *testing.T) {
|
||||
attests := Attests{
|
||||
{Type: "provenance", Attrs: map[string]string{"mode": "max"}},
|
||||
{Type: "sbom", Disabled: true},
|
||||
{Type: "sbom", Attrs: map[string]string{
|
||||
"generator": "scan",
|
||||
"ENV1": `"foo,bar"`,
|
||||
"Env2": "hello",
|
||||
}},
|
||||
}
|
||||
|
||||
actual := attests.ToCtyValue()
|
||||
@@ -71,6 +103,12 @@ func TestAttests(t *testing.T) {
|
||||
"type": cty.StringVal("sbom"),
|
||||
"disabled": cty.StringVal("true"),
|
||||
}),
|
||||
cty.MapVal(map[string]cty.Value{
|
||||
"type": cty.StringVal("sbom"),
|
||||
"generator": cty.StringVal("scan"),
|
||||
"ENV1": cty.StringVal(`"foo,bar"`),
|
||||
"Env2": cty.StringVal("hello"),
|
||||
}),
|
||||
})
|
||||
|
||||
result := actual.Equals(expected)
|
||||
|
@@ -150,7 +150,7 @@ func (e *CacheOptionsEntry) UnmarshalText(text []byte) error {
|
||||
return e.validate(text)
|
||||
}
|
||||
|
||||
func (e *CacheOptionsEntry) validate(gv interface{}) error {
|
||||
func (e *CacheOptionsEntry) validate(gv any) error {
|
||||
if e.Type == "" {
|
||||
var text []byte
|
||||
switch gv := gv.(type) {
|
||||
@@ -175,6 +175,10 @@ func ParseCacheEntry(in []string) (CacheOptions, error) {
|
||||
|
||||
opts := make(CacheOptions, 0, len(in))
|
||||
for _, in := range in {
|
||||
if in == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.Contains(in, "=") {
|
||||
// This is ref only format. Each field in the CSV is its own entry.
|
||||
fields, err := csvvalue.Fields(in, nil)
|
||||
@@ -207,6 +211,7 @@ func addGithubToken(ci *controllerapi.CacheOptionsEntry) {
|
||||
}
|
||||
version, ok := ci.Attrs["version"]
|
||||
if !ok {
|
||||
// https://github.com/actions/toolkit/blob/2b08dc18f261b9fdd978b70279b85cbef81af8bc/packages/cache/src/internal/config.ts#L19
|
||||
if v, ok := os.LookupEnv("ACTIONS_CACHE_SERVICE_V2"); ok {
|
||||
if b, err := strconv.ParseBool(v); err == nil && b {
|
||||
version = "2"
|
||||
@@ -218,15 +223,18 @@ func addGithubToken(ci *controllerapi.CacheOptionsEntry) {
|
||||
ci.Attrs["token"] = v
|
||||
}
|
||||
}
|
||||
if _, ok := ci.Attrs["url_v2"]; !ok && version == "2" {
|
||||
// https://github.com/actions/toolkit/blob/2b08dc18f261b9fdd978b70279b85cbef81af8bc/packages/cache/src/internal/config.ts#L34-L35
|
||||
if v, ok := os.LookupEnv("ACTIONS_RESULTS_URL"); ok {
|
||||
ci.Attrs["url_v2"] = v
|
||||
}
|
||||
}
|
||||
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 {
|
||||
ci.Attrs["url"] = v
|
||||
}
|
||||
// https://github.com/actions/toolkit/blob/2b08dc18f261b9fdd978b70279b85cbef81af8bc/packages/cache/src/internal/config.ts#L28-L33
|
||||
if v, ok := os.LookupEnv("ACTIONS_CACHE_URL"); ok {
|
||||
ci.Attrs["url"] = v
|
||||
} else if v, ok := os.LookupEnv("ACTIONS_RESULTS_URL"); ok {
|
||||
ci.Attrs["url"] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -266,5 +274,5 @@ func isActive(pb *controllerapi.CacheOptionsEntry) bool {
|
||||
if pb.Type != "gha" {
|
||||
return true
|
||||
}
|
||||
return pb.Attrs["token"] != "" && pb.Attrs["url"] != ""
|
||||
return pb.Attrs["token"] != "" && (pb.Attrs["url"] != "" || pb.Attrs["url_v2"] != "")
|
||||
}
|
||||
|
@@ -1,19 +1,20 @@
|
||||
package buildflags
|
||||
|
||||
import "github.com/moby/buildkit/util/entitlements"
|
||||
import (
|
||||
"github.com/moby/buildkit/util/entitlements"
|
||||
)
|
||||
|
||||
func ParseEntitlements(in []string) ([]entitlements.Entitlement, error) {
|
||||
out := make([]entitlements.Entitlement, 0, len(in))
|
||||
func ParseEntitlements(in []string) ([]string, error) {
|
||||
out := make([]string, 0, len(in))
|
||||
for _, v := range in {
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
e, err := entitlements.Parse(v)
|
||||
if err != nil {
|
||||
if _, _, err := entitlements.Parse(v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, e)
|
||||
out = append(out, v)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package buildflags
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
"regexp"
|
||||
@@ -259,9 +260,18 @@ func (w *csvBuilder) Write(key, value string) {
|
||||
if w.sb.Len() > 0 {
|
||||
w.sb.WriteByte(',')
|
||||
}
|
||||
w.sb.WriteString(key)
|
||||
w.sb.WriteByte('=')
|
||||
w.sb.WriteString(value)
|
||||
|
||||
pair := key + "=" + value
|
||||
if strings.ContainsRune(pair, ',') || strings.ContainsRune(pair, '"') {
|
||||
var attr strings.Builder
|
||||
writer := csv.NewWriter(&attr)
|
||||
writer.Write([]string{pair})
|
||||
writer.Flush()
|
||||
// Strips the extra newline added by the csv writer
|
||||
pair = strings.TrimSpace(attr.String())
|
||||
}
|
||||
|
||||
w.sb.WriteString(pair)
|
||||
}
|
||||
|
||||
func (w *csvBuilder) WriteAttributes(attrs map[string]string) {
|
||||
|
@@ -27,7 +27,7 @@ func (s Secrets) Normalize() Secrets {
|
||||
if len(s) == 0 {
|
||||
return nil
|
||||
}
|
||||
return removeDupes(s)
|
||||
return removeSecretDupes(s)
|
||||
}
|
||||
|
||||
func (s Secrets) ToPB() []*controllerapi.Secret {
|
||||
@@ -155,3 +155,17 @@ func parseSecret(value string) (*controllerapi.Secret, error) {
|
||||
}
|
||||
return s.ToPB(), nil
|
||||
}
|
||||
|
||||
func removeSecretDupes(s []*Secret) []*Secret {
|
||||
var res []*Secret
|
||||
m := map[string]int{}
|
||||
for _, sec := range s {
|
||||
if i, ok := m[sec.ID]; ok {
|
||||
res[i] = sec
|
||||
} else {
|
||||
m[sec.ID] = len(res)
|
||||
res = append(res, sec)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
@@ -81,4 +81,17 @@ func TestSecrets(t *testing.T) {
|
||||
result := actual.Equals(expected)
|
||||
require.True(t, result.True())
|
||||
})
|
||||
|
||||
t.Run("RemoveDupes", func(t *testing.T) {
|
||||
secrets := Secrets{
|
||||
{ID: "mysecret", Env: "FOO"},
|
||||
{ID: "mysecret", Env: "BAR"},
|
||||
{ID: "mysecret2", Env: "BAZ"},
|
||||
}.Normalize()
|
||||
|
||||
expected := `[{"id":"mysecret","env":"BAR"},{"id":"mysecret2","env":"BAZ"}]`
|
||||
actual, err := json.Marshal(secrets)
|
||||
require.NoError(t, err)
|
||||
require.JSONEq(t, expected, string(actual))
|
||||
})
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ func (s SSHKeys) Normalize() SSHKeys {
|
||||
if len(s) == 0 {
|
||||
return nil
|
||||
}
|
||||
return removeDupes(s)
|
||||
return removeSSHDupes(s)
|
||||
}
|
||||
|
||||
func (s SSHKeys) ToPB() []*controllerapi.SSH {
|
||||
@@ -131,3 +131,17 @@ func IsGitSSH(repo string) bool {
|
||||
}
|
||||
return url.Scheme == gitutil.SSHProtocol
|
||||
}
|
||||
|
||||
func removeSSHDupes(s []*SSH) []*SSH {
|
||||
var res []*SSH
|
||||
m := map[string]int{}
|
||||
for _, ssh := range s {
|
||||
if i, ok := m[ssh.ID]; ok {
|
||||
res[i] = ssh
|
||||
} else {
|
||||
m[ssh.ID] = len(res)
|
||||
res = append(res, ssh)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
@@ -82,4 +82,17 @@ func TestSSHKeys(t *testing.T) {
|
||||
result := actual.Equals(expected)
|
||||
require.True(t, result.True())
|
||||
})
|
||||
|
||||
t.Run("RemoveDupes", func(t *testing.T) {
|
||||
sshkeys := SSHKeys{
|
||||
{ID: "default"},
|
||||
{ID: "key", Paths: []string{"path/to/foo"}},
|
||||
{ID: "key", Paths: []string{"path/to/bar"}},
|
||||
}.Normalize()
|
||||
|
||||
expected := `[{"id":"default"},{"id":"key","paths":["path/to/bar"]}]`
|
||||
actual, err := json.Marshal(sshkeys)
|
||||
require.NoError(t, err)
|
||||
require.JSONEq(t, expected, string(actual))
|
||||
})
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ func removeDupes[E comparable[E]](s []E) []E {
|
||||
return s
|
||||
}
|
||||
|
||||
func getAndDelete(m map[string]cty.Value, attr string, gv interface{}) error {
|
||||
func getAndDelete(m map[string]cty.Value, attr string, gv any) error {
|
||||
if v, ok := m[attr]; ok && v.IsKnown() {
|
||||
delete(m, attr)
|
||||
return gocty.FromCtyValue(v, gv)
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/atomicwriter"
|
||||
"github.com/moby/buildkit/cmd/buildkitd/config"
|
||||
"github.com/pelletier/go-toml"
|
||||
"github.com/pkg/errors"
|
||||
@@ -106,7 +106,7 @@ func (c *Config) MkdirAll(dir string, perm os.FileMode) error {
|
||||
// AtomicWriteFile writes data to a file within the config dir atomically
|
||||
func (c *Config) AtomicWriteFile(filename string, data []byte, perm os.FileMode) error {
|
||||
f := filepath.Join(c.dir, filename)
|
||||
if err := ioutils.AtomicWriteFile(f, data, perm); err != nil {
|
||||
if err := atomicwriter.WriteFile(f, data, perm); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.chowner == nil {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user