mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-08-14 15:55:54 +08:00
Compare commits
263 Commits
v0.11
...
v0.12.0-rc
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d537b9e418 | ||
![]() |
616fb3e55c | ||
![]() |
80aa28f75c | ||
![]() |
0408f3ac45 | ||
![]() |
7683ef9137 | ||
![]() |
3f423468df | ||
![]() |
ff8bca206b | ||
![]() |
08a70ecdcc | ||
![]() |
d83da63320 | ||
![]() |
639e0bc5ed | ||
![]() |
d0a9a81e2e | ||
![]() |
de1a560f07 | ||
![]() |
e168fd826c | ||
![]() |
2f1b7a0131 | ||
![]() |
f3871b158f | ||
![]() |
deb9dbe9bb | ||
![]() |
6f71ea8904 | ||
![]() |
e437f7ba04 | ||
![]() |
abfc04f621 | ||
![]() |
612dfdd813 | ||
![]() |
ee19ce5ef2 | ||
![]() |
23c2498dee | ||
![]() |
390eedc50b | ||
![]() |
adc839aa40 | ||
![]() |
7838ade9f3 | ||
![]() |
c043c9229e | ||
![]() |
05a0fdf744 | ||
![]() |
dfb557b34f | ||
![]() |
d0d8bfbca4 | ||
![]() |
21e4eb89b2 | ||
![]() |
14834e6085 | ||
![]() |
267e30a19c | ||
![]() |
be4fd7110d | ||
![]() |
24668122d9 | ||
![]() |
31d021a9ca | ||
![]() |
7497e6481e | ||
![]() |
de9d253f45 | ||
![]() |
f4f511201b | ||
![]() |
beca8b6adf | ||
![]() |
457dc402d3 | ||
![]() |
34b9a629a0 | ||
![]() |
ad674e2666 | ||
![]() |
503d483731 | ||
![]() |
6e5aefbb98 | ||
![]() |
7d2c9d5ef5 | ||
![]() |
1734abbb76 | ||
![]() |
b06a55cf53 | ||
![]() |
38137b29dd | ||
![]() |
fc7144f61d | ||
![]() |
ac93a7fbfb | ||
![]() |
48f9b86b9a | ||
![]() |
6c32a8c4c1 | ||
![]() |
7a08248c4e | ||
![]() |
05af608774 | ||
![]() |
511e41386f | ||
![]() |
fd251d2a7b | ||
![]() |
5836c24e7d | ||
![]() |
c8f8a106ed | ||
![]() |
198764f116 | ||
![]() |
0dd89f6029 | ||
![]() |
8da8ee2aea | ||
![]() |
6db8569f09 | ||
![]() |
5a0e4c1023 | ||
![]() |
ded91da575 | ||
![]() |
508b2ef0c6 | ||
![]() |
05b8821625 | ||
![]() |
01245e72ab | ||
![]() |
22e9e3342b | ||
![]() |
0e3911147a | ||
![]() |
2aa6d52b06 | ||
![]() |
561a4330cf | ||
![]() |
7b4bc4f00a | ||
![]() |
a012e0043b | ||
![]() |
2c2294fa43 | ||
![]() |
197824c6f2 | ||
![]() |
22e61ef06f | ||
![]() |
159eac42f3 | ||
![]() |
6c77b76b7b | ||
![]() |
130e9fe093 | ||
![]() |
e9fb769c60 | ||
![]() |
3dcb03452c | ||
![]() |
9b7d30c9a0 | ||
![]() |
2134a1e104 | ||
![]() |
cc6957d1cc | ||
![]() |
0878d5b22b | ||
![]() |
c8002e58a4 | ||
![]() |
cfcd1d9420 | ||
![]() |
e6756d951a | ||
![]() |
b9aad03e7a | ||
![]() |
0bd6f3c7f5 | ||
![]() |
e2ebab5f26 | ||
![]() |
e018f8b6fb | ||
![]() |
03bedfb3c3 | ||
![]() |
bdaaca40a2 | ||
![]() |
bc021c89a8 | ||
![]() |
798402314c | ||
![]() |
7cfb440136 | ||
![]() |
80358842c4 | ||
![]() |
77aedb751e | ||
![]() |
739ec964db | ||
![]() |
320a3109f3 | ||
![]() |
2c986bc184 | ||
![]() |
6c31f43cc9 | ||
![]() |
7b049b99c5 | ||
![]() |
bf5a70023c | ||
![]() |
8d001e338f | ||
![]() |
73ea0826ca | ||
![]() |
66e6dab26b | ||
![]() |
0138f2a00f | ||
![]() |
a59058e8a5 | ||
![]() |
f6b7a3c522 | ||
![]() |
8fe2070d10 | ||
![]() |
54bb799d15 | ||
![]() |
957044825f | ||
![]() |
42a0f3d504 | ||
![]() |
84ad208985 | ||
![]() |
3631dc17c9 | ||
![]() |
bafdc63b8c | ||
![]() |
51c94cd2a6 | ||
![]() |
31d88398bc | ||
![]() |
fbf6594758 | ||
![]() |
f54a67de6d | ||
![]() |
f35b2b7cab | ||
![]() |
29ba5ecef6 | ||
![]() |
fb50d82fd8 | ||
![]() |
87e8e4b847 | ||
![]() |
a71a24c0f4 | ||
![]() |
76119b0f61 | ||
![]() |
7843b5f417 | ||
![]() |
da6662975f | ||
![]() |
de4dbb7d00 | ||
![]() |
3bd4bca994 | ||
![]() |
296832c90e | ||
![]() |
56d55a4137 | ||
![]() |
626e6f8fa3 | ||
![]() |
5941bf0494 | ||
![]() |
29a496cdab | ||
![]() |
a43d9a67c7 | ||
![]() |
c47eb3bf5a | ||
![]() |
a97e1641a4 | ||
![]() |
86ae8ea854 | ||
![]() |
d37d483097 | ||
![]() |
4e96faa201 | ||
![]() |
e5419ef6d7 | ||
![]() |
14747a490a | ||
![]() |
e5cee892ed | ||
![]() |
ef4b984df4 | ||
![]() |
a8f402e28d | ||
![]() |
2eba99b40b | ||
![]() |
7686fa1f16 | ||
![]() |
51b9bab245 | ||
![]() |
6b5758f4cd | ||
![]() |
bd375a14a8 | ||
![]() |
b01693f63e | ||
![]() |
4a059d5144 | ||
![]() |
f3775c0046 | ||
![]() |
50fbdd86f9 | ||
![]() |
1f61de0fcc | ||
![]() |
e206c585bb | ||
![]() |
5e46d8057d | ||
![]() |
4e7709e54c | ||
![]() |
5ed8f1b7d9 | ||
![]() |
1d12c1f5b3 | ||
![]() |
3ef93e081c | ||
![]() |
18894a8e3a | ||
![]() |
13ec635988 | ||
![]() |
f804b8fa4b | ||
![]() |
21a55ff9a1 | ||
![]() |
dd350284df | ||
![]() |
c010d3de8d | ||
![]() |
d11dbbf9f7 | ||
![]() |
75cdceb9f1 | ||
![]() |
10ff93f190 | ||
![]() |
bf00185809 | ||
![]() |
90f03e57c2 | ||
![]() |
a59fd3ebfe | ||
![]() |
3eb490153d | ||
![]() |
d957d8b987 | ||
![]() |
5a1f252bd9 | ||
![]() |
ab4585f38c | ||
![]() |
3003045c0b | ||
![]() |
a6f3f290b4 | ||
![]() |
27d072a099 | ||
![]() |
8e3df1943c | ||
![]() |
8c54de66ce | ||
![]() |
06b9ac2dc4 | ||
![]() |
b8739d7441 | ||
![]() |
23fe02993b | ||
![]() |
1d177f00d2 | ||
![]() |
ceaba7011f | ||
![]() |
9c06f383ba | ||
![]() |
e11c5e3e96 | ||
![]() |
f5719f3017 | ||
![]() |
163babdca7 | ||
![]() |
094d1aded8 | ||
![]() |
05ef20b434 | ||
![]() |
cc718b3444 | ||
![]() |
e98e8f6ac9 | ||
![]() |
36541ed9d5 | ||
![]() |
418ea82d3a | ||
![]() |
130bbda00e | ||
![]() |
2666bd6996 | ||
![]() |
ff2c8da803 | ||
![]() |
e094296f37 | ||
![]() |
7c3b77fb36 | ||
![]() |
fb4c4f07ca | ||
![]() |
b9e25e82cf | ||
![]() |
089036da29 | ||
![]() |
1123bfed10 | ||
![]() |
7f2293308b | ||
![]() |
a65131f9d3 | ||
![]() |
8a3a646c61 | ||
![]() |
4384947be1 | ||
![]() |
69421182ca | ||
![]() |
068382f5df | ||
![]() |
c4bec05466 | ||
![]() |
89e1ac0a6e | ||
![]() |
b84e0e11b4 | ||
![]() |
d95f5f8f3b | ||
![]() |
b4c0941683 | ||
![]() |
cf9798cede | ||
![]() |
20d2501edc | ||
![]() |
d45601fdc6 | ||
![]() |
c81a9a89cf | ||
![]() |
87b9f9ecfb | ||
![]() |
cbc473359a | ||
![]() |
2eba60db75 | ||
![]() |
0dcbed3f53 | ||
![]() |
ca08eb65e2 | ||
![]() |
6f37d9bee7 | ||
![]() |
e65f6b8c8b | ||
![]() |
707dc43d55 | ||
![]() |
8cbb7a9319 | ||
![]() |
4f5a56aadb | ||
![]() |
399beb53d9 | ||
![]() |
7dec9fd6e7 | ||
![]() |
120f3a8918 | ||
![]() |
bd672eaf5b | ||
![]() |
c2500ea2d8 | ||
![]() |
a4663b4b2e | ||
![]() |
57c618b83a | ||
![]() |
b3a4f95110 | ||
![]() |
28a1eb3527 | ||
![]() |
75ecc15958 | ||
![]() |
2235ebce2f | ||
![]() |
7147463418 | ||
![]() |
010e4c8d54 | ||
![]() |
6f394a0691 | ||
![]() |
efd7279118 | ||
![]() |
601056f3a7 | ||
![]() |
0a7f96cbfb | ||
![]() |
1c530c2fe0 | ||
![]() |
1e576dd7c6 | ||
![]() |
7a5472153b | ||
![]() |
b986ce566b | ||
![]() |
daba16f4be | ||
![]() |
ee36e2264e | ||
![]() |
329e98d9f0 | ||
![]() |
f4513f7028 | ||
![]() |
b1c5449428 | ||
![]() |
431732f5d1 | ||
![]() |
d0bff18cee | ||
![]() |
8ad30d0a35 |
53
.github/workflows/build.yml
vendored
53
.github/workflows/build.yml
vendored
@@ -31,20 +31,20 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v3
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: integration-test-base
|
||||
set: |
|
||||
@@ -66,6 +66,7 @@ jobs:
|
||||
matrix:
|
||||
worker:
|
||||
- docker
|
||||
- docker\+containerd # same as docker, but with containerd snapshotter
|
||||
- docker-container
|
||||
- remote
|
||||
pkg:
|
||||
@@ -76,20 +77,22 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build test image
|
||||
uses: docker/bake-action@v3
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: integration-test
|
||||
set: |
|
||||
@@ -101,8 +104,8 @@ jobs:
|
||||
export TEST_REPORT_SUFFIX=-${{ github.job }}-$(echo "${{ matrix.pkg }}-${{ matrix.skip-integration-tests }}-${{ matrix.worker }}" | tr -dc '[:alnum:]-\n\r' | tr '[:upper:]' '[:lower:]')
|
||||
./hack/test
|
||||
env:
|
||||
TEST_DOCKERD: "${{ (matrix.worker == 'docker' || matrix.worker == 'docker-container') && '1' || '0' }}"
|
||||
TESTFLAGS: "${{ (matrix.worker == 'docker' || matrix.worker == 'docker-container') && env.TESTFLAGS_DOCKER || env.TESTFLAGS }} --run=//worker=${{ matrix.worker }}$"
|
||||
TEST_DOCKERD: "${{ startsWith(matrix.worker, 'docker') && '1' || '0' }}"
|
||||
TESTFLAGS: "${{ (matrix.worker == 'docker' || matrix.worker == 'docker\\+containerd') && env.TESTFLAGS_DOCKER || env.TESTFLAGS }} --run=//worker=${{ matrix.worker }}$"
|
||||
TESTPKGS: "${{ matrix.pkg }}"
|
||||
SKIP_INTEGRATION_TESTS: "${{ matrix.skip-integration-tests }}"
|
||||
-
|
||||
@@ -132,7 +135,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Create matrix
|
||||
id: platforms
|
||||
@@ -159,13 +162,13 @@ jobs:
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.BUILDKIT_IMAGE }}
|
||||
@@ -194,13 +197,13 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.BUILDKIT_IMAGE }}
|
||||
@@ -208,7 +211,7 @@ jobs:
|
||||
-
|
||||
name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
${{ env.REPO_SLUG }}
|
||||
@@ -220,13 +223,13 @@ jobs:
|
||||
-
|
||||
name: Login to DockerHub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push image
|
||||
uses: docker/bake-action@v3
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
files: |
|
||||
./docker-bake.hcl
|
||||
@@ -246,7 +249,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Download binaries
|
||||
uses: actions/download-artifact@v3
|
||||
@@ -280,13 +283,13 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.BUILDX_VERSION }}
|
||||
driver-opts: image=moby/buildkit:master
|
||||
@@ -294,6 +297,6 @@ jobs:
|
||||
-
|
||||
# Just run a bake target to check eveything runs fine
|
||||
name: Build
|
||||
uses: docker/bake-action@v3
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: binaries
|
||||
|
42
.github/workflows/codeql.yml
vendored
Normal file
42
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
name: codeql
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'v[0-9]*'
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
env:
|
||||
GO_VERSION: 1.21.3
|
||||
|
||||
jobs:
|
||||
codeql:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: go
|
||||
-
|
||||
name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
-
|
||||
name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:go"
|
8
.github/workflows/docs-release.yml
vendored
8
.github/workflows/docs-release.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout docs repo
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GHPAT_DOCS_DISPATCH }}
|
||||
repository: docker/docs
|
||||
@@ -23,10 +23,10 @@ jobs:
|
||||
rm -rf ./_data/buildx/*
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build docs
|
||||
uses: docker/bake-action@v3
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
source: ${{ github.server_url }}/${{ github.repository }}.git#${{ github.event.release.name }}
|
||||
targets: update-docs
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
git add -A .
|
||||
-
|
||||
name: Create PR on docs repo
|
||||
uses: peter-evans/create-pull-request@284f54f989303d2699d373481a0cfa13ad5a6666
|
||||
uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38
|
||||
with:
|
||||
token: ${{ secrets.GHPAT_DOCS_DISPATCH }}
|
||||
push-to-fork: docker-tools-robot/docker.github.io
|
||||
|
8
.github/workflows/docs-upstream.yml
vendored
8
.github/workflows/docs-upstream.yml
vendored
@@ -26,15 +26,15 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: latest
|
||||
-
|
||||
name: Build reference YAML docs
|
||||
uses: docker/bake-action@v3
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: update-docs
|
||||
set: |
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
needs:
|
||||
- docs-yaml
|
||||
with:
|
||||
repo: https://github.com/${{ github.repository }}
|
||||
module-name: docker/buildx
|
||||
data-files-id: docs-yaml
|
||||
data-files-folder: buildx
|
||||
data-files-placeholder-folder: engine/reference/commandline
|
||||
|
10
.github/workflows/e2e.yml
vendored
10
.github/workflows/e2e.yml
vendored
@@ -25,15 +25,15 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: latest
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v3
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: binaries
|
||||
set: |
|
||||
@@ -96,10 +96,10 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
if: matrix.driver == 'docker' || matrix.driver == 'docker-container'
|
||||
-
|
||||
name: Install buildx
|
||||
|
4
.github/workflows/validate.yml
vendored
4
.github/workflows/validate.yml
vendored
@@ -30,10 +30,10 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: latest
|
||||
-
|
||||
|
@@ -26,12 +26,13 @@ linters:
|
||||
|
||||
linters-settings:
|
||||
depguard:
|
||||
list-type: blacklist
|
||||
include-go-root: true
|
||||
packages:
|
||||
# The io/ioutil package has been deprecated.
|
||||
# https://go.dev/doc/go1.16#ioutil
|
||||
- io/ioutil
|
||||
rules:
|
||||
main:
|
||||
deny:
|
||||
# The io/ioutil package has been deprecated.
|
||||
# https://go.dev/doc/go1.16#ioutil
|
||||
- pkg: "io/ioutil"
|
||||
desc: The io/ioutil package has been deprecated.
|
||||
forbidigo:
|
||||
forbid:
|
||||
- '^fmt\.Errorf(# use errors\.Errorf instead)?$'
|
||||
@@ -47,3 +48,22 @@ issues:
|
||||
- linters:
|
||||
- revive
|
||||
text: "stutters"
|
||||
- linters:
|
||||
- revive
|
||||
text: "empty-block"
|
||||
- linters:
|
||||
- revive
|
||||
text: "superfluous-else"
|
||||
- linters:
|
||||
- revive
|
||||
text: "unused-parameter"
|
||||
- linters:
|
||||
- revive
|
||||
text: "redefines-builtin-id"
|
||||
- linters:
|
||||
- revive
|
||||
text: "if-return"
|
||||
|
||||
# show all
|
||||
max-issues-per-linter: 0
|
||||
max-same-issues: 0
|
||||
|
38
Dockerfile
38
Dockerfile
@@ -1,14 +1,13 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG GO_VERSION=1.20
|
||||
ARG GO_VERSION=1.21.3
|
||||
ARG XX_VERSION=1.2.1
|
||||
ARG DOCKERD_VERSION=20.10.14
|
||||
|
||||
ARG DOCKER_VERSION=24.0.6
|
||||
ARG GOTESTSUM_VERSION=v1.9.0
|
||||
ARG REGISTRY_VERSION=2.8.0
|
||||
ARG BUILDKIT_VERSION=v0.11.6
|
||||
|
||||
FROM docker:$DOCKERD_VERSION AS dockerd-release
|
||||
|
||||
# xx is a helper for cross-compilation
|
||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
||||
|
||||
@@ -25,6 +24,22 @@ FROM registry:$REGISTRY_VERSION AS registry
|
||||
|
||||
FROM moby/buildkit:$BUILDKIT_VERSION AS buildkit
|
||||
|
||||
FROM gobase AS docker
|
||||
ARG TARGETPLATFORM
|
||||
ARG DOCKER_VERSION
|
||||
WORKDIR /opt/docker
|
||||
RUN DOCKER_ARCH=$(case ${TARGETPLATFORM:-linux/amd64} in \
|
||||
"linux/amd64") echo "x86_64" ;; \
|
||||
"linux/arm/v6") echo "armel" ;; \
|
||||
"linux/arm/v7") echo "armhf" ;; \
|
||||
"linux/arm64") echo "aarch64" ;; \
|
||||
"linux/ppc64le") echo "ppc64le" ;; \
|
||||
"linux/s390x") echo "s390x" ;; \
|
||||
*) echo "" ;; esac) \
|
||||
&& echo "DOCKER_ARCH=$DOCKER_ARCH" \
|
||||
&& wget -qO- "https://download.docker.com/linux/static/stable/${DOCKER_ARCH}/docker-${DOCKER_VERSION}.tgz" | tar xvz --strip 1
|
||||
RUN ./dockerd --version && ./containerd --version && ./ctr --version && ./runc --version
|
||||
|
||||
FROM gobase AS gotestsum
|
||||
ARG GOTESTSUM_VERSION
|
||||
ENV GOFLAGS=
|
||||
@@ -77,9 +92,20 @@ FROM binaries-$TARGETOS AS binaries
|
||||
ARG BUILDKIT_SBOM_SCAN_STAGE=true
|
||||
|
||||
FROM gobase AS integration-test-base
|
||||
RUN apk add --no-cache docker runc containerd
|
||||
# https://github.com/docker/docker/blob/master/project/PACKAGERS.md#runtime-dependencies
|
||||
RUN apk add --no-cache \
|
||||
btrfs-progs \
|
||||
e2fsprogs \
|
||||
e2fsprogs-extra \
|
||||
ip6tables \
|
||||
iptables \
|
||||
openssl \
|
||||
shadow-uidmap \
|
||||
xfsprogs \
|
||||
xz
|
||||
COPY --link --from=gotestsum /out/gotestsum /usr/bin/
|
||||
COPY --link --from=registry /bin/registry /usr/bin/
|
||||
COPY --link --from=docker /opt/docker/* /usr/bin/
|
||||
COPY --link --from=buildkit /usr/bin/buildkitd /usr/bin/
|
||||
COPY --link --from=buildkit /usr/bin/buildctl /usr/bin/
|
||||
COPY --link --from=binaries /buildx /usr/bin/
|
||||
@@ -102,7 +128,7 @@ FROM scratch AS release
|
||||
COPY --from=releaser /out/ /
|
||||
|
||||
# Shell
|
||||
FROM docker:$DOCKERD_VERSION AS dockerd-release
|
||||
FROM docker:$DOCKER_VERSION AS dockerd-release
|
||||
FROM alpine AS shell
|
||||
RUN apk add --no-cache iptables tmux git vim less openssh
|
||||
RUN mkdir -p /usr/local/lib/docker/cli-plugins && ln -s /usr/local/bin/buildx /usr/local/lib/docker/cli-plugins/docker-buildx
|
||||
|
11
README.md
11
README.md
@@ -41,12 +41,10 @@ Key features:
|
||||
- [`buildx imagetools create`](docs/reference/buildx_imagetools_create.md)
|
||||
- [`buildx imagetools inspect`](docs/reference/buildx_imagetools_inspect.md)
|
||||
- [`buildx inspect`](docs/reference/buildx_inspect.md)
|
||||
- [`buildx install`](docs/reference/buildx_install.md)
|
||||
- [`buildx ls`](docs/reference/buildx_ls.md)
|
||||
- [`buildx prune`](docs/reference/buildx_prune.md)
|
||||
- [`buildx rm`](docs/reference/buildx_rm.md)
|
||||
- [`buildx stop`](docs/reference/buildx_stop.md)
|
||||
- [`buildx uninstall`](docs/reference/buildx_uninstall.md)
|
||||
- [`buildx use`](docs/reference/buildx_use.md)
|
||||
- [`buildx version`](docs/reference/buildx_version.md)
|
||||
- [Contributing](#contributing)
|
||||
@@ -71,8 +69,9 @@ for Windows and macOS.
|
||||
|
||||
## Linux packages
|
||||
|
||||
Docker Linux packages also include Docker Buildx when installed using the
|
||||
[DEB or RPM packages](https://docs.docker.com/engine/install/).
|
||||
Docker Engine package repositories contain Docker Buildx packages when installed according to the
|
||||
[Docker Engine install documentation](https://docs.docker.com/engine/install/). Install the
|
||||
`docker-buildx-plugin` package to install the Buildx plugin.
|
||||
|
||||
## Manual download
|
||||
|
||||
@@ -148,7 +147,7 @@ $ DOCKER_BUILDKIT=1 docker build --platform=local -o . "https://github.com/docke
|
||||
$ mkdir -p ~/.docker/cli-plugins
|
||||
$ mv buildx ~/.docker/cli-plugins/docker-buildx
|
||||
|
||||
# Local
|
||||
# Local
|
||||
$ git clone https://github.com/docker/buildx.git && cd buildx
|
||||
$ make install
|
||||
```
|
||||
@@ -240,7 +239,7 @@ When you invoke a build, you can set the `--platform` flag to specify the target
|
||||
platform for the build output, (for example, `linux/amd64`, `linux/arm64`, or
|
||||
`darwin/amd64`).
|
||||
|
||||
When the current builder instance is backed by the `docker-container` or
|
||||
When the current builder instance is backed by the `docker-container` or
|
||||
`kubernetes` driver, you can specify multiple platforms together. In this case,
|
||||
it builds a manifest list which contains images for all specified architectures.
|
||||
When you use this image in [`docker run`](https://docs.docker.com/engine/reference/commandline/run/)
|
||||
|
172
bake/bake.go
172
bake/bake.go
@@ -11,6 +11,7 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
composecli "github.com/compose-spec/compose-go/cli"
|
||||
"github.com/docker/buildx/bake/hclparser"
|
||||
@@ -18,9 +19,10 @@ import (
|
||||
controllerapi "github.com/docker/buildx/controller/pb"
|
||||
"github.com/docker/buildx/util/buildflags"
|
||||
"github.com/docker/buildx/util/platformutil"
|
||||
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/docker/cli/cli/config"
|
||||
hcl "github.com/hashicorp/hcl/v2"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/client/llb"
|
||||
"github.com/moby/buildkit/session/auth/authprovider"
|
||||
"github.com/pkg/errors"
|
||||
@@ -55,7 +57,7 @@ func defaultFilenames() []string {
|
||||
return names
|
||||
}
|
||||
|
||||
func ReadLocalFiles(names []string, stdin io.Reader) ([]File, error) {
|
||||
func ReadLocalFiles(names []string, stdin io.Reader, l progress.SubLogger) ([]File, error) {
|
||||
isDefault := false
|
||||
if len(names) == 0 {
|
||||
isDefault = true
|
||||
@@ -63,20 +65,26 @@ func ReadLocalFiles(names []string, stdin io.Reader) ([]File, error) {
|
||||
}
|
||||
out := make([]File, 0, len(names))
|
||||
|
||||
setStatus := func(st *client.VertexStatus) {
|
||||
if l != nil {
|
||||
l.SetStatus(st)
|
||||
}
|
||||
}
|
||||
|
||||
for _, n := range names {
|
||||
var dt []byte
|
||||
var err error
|
||||
if n == "-" {
|
||||
dt, err = io.ReadAll(stdin)
|
||||
dt, err = readWithProgress(stdin, setStatus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
dt, err = os.ReadFile(n)
|
||||
dt, err = readFileWithProgress(n, isDefault, setStatus)
|
||||
if dt == nil && err == nil {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
if isDefault && errors.Is(err, os.ErrNotExist) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -85,6 +93,88 @@ func ReadLocalFiles(names []string, stdin io.Reader) ([]File, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func readFileWithProgress(fname string, isDefault bool, setStatus func(st *client.VertexStatus)) (dt []byte, err error) {
|
||||
st := &client.VertexStatus{
|
||||
ID: "reading " + fname,
|
||||
}
|
||||
|
||||
defer func() {
|
||||
now := time.Now()
|
||||
st.Completed = &now
|
||||
if dt != nil || err != nil {
|
||||
setStatus(st)
|
||||
}
|
||||
}()
|
||||
|
||||
now := time.Now()
|
||||
st.Started = &now
|
||||
|
||||
f, err := os.Open(fname)
|
||||
if err != nil {
|
||||
if isDefault && errors.Is(err, os.ErrNotExist) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
setStatus(st)
|
||||
|
||||
info, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
st.Total = info.Size()
|
||||
setStatus(st)
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
for {
|
||||
n, err := f.Read(buf)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dt = append(dt, buf[:n]...)
|
||||
st.Current += int64(n)
|
||||
setStatus(st)
|
||||
}
|
||||
|
||||
return dt, nil
|
||||
}
|
||||
|
||||
func readWithProgress(r io.Reader, setStatus func(st *client.VertexStatus)) (dt []byte, err error) {
|
||||
st := &client.VertexStatus{
|
||||
ID: "reading from stdin",
|
||||
}
|
||||
|
||||
defer func() {
|
||||
now := time.Now()
|
||||
st.Completed = &now
|
||||
setStatus(st)
|
||||
}()
|
||||
|
||||
now := time.Now()
|
||||
st.Started = &now
|
||||
setStatus(st)
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
for {
|
||||
n, err := r.Read(buf)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dt = append(dt, buf[:n]...)
|
||||
st.Current += int64(n)
|
||||
setStatus(st)
|
||||
}
|
||||
|
||||
return dt, nil
|
||||
}
|
||||
|
||||
func ListTargets(files []File) ([]string, error) {
|
||||
c, err := ParseFiles(files, nil)
|
||||
if err != nil {
|
||||
@@ -248,7 +338,7 @@ func ParseFiles(files []File, defaults map[string]string) (_ *Config, err error)
|
||||
}
|
||||
|
||||
if len(hclFiles) > 0 {
|
||||
renamed, err := hclparser.Parse(hcl.MergeFiles(hclFiles), hclparser.Opt{
|
||||
renamed, err := hclparser.Parse(hclparser.MergeFiles(hclFiles), hclparser.Opt{
|
||||
LookupVar: os.LookupEnv,
|
||||
Vars: defaults,
|
||||
ValidateLabel: validateTargetName,
|
||||
@@ -587,9 +677,10 @@ type Target struct {
|
||||
Name string `json:"-" hcl:"name,label" cty:"name"`
|
||||
|
||||
// Inherits is the only field that cannot be overridden with --set
|
||||
Attest []string `json:"attest,omitempty" hcl:"attest,optional" cty:"attest"`
|
||||
Inherits []string `json:"inherits,omitempty" hcl:"inherits,optional" cty:"inherits"`
|
||||
|
||||
Annotations []string `json:"annotations,omitempty" hcl:"annotations,optional" cty:"annotations"`
|
||||
Attest []string `json:"attest,omitempty" hcl:"attest,optional" cty:"attest"`
|
||||
Context *string `json:"context,omitempty" hcl:"context,optional" cty:"context"`
|
||||
Contexts map[string]string `json:"contexts,omitempty" hcl:"contexts,optional" cty:"contexts"`
|
||||
Dockerfile *string `json:"dockerfile,omitempty" hcl:"dockerfile,optional" cty:"dockerfile"`
|
||||
@@ -620,6 +711,7 @@ var _ hclparser.WithEvalContexts = &Group{}
|
||||
var _ hclparser.WithGetName = &Group{}
|
||||
|
||||
func (t *Target) normalize() {
|
||||
t.Annotations = removeDupes(t.Annotations)
|
||||
t.Attest = removeAttestDupes(t.Attest)
|
||||
t.Tags = removeDupes(t.Tags)
|
||||
t.Secrets = removeDupes(t.Secrets)
|
||||
@@ -680,6 +772,9 @@ func (t *Target) Merge(t2 *Target) {
|
||||
if t2.Target != nil {
|
||||
t.Target = t2.Target
|
||||
}
|
||||
if t2.Annotations != nil { // merge
|
||||
t.Annotations = append(t.Annotations, t2.Annotations...)
|
||||
}
|
||||
if t2.Attest != nil { // merge
|
||||
t.Attest = append(t.Attest, t2.Attest...)
|
||||
t.Attest = removeAttestDupes(t.Attest)
|
||||
@@ -766,6 +861,8 @@ func (t *Target) AddOverrides(overrides map[string]Override) error {
|
||||
t.Platforms = o.ArrValue
|
||||
case "output":
|
||||
t.Outputs = o.ArrValue
|
||||
case "annotations":
|
||||
t.Annotations = append(t.Annotations, o.ArrValue...)
|
||||
case "attest":
|
||||
t.Attest = append(t.Attest, o.ArrValue...)
|
||||
case "no-cache":
|
||||
@@ -852,8 +949,10 @@ func (t *Target) GetEvalContexts(ectx *hcl.EvalContext, block *hcl.Block, loadDe
|
||||
for _, e := range ectxs {
|
||||
e2 := ectx.NewChild()
|
||||
e2.Variables = make(map[string]cty.Value)
|
||||
for k, v := range e.Variables {
|
||||
e2.Variables[k] = v
|
||||
if e != ectx {
|
||||
for k, v := range e.Variables {
|
||||
e2.Variables[k] = v
|
||||
}
|
||||
}
|
||||
e2.Variables[k] = v
|
||||
ectxs2 = append(ectxs2, e2)
|
||||
@@ -1038,6 +1137,9 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
|
||||
if t.Dockerfile != nil {
|
||||
dockerfilePath = *t.Dockerfile
|
||||
}
|
||||
if !strings.HasPrefix(dockerfilePath, "cwd://") {
|
||||
dockerfilePath = path.Clean(dockerfilePath)
|
||||
}
|
||||
|
||||
bi := build.Inputs{
|
||||
ContextPath: contextPath,
|
||||
@@ -1048,12 +1150,44 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
|
||||
bi.DockerfileInline = *t.DockerfileInline
|
||||
}
|
||||
updateContext(&bi, inp)
|
||||
if !build.IsRemoteURL(bi.ContextPath) && bi.ContextState == nil && !path.IsAbs(bi.DockerfilePath) {
|
||||
bi.DockerfilePath = path.Join(bi.ContextPath, bi.DockerfilePath)
|
||||
if strings.HasPrefix(bi.DockerfilePath, "cwd://") {
|
||||
// If Dockerfile is local for a remote invocation, we first check if
|
||||
// it's not outside the working directory and then resolve it to an
|
||||
// absolute path.
|
||||
bi.DockerfilePath = path.Clean(strings.TrimPrefix(bi.DockerfilePath, "cwd://"))
|
||||
if err := checkPath(bi.DockerfilePath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var err error
|
||||
bi.DockerfilePath, err = filepath.Abs(bi.DockerfilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if !build.IsRemoteURL(bi.DockerfilePath) && strings.HasPrefix(bi.ContextPath, "cwd://") && (inp != nil && build.IsRemoteURL(inp.URL)) {
|
||||
// We don't currently support reading a remote Dockerfile with a local
|
||||
// context when doing a remote invocation because we automatically
|
||||
// derive the dockerfile from the context atm:
|
||||
//
|
||||
// target "default" {
|
||||
// context = BAKE_CMD_CONTEXT
|
||||
// dockerfile = "Dockerfile.app"
|
||||
// }
|
||||
//
|
||||
// > docker buildx bake https://github.com/foo/bar.git
|
||||
// failed to solve: failed to read dockerfile: open /var/lib/docker/tmp/buildkit-mount3004544897/Dockerfile.app: no such file or directory
|
||||
//
|
||||
// To avoid mistakenly reading a local Dockerfile, we check if the
|
||||
// Dockerfile exists locally and if so, we error out.
|
||||
if _, err := os.Stat(filepath.Join(path.Clean(strings.TrimPrefix(bi.ContextPath, "cwd://")), bi.DockerfilePath)); err == nil {
|
||||
return nil, errors.Errorf("reading a dockerfile for a remote build invocation is currently not supported")
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(bi.ContextPath, "cwd://") {
|
||||
bi.ContextPath = path.Clean(strings.TrimPrefix(bi.ContextPath, "cwd://"))
|
||||
}
|
||||
if !build.IsRemoteURL(bi.ContextPath) && bi.ContextState == nil && !path.IsAbs(bi.DockerfilePath) {
|
||||
bi.DockerfilePath = path.Join(bi.ContextPath, bi.DockerfilePath)
|
||||
}
|
||||
for k, v := range bi.NamedContexts {
|
||||
if strings.HasPrefix(v.Path, "cwd://") {
|
||||
bi.NamedContexts[k] = build.NamedContext{Path: path.Clean(strings.TrimPrefix(v.Path, "cwd://"))}
|
||||
@@ -1114,7 +1248,7 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
|
||||
bo.Platforms = platforms
|
||||
|
||||
dockerConfig := config.LoadDefaultConfigFile(os.Stderr)
|
||||
bo.Session = append(bo.Session, authprovider.NewDockerAuthProvider(dockerConfig))
|
||||
bo.Session = append(bo.Session, authprovider.NewDockerAuthProvider(dockerConfig, nil))
|
||||
|
||||
secrets, err := buildflags.ParseSecretSpecs(t.Secrets)
|
||||
if err != nil {
|
||||
@@ -1164,6 +1298,16 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
annotations, err := buildflags.ParseAnnotations(t.Annotations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, e := range bo.Exports {
|
||||
for k, v := range annotations {
|
||||
e.Attrs[k.String()] = v
|
||||
}
|
||||
}
|
||||
|
||||
attests, err := buildflags.ParseAttests(t.Attest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -3,10 +3,12 @@ package bake
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -295,6 +297,9 @@ services:
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
|
||||
m, g, err := ReadTargets(ctx, []File{fp, fp2, fp3}, []string{"default"}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -303,7 +308,7 @@ services:
|
||||
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "Dockerfile.webapp", *m["webapp"].Dockerfile)
|
||||
require.Equal(t, ".", *m["webapp"].Context)
|
||||
require.Equal(t, cwd, *m["webapp"].Context)
|
||||
require.Equal(t, ptrstr("1"), m["webapp"].Args["buildno"])
|
||||
require.Equal(t, ptrstr("12"), m["webapp"].Args["buildno2"])
|
||||
|
||||
@@ -342,6 +347,9 @@ services:
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
|
||||
m, _, err := ReadTargets(ctx, []File{fp}, []string{"web.app"}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(m))
|
||||
@@ -364,7 +372,7 @@ services:
|
||||
_, ok = m["web_app"]
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "Dockerfile.webapp", *m["web_app"].Dockerfile)
|
||||
require.Equal(t, ".", *m["web_app"].Context)
|
||||
require.Equal(t, cwd, *m["web_app"].Context)
|
||||
require.Equal(t, ptrstr("1"), m["web_app"].Args["buildno"])
|
||||
require.Equal(t, ptrstr("12"), m["web_app"].Args["buildno2"])
|
||||
|
||||
@@ -373,7 +381,7 @@ services:
|
||||
require.Equal(t, []string{"web_app"}, g["default"].Targets)
|
||||
}
|
||||
|
||||
func TestHCLCwdPrefix(t *testing.T) {
|
||||
func TestHCLContextCwdPrefix(t *testing.T) {
|
||||
fp := File{
|
||||
Name: "docker-bake.hcl",
|
||||
Data: []byte(
|
||||
@@ -386,18 +394,49 @@ func TestHCLCwdPrefix(t *testing.T) {
|
||||
m, g, err := ReadTargets(ctx, []File{fp}, []string{"app"}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(m))
|
||||
_, ok := m["app"]
|
||||
require.True(t, ok)
|
||||
|
||||
_, err = TargetsToBuildOpt(m, &Input{})
|
||||
bo, err := TargetsToBuildOpt(m, &Input{})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "test", *m["app"].Dockerfile)
|
||||
require.Equal(t, "foo", *m["app"].Context)
|
||||
|
||||
require.Equal(t, 1, len(g))
|
||||
require.Equal(t, []string{"app"}, g["default"].Targets)
|
||||
|
||||
require.Equal(t, 1, len(m))
|
||||
require.Contains(t, m, "app")
|
||||
assert.Equal(t, "test", *m["app"].Dockerfile)
|
||||
assert.Equal(t, "foo", *m["app"].Context)
|
||||
assert.Equal(t, "foo/test", bo["app"].Inputs.DockerfilePath)
|
||||
assert.Equal(t, "foo", bo["app"].Inputs.ContextPath)
|
||||
}
|
||||
|
||||
func TestHCLDockerfileCwdPrefix(t *testing.T) {
|
||||
fp := File{
|
||||
Name: "docker-bake.hcl",
|
||||
Data: []byte(
|
||||
`target "app" {
|
||||
context = "."
|
||||
dockerfile = "cwd://Dockerfile.app"
|
||||
}`),
|
||||
}
|
||||
ctx := context.TODO()
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
|
||||
m, g, err := ReadTargets(ctx, []File{fp}, []string{"app"}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
bo, err := TargetsToBuildOpt(m, &Input{})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(g))
|
||||
require.Equal(t, []string{"app"}, g["default"].Targets)
|
||||
|
||||
require.Equal(t, 1, len(m))
|
||||
require.Contains(t, m, "app")
|
||||
assert.Equal(t, "cwd://Dockerfile.app", *m["app"].Dockerfile)
|
||||
assert.Equal(t, ".", *m["app"].Context)
|
||||
assert.Equal(t, filepath.Join(cwd, "Dockerfile.app"), bo["app"].Inputs.DockerfilePath)
|
||||
assert.Equal(t, ".", bo["app"].Inputs.ContextPath)
|
||||
}
|
||||
|
||||
func TestOverrideMerge(t *testing.T) {
|
||||
@@ -542,6 +581,9 @@ services:
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
|
||||
m, _, err := ReadTargets(ctx, []File{fp, fp2}, []string{"app1", "app2"}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -554,7 +596,7 @@ services:
|
||||
require.Equal(t, "Dockerfile", *m["app1"].Dockerfile)
|
||||
require.Equal(t, ".", *m["app1"].Context)
|
||||
require.Equal(t, "Dockerfile", *m["app2"].Dockerfile)
|
||||
require.Equal(t, ".", *m["app2"].Context)
|
||||
require.Equal(t, cwd, *m["app2"].Context)
|
||||
}
|
||||
|
||||
func TestReadContextFromTargetChain(t *testing.T) {
|
||||
@@ -1398,7 +1440,7 @@ func TestReadLocalFilesDefault(t *testing.T) {
|
||||
for _, tf := range tt.filenames {
|
||||
require.NoError(t, os.WriteFile(tf, []byte(tf), 0644))
|
||||
}
|
||||
files, err := ReadLocalFiles(nil, nil)
|
||||
files, err := ReadLocalFiles(nil, nil, nil)
|
||||
require.NoError(t, err)
|
||||
if len(files) == 0 {
|
||||
require.Equal(t, len(tt.expected), len(files))
|
||||
@@ -1450,3 +1492,31 @@ func TestAttestDuplicates(t *testing.T) {
|
||||
"provenance": ptrstr("type=provenance,mode=max"),
|
||||
}, opts["default"].Attests)
|
||||
}
|
||||
|
||||
func TestAnnotations(t *testing.T) {
|
||||
fp := File{
|
||||
Name: "docker-bake.hcl",
|
||||
Data: []byte(
|
||||
`target "app" {
|
||||
output = ["type=image,name=foo"]
|
||||
annotations = ["manifest[linux/amd64]:foo=bar"]
|
||||
}`),
|
||||
}
|
||||
ctx := context.TODO()
|
||||
m, g, err := ReadTargets(ctx, []File{fp}, []string{"app"}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
bo, err := TargetsToBuildOpt(m, &Input{})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(g))
|
||||
require.Equal(t, []string{"app"}, g["default"].Targets)
|
||||
|
||||
require.Equal(t, 1, len(m))
|
||||
require.Contains(t, m, "app")
|
||||
require.Equal(t, "type=image,name=foo", m["app"].Outputs[0])
|
||||
require.Equal(t, "manifest[linux/amd64]:foo=bar", m["app"].Annotations[0])
|
||||
|
||||
require.Len(t, bo["app"].Exports, 1)
|
||||
require.Equal(t, "bar", bo["app"].Exports[0].Attrs["annotation-manifest[linux/amd64].foo"])
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package bake
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -31,12 +32,13 @@ func ParseCompose(cfgs []compose.ConfigFile, envs map[string]string) (*Config, e
|
||||
if envs == nil {
|
||||
envs = make(map[string]string)
|
||||
}
|
||||
cfg, err := loader.Load(compose.ConfigDetails{
|
||||
cfg, err := loader.LoadWithContext(context.Background(), compose.ConfigDetails{
|
||||
ConfigFiles: cfgs,
|
||||
Environment: envs,
|
||||
}, func(options *loader.Options) {
|
||||
options.SetProjectName("bake", false)
|
||||
options.SkipNormalization = true
|
||||
options.Profiles = []string{"*"}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -50,6 +52,7 @@ func ParseCompose(cfgs []compose.ConfigFile, envs map[string]string) (*Config, e
|
||||
g := &Group{Name: "default"}
|
||||
|
||||
for _, s := range cfg.Services {
|
||||
s := s
|
||||
if s.Build == nil {
|
||||
continue
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ services:
|
||||
build:
|
||||
context: ./dir
|
||||
additional_contexts:
|
||||
foo: /bar
|
||||
foo: ./bar
|
||||
dockerfile: Dockerfile-alternate
|
||||
network:
|
||||
none
|
||||
@@ -36,6 +36,8 @@ services:
|
||||
- token
|
||||
- aws
|
||||
webapp2:
|
||||
profiles:
|
||||
- test
|
||||
build:
|
||||
context: ./dir
|
||||
dockerfile_inline: |
|
||||
@@ -47,6 +49,9 @@ secrets:
|
||||
file: /root/.aws/credentials
|
||||
`)
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -60,12 +65,12 @@ secrets:
|
||||
return c.Targets[i].Name < c.Targets[j].Name
|
||||
})
|
||||
require.Equal(t, "db", c.Targets[0].Name)
|
||||
require.Equal(t, "./db", *c.Targets[0].Context)
|
||||
require.Equal(t, filepath.Join(cwd, "db"), *c.Targets[0].Context)
|
||||
require.Equal(t, []string{"docker.io/tonistiigi/db"}, c.Targets[0].Tags)
|
||||
|
||||
require.Equal(t, "webapp", c.Targets[1].Name)
|
||||
require.Equal(t, "./dir", *c.Targets[1].Context)
|
||||
require.Equal(t, map[string]string{"foo": "/bar"}, c.Targets[1].Contexts)
|
||||
require.Equal(t, filepath.Join(cwd, "dir"), *c.Targets[1].Context)
|
||||
require.Equal(t, map[string]string{"foo": filepath.Join(cwd, "bar")}, c.Targets[1].Contexts)
|
||||
require.Equal(t, "Dockerfile-alternate", *c.Targets[1].Dockerfile)
|
||||
require.Equal(t, 1, len(c.Targets[1].Args))
|
||||
require.Equal(t, ptrstr("123"), c.Targets[1].Args["buildno"])
|
||||
@@ -78,7 +83,7 @@ secrets:
|
||||
}, c.Targets[1].Secrets)
|
||||
|
||||
require.Equal(t, "webapp2", c.Targets[2].Name)
|
||||
require.Equal(t, "./dir", *c.Targets[2].Context)
|
||||
require.Equal(t, filepath.Join(cwd, "dir"), *c.Targets[2].Context)
|
||||
require.Equal(t, "FROM alpine\n", *c.Targets[2].DockerfileInline)
|
||||
}
|
||||
|
||||
@@ -654,6 +659,85 @@ services:
|
||||
require.Equal(t, map[string]*string{"bar": ptrstr("baz")}, c.Targets[0].Args)
|
||||
}
|
||||
|
||||
func TestDependsOn(t *testing.T) {
|
||||
var dt = []byte(`
|
||||
services:
|
||||
foo:
|
||||
build:
|
||||
context: .
|
||||
ports:
|
||||
- 3306:3306
|
||||
depends_on:
|
||||
- bar
|
||||
bar:
|
||||
build:
|
||||
context: .
|
||||
`)
|
||||
_, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestInclude(t *testing.T) {
|
||||
tmpdir := t.TempDir()
|
||||
|
||||
err := os.WriteFile(filepath.Join(tmpdir, "compose-foo.yml"), []byte(`
|
||||
services:
|
||||
foo:
|
||||
build:
|
||||
context: .
|
||||
target: buildfoo
|
||||
ports:
|
||||
- 3306:3306
|
||||
`), 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
var dt = []byte(`
|
||||
include:
|
||||
- compose-foo.yml
|
||||
|
||||
services:
|
||||
bar:
|
||||
build:
|
||||
context: .
|
||||
target: buildbar
|
||||
`)
|
||||
|
||||
chdir(t, tmpdir)
|
||||
c, err := ParseComposeFiles([]File{{
|
||||
Name: "compose.yml",
|
||||
Data: dt,
|
||||
}})
|
||||
require.NoError(t, err)
|
||||
|
||||
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, "bar", c.Targets[0].Name)
|
||||
require.Equal(t, "buildbar", *c.Targets[0].Target)
|
||||
require.Equal(t, "foo", c.Targets[1].Name)
|
||||
require.Equal(t, "buildfoo", *c.Targets[1].Target)
|
||||
}
|
||||
|
||||
func TestDevelop(t *testing.T) {
|
||||
var dt = []byte(`
|
||||
services:
|
||||
scratch:
|
||||
build:
|
||||
context: ./webapp
|
||||
develop:
|
||||
watch:
|
||||
- path: ./webapp/html
|
||||
action: sync
|
||||
target: /var/www
|
||||
ignore:
|
||||
- node_modules/
|
||||
`)
|
||||
|
||||
_, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
@@ -634,6 +634,29 @@ func TestHCLMultiFileAttrs(t *testing.T) {
|
||||
require.Equal(t, ptrstr("pre-ghi"), c.Targets[0].Args["v1"])
|
||||
}
|
||||
|
||||
func TestHCLMultiFileGlobalAttrs(t *testing.T) {
|
||||
dt := []byte(`
|
||||
FOO = "abc"
|
||||
target "app" {
|
||||
args = {
|
||||
v1 = "pre-${FOO}"
|
||||
}
|
||||
}
|
||||
`)
|
||||
dt2 := []byte(`
|
||||
FOO = "def"
|
||||
`)
|
||||
|
||||
c, err := ParseFiles([]File{
|
||||
{Data: dt, Name: "c1.hcl"},
|
||||
{Data: dt2, Name: "c2.hcl"},
|
||||
}, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(c.Targets))
|
||||
require.Equal(t, c.Targets[0].Name, "app")
|
||||
require.Equal(t, "pre-def", *c.Targets[0].Args["v1"])
|
||||
}
|
||||
|
||||
func TestHCLDuplicateTarget(t *testing.T) {
|
||||
dt := []byte(`
|
||||
target "app" {
|
||||
@@ -1090,6 +1113,27 @@ func TestHCLMatrixBadTypes(t *testing.T) {
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestHCLMatrixWithGlobalTarget(t *testing.T) {
|
||||
dt := []byte(`
|
||||
target "x" {
|
||||
tags = ["a", "b"]
|
||||
}
|
||||
|
||||
target "default" {
|
||||
tags = target.x.tags
|
||||
matrix = {
|
||||
dummy = [""]
|
||||
}
|
||||
}
|
||||
`)
|
||||
c, err := ParseFile(dt, "docker-bake.hcl")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(c.Targets))
|
||||
require.Equal(t, "x", c.Targets[0].Name)
|
||||
require.Equal(t, "default", c.Targets[1].Name)
|
||||
require.Equal(t, []string{"a", "b"}, c.Targets[1].Tags)
|
||||
}
|
||||
|
||||
func TestJSONAttributes(t *testing.T) {
|
||||
dt := []byte(`{"FOO": "abc", "variable": {"BAR": {"default": "def"}}, "target": { "app": { "args": {"v1": "pre-${FOO}-${BAR}"}} } }`)
|
||||
|
||||
|
@@ -613,7 +613,7 @@ func Parse(b hcl.Body, opt Opt, val interface{}) (map[string]map[string][]string
|
||||
|
||||
attrs, diags := b.JustAttributes()
|
||||
if diags.HasErrors() {
|
||||
if d := removeAttributesDiags(diags, reserved, p.vars); len(d) > 0 {
|
||||
if d := removeAttributesDiags(diags, reserved, p.vars, attrs); len(d) > 0 {
|
||||
return nil, d
|
||||
}
|
||||
}
|
||||
@@ -631,13 +631,14 @@ func Parse(b hcl.Body, opt Opt, val interface{}) (map[string]map[string][]string
|
||||
}
|
||||
|
||||
for _, a := range content.Attributes {
|
||||
a := a
|
||||
return nil, hcl.Diagnostics{
|
||||
&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid attribute",
|
||||
Detail: "global attributes currently not supported",
|
||||
Subject: &a.Range,
|
||||
Context: &a.Range,
|
||||
Subject: a.Range.Ptr(),
|
||||
Context: a.Range.Ptr(),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -660,13 +661,14 @@ func Parse(b hcl.Body, opt Opt, val interface{}) (map[string]map[string][]string
|
||||
var subject *hcl.Range
|
||||
var context *hcl.Range
|
||||
if p.funcs[k].Params != nil {
|
||||
subject = &p.funcs[k].Params.Range
|
||||
subject = p.funcs[k].Params.Range.Ptr()
|
||||
context = subject
|
||||
} else {
|
||||
for _, block := range blocks.Blocks {
|
||||
block := block
|
||||
if block.Type == "function" && len(block.Labels) == 1 && block.Labels[0] == k {
|
||||
subject = &block.LabelRanges[0]
|
||||
context = &block.DefRange
|
||||
subject = block.LabelRanges[0].Ptr()
|
||||
context = block.DefRange.Ptr()
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -732,6 +734,7 @@ func Parse(b hcl.Body, opt Opt, val interface{}) (map[string]map[string][]string
|
||||
|
||||
diags = hcl.Diagnostics{}
|
||||
for _, b := range content.Blocks {
|
||||
b := b
|
||||
v := reflect.ValueOf(val)
|
||||
|
||||
err := p.resolveBlock(b, nil)
|
||||
@@ -742,7 +745,7 @@ func Parse(b hcl.Body, opt Opt, val interface{}) (map[string]map[string][]string
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
return nil, wrapErrorDiagnostic("Invalid block", err, &b.LabelRanges[0], &b.DefRange)
|
||||
return nil, wrapErrorDiagnostic("Invalid block", err, b.LabelRanges[0].Ptr(), b.DefRange.Ptr())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -854,7 +857,7 @@ func getNameIndex(v reflect.Value) (int, bool) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func removeAttributesDiags(diags hcl.Diagnostics, reserved map[string]struct{}, vars map[string]*variable) hcl.Diagnostics {
|
||||
func removeAttributesDiags(diags hcl.Diagnostics, reserved map[string]struct{}, vars map[string]*variable, attrs hcl.Attributes) hcl.Diagnostics {
|
||||
var fdiags hcl.Diagnostics
|
||||
for _, d := range diags {
|
||||
if fout := func(d *hcl.Diagnostic) bool {
|
||||
@@ -876,6 +879,12 @@ func removeAttributesDiags(diags hcl.Diagnostics, reserved map[string]struct{},
|
||||
return true
|
||||
}
|
||||
}
|
||||
for a := range attrs {
|
||||
// Do the same for attributes
|
||||
if strings.HasPrefix(d.Detail, fmt.Sprintf(`Argument "%s" was already set at `, a)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}(d); !fout {
|
||||
fdiags = append(fdiags, d)
|
||||
|
230
bake/hclparser/merged.go
Normal file
230
bake/hclparser/merged.go
Normal file
@@ -0,0 +1,230 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
// Forked from https://github.com/hashicorp/hcl/blob/4679383728fe331fc8a6b46036a27b8f818d9bc0/merged.go
|
||||
|
||||
package hclparser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
)
|
||||
|
||||
// MergeFiles combines the given files to produce a single body that contains
|
||||
// configuration from all of the given files.
|
||||
//
|
||||
// The ordering of the given files decides the order in which contained
|
||||
// elements will be returned. If any top-level attributes are defined with
|
||||
// the same name across multiple files, a diagnostic will be produced from
|
||||
// the Content and PartialContent methods describing this error in a
|
||||
// user-friendly way.
|
||||
func MergeFiles(files []*hcl.File) hcl.Body {
|
||||
var bodies []hcl.Body
|
||||
for _, file := range files {
|
||||
bodies = append(bodies, file.Body)
|
||||
}
|
||||
return MergeBodies(bodies)
|
||||
}
|
||||
|
||||
// MergeBodies is like MergeFiles except it deals directly with bodies, rather
|
||||
// than with entire files.
|
||||
func MergeBodies(bodies []hcl.Body) hcl.Body {
|
||||
if len(bodies) == 0 {
|
||||
// Swap out for our singleton empty body, to reduce the number of
|
||||
// empty slices we have hanging around.
|
||||
return emptyBody
|
||||
}
|
||||
|
||||
// If any of the given bodies are already merged bodies, we'll unpack
|
||||
// to flatten to a single mergedBodies, since that's conceptually simpler.
|
||||
// This also, as a side-effect, eliminates any empty bodies, since
|
||||
// empties are merged bodies with no inner bodies.
|
||||
var newLen int
|
||||
var flatten bool
|
||||
for _, body := range bodies {
|
||||
if children, merged := body.(mergedBodies); merged {
|
||||
newLen += len(children)
|
||||
flatten = true
|
||||
} else {
|
||||
newLen++
|
||||
}
|
||||
}
|
||||
|
||||
if !flatten { // not just newLen == len, because we might have mergedBodies with single bodies inside
|
||||
return mergedBodies(bodies)
|
||||
}
|
||||
|
||||
if newLen == 0 {
|
||||
// Don't allocate a new empty when we already have one
|
||||
return emptyBody
|
||||
}
|
||||
|
||||
n := make([]hcl.Body, 0, newLen)
|
||||
for _, body := range bodies {
|
||||
if children, merged := body.(mergedBodies); merged {
|
||||
n = append(n, children...)
|
||||
} else {
|
||||
n = append(n, body)
|
||||
}
|
||||
}
|
||||
return mergedBodies(n)
|
||||
}
|
||||
|
||||
var emptyBody = mergedBodies([]hcl.Body{})
|
||||
|
||||
// EmptyBody returns a body with no content. This body can be used as a
|
||||
// placeholder when a body is required but no body content is available.
|
||||
func EmptyBody() hcl.Body {
|
||||
return emptyBody
|
||||
}
|
||||
|
||||
type mergedBodies []hcl.Body
|
||||
|
||||
// Content returns the content produced by applying the given schema to all
|
||||
// of the merged bodies and merging the result.
|
||||
//
|
||||
// Although required attributes _are_ supported, they should be used sparingly
|
||||
// with merged bodies since in this case there is no contextual information
|
||||
// with which to return good diagnostics. Applications working with merged
|
||||
// bodies may wish to mark all attributes as optional and then check for
|
||||
// required attributes afterwards, to produce better diagnostics.
|
||||
func (mb mergedBodies) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
|
||||
// the returned body will always be empty in this case, because mergedContent
|
||||
// will only ever call Content on the child bodies.
|
||||
content, _, diags := mb.mergedContent(schema, false)
|
||||
return content, diags
|
||||
}
|
||||
|
||||
func (mb mergedBodies) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
|
||||
return mb.mergedContent(schema, true)
|
||||
}
|
||||
|
||||
func (mb mergedBodies) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
|
||||
attrs := make(map[string]*hcl.Attribute)
|
||||
var diags hcl.Diagnostics
|
||||
|
||||
for _, body := range mb {
|
||||
thisAttrs, thisDiags := body.JustAttributes()
|
||||
|
||||
if len(thisDiags) != 0 {
|
||||
diags = append(diags, thisDiags...)
|
||||
}
|
||||
|
||||
if thisAttrs != nil {
|
||||
for name, attr := range thisAttrs {
|
||||
if existing := attrs[name]; existing != nil {
|
||||
diags = diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Duplicate argument",
|
||||
Detail: fmt.Sprintf(
|
||||
"Argument %q was already set at %s",
|
||||
name, existing.NameRange.String(),
|
||||
),
|
||||
Subject: thisAttrs[name].NameRange.Ptr(),
|
||||
})
|
||||
}
|
||||
attrs[name] = attr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attrs, diags
|
||||
}
|
||||
|
||||
func (mb mergedBodies) MissingItemRange() hcl.Range {
|
||||
if len(mb) == 0 {
|
||||
// Nothing useful to return here, so we'll return some garbage.
|
||||
return hcl.Range{
|
||||
Filename: "<empty>",
|
||||
}
|
||||
}
|
||||
|
||||
// arbitrarily use the first body's missing item range
|
||||
return mb[0].MissingItemRange()
|
||||
}
|
||||
|
||||
func (mb mergedBodies) mergedContent(schema *hcl.BodySchema, partial bool) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
|
||||
// We need to produce a new schema with none of the attributes marked as
|
||||
// required, since _any one_ of our bodies can contribute an attribute value.
|
||||
// We'll separately check that all required attributes are present at
|
||||
// the end.
|
||||
mergedSchema := &hcl.BodySchema{
|
||||
Blocks: schema.Blocks,
|
||||
}
|
||||
for _, attrS := range schema.Attributes {
|
||||
mergedAttrS := attrS
|
||||
mergedAttrS.Required = false
|
||||
mergedSchema.Attributes = append(mergedSchema.Attributes, mergedAttrS)
|
||||
}
|
||||
|
||||
var mergedLeftovers []hcl.Body
|
||||
content := &hcl.BodyContent{
|
||||
Attributes: map[string]*hcl.Attribute{},
|
||||
}
|
||||
|
||||
var diags hcl.Diagnostics
|
||||
for _, body := range mb {
|
||||
var thisContent *hcl.BodyContent
|
||||
var thisLeftovers hcl.Body
|
||||
var thisDiags hcl.Diagnostics
|
||||
|
||||
if partial {
|
||||
thisContent, thisLeftovers, thisDiags = body.PartialContent(mergedSchema)
|
||||
} else {
|
||||
thisContent, thisDiags = body.Content(mergedSchema)
|
||||
}
|
||||
|
||||
if thisLeftovers != nil {
|
||||
mergedLeftovers = append(mergedLeftovers, thisLeftovers)
|
||||
}
|
||||
if len(thisDiags) != 0 {
|
||||
diags = append(diags, thisDiags...)
|
||||
}
|
||||
|
||||
if thisContent.Attributes != nil {
|
||||
for name, attr := range thisContent.Attributes {
|
||||
if existing := content.Attributes[name]; existing != nil {
|
||||
diags = diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Duplicate argument",
|
||||
Detail: fmt.Sprintf(
|
||||
"Argument %q was already set at %s",
|
||||
name, existing.NameRange.String(),
|
||||
),
|
||||
Subject: thisContent.Attributes[name].NameRange.Ptr(),
|
||||
})
|
||||
}
|
||||
content.Attributes[name] = attr
|
||||
}
|
||||
}
|
||||
|
||||
if len(thisContent.Blocks) != 0 {
|
||||
content.Blocks = append(content.Blocks, thisContent.Blocks...)
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, we check for required attributes.
|
||||
for _, attrS := range schema.Attributes {
|
||||
if !attrS.Required {
|
||||
continue
|
||||
}
|
||||
|
||||
if content.Attributes[attrS.Name] == nil {
|
||||
// We don't have any context here to produce a good diagnostic,
|
||||
// which is why we warn in the Content docstring to minimize the
|
||||
// use of required attributes on merged bodies.
|
||||
diags = diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing required argument",
|
||||
Detail: fmt.Sprintf(
|
||||
"The argument %q is required, but was not set.",
|
||||
attrS.Name,
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
leftoverBody := MergeBodies(mergedLeftovers)
|
||||
return content, leftoverBody, diags
|
||||
}
|
@@ -59,7 +59,7 @@ func ReadRemoteFiles(ctx context.Context, nodes []builder.Node, url string, name
|
||||
|
||||
ch, done := progress.NewChannel(pw)
|
||||
defer func() { <-done }()
|
||||
_, err = c.Build(ctx, client.SolveOpt{Session: session}, "buildx", func(ctx context.Context, c gwclient.Client) (*gwclient.Result, error) {
|
||||
_, err = c.Build(ctx, client.SolveOpt{Session: session, Internal: true}, "buildx", func(ctx context.Context, c gwclient.Client) (*gwclient.Result, error) {
|
||||
def, err := st.Marshal(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
414
build/build.go
414
build/build.go
@@ -23,9 +23,9 @@ import (
|
||||
"github.com/containerd/containerd/content/local"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/buildx/builder"
|
||||
"github.com/docker/buildx/driver"
|
||||
"github.com/docker/buildx/localstate"
|
||||
"github.com/docker/buildx/util/desktop"
|
||||
"github.com/docker/buildx/util/dockerutil"
|
||||
"github.com/docker/buildx/util/imagetools"
|
||||
@@ -33,7 +33,6 @@ import (
|
||||
"github.com/docker/buildx/util/resolver"
|
||||
"github.com/docker/buildx/util/waitmap"
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/builder/remotecontext/urlutil"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
@@ -66,12 +65,14 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
//nolint:gosec // G101: false-positive
|
||||
printFallbackImage = "docker/dockerfile:1.5.2-labs@sha256:f2e91734a84c0922ff47aa4098ab775f1dfa932430d2888dd5cad5251fafdac4"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Inputs Inputs
|
||||
|
||||
Ref string
|
||||
Allow []entitlements.Entitlement
|
||||
Attests map[string]*string
|
||||
BuildArgs map[string]string
|
||||
@@ -91,12 +92,11 @@ type Options struct {
|
||||
Target string
|
||||
Ulimits *opts.UlimitOpt
|
||||
|
||||
Session []session.Attachable
|
||||
|
||||
// Linked marks this target as exclusively linked (not requested by the user).
|
||||
Linked bool
|
||||
Session []session.Attachable
|
||||
Linked bool // Linked marks this target as exclusively linked (not requested by the user).
|
||||
PrintFunc *PrintFunc
|
||||
SourcePolicy *spb.Policy
|
||||
GroupRef string
|
||||
}
|
||||
|
||||
type PrintFunc struct {
|
||||
@@ -135,218 +135,6 @@ func filterAvailableNodes(nodes []builder.Node) ([]builder.Node, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
type driverPair struct {
|
||||
driverIndex int
|
||||
platforms []specs.Platform
|
||||
so *client.SolveOpt
|
||||
bopts gateway.BuildOpts
|
||||
}
|
||||
|
||||
func driverIndexes(m map[string][]driverPair) []int {
|
||||
out := make([]int, 0, len(m))
|
||||
visited := map[int]struct{}{}
|
||||
for _, dp := range m {
|
||||
for _, d := range dp {
|
||||
if _, ok := visited[d.driverIndex]; ok {
|
||||
continue
|
||||
}
|
||||
visited[d.driverIndex] = struct{}{}
|
||||
out = append(out, d.driverIndex)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func allIndexes(l int) []int {
|
||||
out := make([]int, 0, l)
|
||||
for i := 0; i < l; i++ {
|
||||
out = append(out, i)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func ensureBooted(ctx context.Context, nodes []builder.Node, idxs []int, pw progress.Writer) ([]*client.Client, error) {
|
||||
clients := make([]*client.Client, len(nodes))
|
||||
|
||||
baseCtx := ctx
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
for _, i := range idxs {
|
||||
func(i int) {
|
||||
eg.Go(func() error {
|
||||
c, err := driver.Boot(ctx, baseCtx, nodes[i].Driver, pw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clients[i] = c
|
||||
return nil
|
||||
})
|
||||
}(i)
|
||||
}
|
||||
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return clients, nil
|
||||
}
|
||||
|
||||
func splitToDriverPairs(availablePlatforms map[string]int, opt map[string]Options) map[string][]driverPair {
|
||||
m := map[string][]driverPair{}
|
||||
for k, opt := range opt {
|
||||
mm := map[int][]specs.Platform{}
|
||||
for _, p := range opt.Platforms {
|
||||
k := platforms.Format(p)
|
||||
idx := availablePlatforms[k] // default 0
|
||||
pp := mm[idx]
|
||||
pp = append(pp, p)
|
||||
mm[idx] = pp
|
||||
}
|
||||
// if no platform is specified, use first driver
|
||||
if len(mm) == 0 {
|
||||
mm[0] = nil
|
||||
}
|
||||
dps := make([]driverPair, 0, 2)
|
||||
for idx, pp := range mm {
|
||||
dps = append(dps, driverPair{driverIndex: idx, platforms: pp})
|
||||
}
|
||||
m[k] = dps
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func resolveDrivers(ctx context.Context, nodes []builder.Node, opt map[string]Options, pw progress.Writer) (map[string][]driverPair, []*client.Client, error) {
|
||||
dps, clients, err := resolveDriversBase(ctx, nodes, opt, pw)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
bopts := make([]gateway.BuildOpts, len(clients))
|
||||
|
||||
span, ctx := tracing.StartSpan(ctx, "load buildkit capabilities", trace.WithSpanKind(trace.SpanKindInternal))
|
||||
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
for i, c := range clients {
|
||||
if c == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
func(i int, c *client.Client) {
|
||||
eg.Go(func() error {
|
||||
clients[i].Build(ctx, client.SolveOpt{
|
||||
Internal: true,
|
||||
}, "buildx", func(ctx context.Context, c gateway.Client) (*gateway.Result, error) {
|
||||
bopts[i] = c.BuildOpts()
|
||||
return nil, nil
|
||||
}, nil)
|
||||
return nil
|
||||
})
|
||||
}(i, c)
|
||||
}
|
||||
|
||||
err = eg.Wait()
|
||||
tracing.FinishWithError(span, err)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for key := range dps {
|
||||
for i, dp := range dps[key] {
|
||||
dps[key][i].bopts = bopts[dp.driverIndex]
|
||||
}
|
||||
}
|
||||
|
||||
return dps, clients, nil
|
||||
}
|
||||
|
||||
func resolveDriversBase(ctx context.Context, nodes []builder.Node, opt map[string]Options, pw progress.Writer) (map[string][]driverPair, []*client.Client, error) {
|
||||
availablePlatforms := map[string]int{}
|
||||
for i, node := range nodes {
|
||||
for _, p := range node.Platforms {
|
||||
availablePlatforms[platforms.Format(p)] = i
|
||||
}
|
||||
}
|
||||
|
||||
undetectedPlatform := false
|
||||
allPlatforms := map[string]int{}
|
||||
for _, opt := range opt {
|
||||
for _, p := range opt.Platforms {
|
||||
k := platforms.Format(p)
|
||||
allPlatforms[k] = -1
|
||||
if _, ok := availablePlatforms[k]; !ok {
|
||||
undetectedPlatform = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fast path
|
||||
if len(nodes) == 1 || len(allPlatforms) == 0 {
|
||||
m := map[string][]driverPair{}
|
||||
for k, opt := range opt {
|
||||
m[k] = []driverPair{{driverIndex: 0, platforms: opt.Platforms}}
|
||||
}
|
||||
clients, err := ensureBooted(ctx, nodes, driverIndexes(m), pw)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return m, clients, nil
|
||||
}
|
||||
|
||||
// map based on existing platforms
|
||||
if !undetectedPlatform {
|
||||
m := splitToDriverPairs(availablePlatforms, opt)
|
||||
clients, err := ensureBooted(ctx, nodes, driverIndexes(m), pw)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return m, clients, nil
|
||||
}
|
||||
|
||||
// boot all drivers in k
|
||||
clients, err := ensureBooted(ctx, nodes, allIndexes(len(nodes)), pw)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
workers := make([][]*client.WorkerInfo, len(clients))
|
||||
|
||||
for i, c := range clients {
|
||||
if c == nil {
|
||||
continue
|
||||
}
|
||||
func(i int) {
|
||||
eg.Go(func() error {
|
||||
ww, err := clients[i].ListWorkers(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "listing workers")
|
||||
}
|
||||
workers[i] = ww
|
||||
return nil
|
||||
})
|
||||
|
||||
}(i)
|
||||
}
|
||||
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for i, ww := range workers {
|
||||
for _, w := range ww {
|
||||
for _, p := range w.Platforms {
|
||||
p = platforms.Normalize(p)
|
||||
ps := platforms.Format(p)
|
||||
|
||||
if _, ok := availablePlatforms[ps]; !ok {
|
||||
availablePlatforms[ps] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return splitToDriverPairs(availablePlatforms, opt), clients, nil
|
||||
}
|
||||
|
||||
func toRepoOnly(in string) (string, error) {
|
||||
m := map[string]struct{}{}
|
||||
p := strings.Split(in, ",")
|
||||
@@ -391,7 +179,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
|
||||
|
||||
for _, e := range opt.CacheTo {
|
||||
if e.Type != "inline" && !nodeDriver.Features(ctx)[driver.CacheExport] {
|
||||
return nil, nil, notSupported(nodeDriver, driver.CacheExport)
|
||||
return nil, nil, notSupported(driver.CacheExport, nodeDriver, "https://docs.docker.com/go/build-cache-backends/")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,6 +212,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
|
||||
}
|
||||
|
||||
so := client.SolveOpt{
|
||||
Ref: opt.Ref,
|
||||
Frontend: "dockerfile.v0",
|
||||
FrontendAttrs: map[string]string{},
|
||||
LocalDirs: map[string]string{},
|
||||
@@ -433,6 +222,10 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
|
||||
SourcePolicy: opt.SourcePolicy,
|
||||
}
|
||||
|
||||
if so.Ref == "" {
|
||||
so.Ref = identity.NewID()
|
||||
}
|
||||
|
||||
if opt.CgroupParent != "" {
|
||||
so.FrontendAttrs["cgroup-parent"] = opt.CgroupParent
|
||||
}
|
||||
@@ -454,7 +247,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
|
||||
attests[k] = *v
|
||||
}
|
||||
}
|
||||
supportsAttestations := bopts.LLBCaps.Contains(apicaps.CapID("exporter.image.attestations"))
|
||||
supportsAttestations := bopts.LLBCaps.Contains(apicaps.CapID("exporter.image.attestations")) && nodeDriver.Features(ctx)[driver.MultiPlatform]
|
||||
if len(attests) > 0 {
|
||||
if !supportsAttestations {
|
||||
return nil, nil, errors.Errorf("attestations are not supported by the current buildkitd")
|
||||
@@ -529,7 +322,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
|
||||
// set up exporters
|
||||
for i, e := range opt.Exports {
|
||||
if e.Type == "oci" && !nodeDriver.Features(ctx)[driver.OCIExporter] {
|
||||
return nil, nil, notSupported(nodeDriver, driver.OCIExporter)
|
||||
return nil, nil, notSupported(driver.OCIExporter, nodeDriver, "https://docs.docker.com/go/build-exporters/")
|
||||
}
|
||||
if e.Type == "docker" {
|
||||
features := docker.Features(ctx, e.Attrs["context"])
|
||||
@@ -552,10 +345,12 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
|
||||
return nil, nil, err
|
||||
}
|
||||
defers = append(defers, cancel)
|
||||
opt.Exports[i].Output = wrapWriteCloser(w)
|
||||
opt.Exports[i].Output = func(_ map[string]string) (io.WriteCloser, error) {
|
||||
return w, nil
|
||||
}
|
||||
}
|
||||
} else if !nodeDriver.Features(ctx)[driver.DockerExporter] {
|
||||
return nil, nil, notSupported(nodeDriver, driver.DockerExporter)
|
||||
return nil, nil, notSupported(driver.DockerExporter, nodeDriver, "https:/docs.docker.com/go/build-exporters/")
|
||||
}
|
||||
}
|
||||
if e.Type == "image" && nodeDriver.IsMobyDriver() {
|
||||
@@ -593,7 +388,10 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
|
||||
}
|
||||
|
||||
if opt.Pull {
|
||||
so.FrontendAttrs["image-resolve-mode"] = "pull"
|
||||
so.FrontendAttrs["image-resolve-mode"] = pb.AttrImageResolveModeForcePull
|
||||
} else if nodeDriver.IsMobyDriver() {
|
||||
// moby driver always resolves local images by default
|
||||
so.FrontendAttrs["image-resolve-mode"] = pb.AttrImageResolveModePreferLocal
|
||||
}
|
||||
if opt.Target != "" {
|
||||
so.FrontendAttrs["target"] = opt.Target
|
||||
@@ -624,7 +422,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
|
||||
pp[i] = platforms.Format(p)
|
||||
}
|
||||
if len(pp) > 1 && !nodeDriver.Features(ctx)[driver.MultiPlatform] {
|
||||
return nil, nil, notSupported(nodeDriver, driver.MultiPlatform)
|
||||
return nil, nil, notSupported(driver.MultiPlatform, nodeDriver, "https://docs.docker.com/go/build-multi-platform/")
|
||||
}
|
||||
so.FrontendAttrs["platform"] = strings.Join(pp, ",")
|
||||
}
|
||||
@@ -642,7 +440,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
|
||||
}
|
||||
|
||||
// setup extrahosts
|
||||
extraHosts, err := toBuildkitExtraHosts(opt.ExtraHosts, nodeDriver.IsMobyDriver())
|
||||
extraHosts, err := toBuildkitExtraHosts(ctx, opt.ExtraHosts, nodeDriver)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -663,12 +461,6 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
|
||||
so.FrontendAttrs["ulimit"] = ulimits
|
||||
}
|
||||
|
||||
// remember local state like directory path that is not sent to buildkit
|
||||
so.Ref = identity.NewID()
|
||||
if err := saveLocalState(so, opt, node, configDir); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &so, releaseF, nil
|
||||
}
|
||||
|
||||
@@ -713,10 +505,14 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
||||
}
|
||||
}
|
||||
|
||||
m, clients, err := resolveDrivers(ctx, nodes, opt, w)
|
||||
drivers, err := resolveDrivers(ctx, nodes, opt, w)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
driversSolveOpts := make(map[string][]*client.SolveOpt, len(drivers))
|
||||
for k, dps := range drivers {
|
||||
driversSolveOpts[k] = make([]*client.SolveOpt, len(dps))
|
||||
}
|
||||
|
||||
defers := make([]func(), 0, 2)
|
||||
defer func() {
|
||||
@@ -730,27 +526,33 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
for k, opt := range opt {
|
||||
multiDriver := len(m[k]) > 1
|
||||
multiDriver := len(drivers[k]) > 1
|
||||
hasMobyDriver := false
|
||||
gitattrs, err := getGitAttributes(ctx, opt.Inputs.ContextPath, opt.Inputs.DockerfilePath)
|
||||
if err != nil {
|
||||
logrus.Warn(err)
|
||||
logrus.WithError(err).Warn("current commit information was not captured by the build")
|
||||
}
|
||||
for i, np := range m[k] {
|
||||
node := nodes[np.driverIndex]
|
||||
if node.Driver.IsMobyDriver() {
|
||||
for i, np := range drivers[k] {
|
||||
if np.Node().Driver.IsMobyDriver() {
|
||||
hasMobyDriver = true
|
||||
}
|
||||
opt.Platforms = np.platforms
|
||||
so, release, err := toSolveOpt(ctx, node, multiDriver, opt, np.bopts, configDir, w, docker)
|
||||
gatewayOpts, err := np.BuildOpts(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
so, release, err := toSolveOpt(ctx, np.Node(), multiDriver, opt, gatewayOpts, configDir, w, docker)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := saveLocalState(so, k, opt, np.Node(), configDir); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range gitattrs {
|
||||
so.FrontendAttrs[k] = v
|
||||
}
|
||||
defers = append(defers, release)
|
||||
m[k][i].so = so
|
||||
driversSolveOpts[k][i] = so
|
||||
}
|
||||
for _, at := range opt.Session {
|
||||
if s, ok := at.(interface {
|
||||
@@ -764,8 +566,8 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
||||
|
||||
// validate for multi-node push
|
||||
if hasMobyDriver && multiDriver {
|
||||
for _, dp := range m[k] {
|
||||
for _, e := range dp.so.Exports {
|
||||
for _, so := range driversSolveOpts[k] {
|
||||
for _, e := range so.Exports {
|
||||
if e.Type == "moby" {
|
||||
if ok, _ := strconv.ParseBool(e.Attrs["push"]); ok {
|
||||
return nil, errors.Errorf("multi-node push can't currently be performed with the docker driver, please switch to a different driver")
|
||||
@@ -778,12 +580,13 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
||||
|
||||
// validate that all links between targets use same drivers
|
||||
for name := range opt {
|
||||
dps := m[name]
|
||||
for _, dp := range dps {
|
||||
for k, v := range dp.so.FrontendAttrs {
|
||||
dps := drivers[name]
|
||||
for i, dp := range dps {
|
||||
so := driversSolveOpts[name][i]
|
||||
for k, v := range so.FrontendAttrs {
|
||||
if strings.HasPrefix(k, "context:") && strings.HasPrefix(v, "target:") {
|
||||
k2 := strings.TrimPrefix(v, "target:")
|
||||
dps2, ok := m[k2]
|
||||
dps2, ok := drivers[k2]
|
||||
if !ok {
|
||||
return nil, errors.Errorf("failed to find target %s for context %s", k2, strings.TrimPrefix(k, "context:")) // should be validated before already
|
||||
}
|
||||
@@ -807,12 +610,13 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
||||
results := waitmap.New()
|
||||
|
||||
multiTarget := len(opt) > 1
|
||||
childTargets := calculateChildTargets(drivers, driversSolveOpts, opt)
|
||||
|
||||
for k, opt := range opt {
|
||||
err := func(k string) error {
|
||||
opt := opt
|
||||
dps := m[k]
|
||||
multiDriver := len(m[k]) > 1
|
||||
dps := drivers[k]
|
||||
multiDriver := len(drivers[k]) > 1
|
||||
|
||||
var span trace.Span
|
||||
ctx := ctx
|
||||
@@ -828,8 +632,9 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
||||
var insecurePush bool
|
||||
|
||||
for i, dp := range dps {
|
||||
i, dp, so := i, dp, *dp.so
|
||||
node := nodes[dp.driverIndex]
|
||||
i, dp := i, dp
|
||||
node := dp.Node()
|
||||
so := driversSolveOpts[k][i]
|
||||
if multiDriver {
|
||||
for i, e := range so.Exports {
|
||||
switch e.Type {
|
||||
@@ -860,11 +665,14 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
||||
|
||||
pw := progress.WithPrefix(w, k, multiTarget)
|
||||
|
||||
c := clients[dp.driverIndex]
|
||||
c, err := dp.Client(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
eg2.Go(func() error {
|
||||
pw = progress.ResetTime(pw)
|
||||
|
||||
if err := waitContextDeps(ctx, dp.driverIndex, results, &so); err != nil {
|
||||
if err := waitContextDeps(ctx, dp.driverIndex, results, so); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -937,16 +745,35 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
||||
printRes = res.Metadata
|
||||
}
|
||||
|
||||
results.Set(resultKey(dp.driverIndex, k), res)
|
||||
rKey := resultKey(dp.driverIndex, k)
|
||||
results.Set(rKey, res)
|
||||
|
||||
if children, ok := childTargets[rKey]; ok && len(children) > 0 {
|
||||
// we need to wait until the child targets have completed before we can release
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
eg.Go(func() error {
|
||||
return res.EachRef(func(ref gateway.Reference) error {
|
||||
return ref.Evaluate(ctx)
|
||||
})
|
||||
})
|
||||
eg.Go(func() error {
|
||||
_, err := results.Get(ctx, children...)
|
||||
return err
|
||||
})
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
var rr *client.SolveResponse
|
||||
if resultHandleFunc != nil {
|
||||
var resultHandle *ResultHandle
|
||||
resultHandle, rr, err = NewResultHandle(ctx, cc, so, "buildx", buildFunc, ch)
|
||||
resultHandle, rr, err = NewResultHandle(ctx, cc, *so, "buildx", buildFunc, ch)
|
||||
resultHandleFunc(dp.driverIndex, resultHandle)
|
||||
} else {
|
||||
rr, err = c.Build(ctx, so, "buildx", buildFunc, ch)
|
||||
rr, err = c.Build(ctx, *so, "buildx", buildFunc, ch)
|
||||
}
|
||||
if desktop.BuildBackendEnabled() && node.Driver.HistoryAPISupported(ctx) {
|
||||
buildRef := fmt.Sprintf("%s/%s/%s", node.Builder, node.Name, so.Ref)
|
||||
@@ -970,7 +797,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
||||
rr.ExporterResponse[k] = string(v)
|
||||
}
|
||||
|
||||
node := nodes[dp.driverIndex].Driver
|
||||
node := dp.Node().Driver
|
||||
if node.IsMobyDriver() {
|
||||
for _, e := range so.Exports {
|
||||
if e.Type == "moby" && e.Attrs["push"] != "" {
|
||||
@@ -1062,7 +889,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
||||
if len(descs) > 0 {
|
||||
var imageopt imagetools.Opt
|
||||
for _, dp := range dps {
|
||||
imageopt = nodes[dp.driverIndex].ImageOpt
|
||||
imageopt = dp.Node().ImageOpt
|
||||
break
|
||||
}
|
||||
names := strings.Split(pushNames, ",")
|
||||
@@ -1098,7 +925,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
||||
}
|
||||
}
|
||||
|
||||
dt, desc, err := itpull.Combine(ctx, srcs)
|
||||
dt, desc, err := itpull.Combine(ctx, srcs, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1325,6 +1152,10 @@ func LoadInputs(ctx context.Context, d *driver.DriverHandle, inp Inputs, pw prog
|
||||
case IsRemoteURL(inp.ContextPath):
|
||||
if inp.DockerfilePath == "-" {
|
||||
dockerfileReader = inp.InStream
|
||||
} else if filepath.IsAbs(inp.DockerfilePath) {
|
||||
dockerfileDir = filepath.Dir(inp.DockerfilePath)
|
||||
dockerfileName = filepath.Base(inp.DockerfilePath)
|
||||
target.FrontendAttrs["dockerfilekey"] = "dockerfile"
|
||||
}
|
||||
target.FrontendAttrs["context"] = inp.ContextPath
|
||||
default:
|
||||
@@ -1471,6 +1302,24 @@ func resultKey(index int, name string) string {
|
||||
return fmt.Sprintf("%d-%s", index, name)
|
||||
}
|
||||
|
||||
// calculateChildTargets returns all the targets that depend on current target for reverse index
|
||||
func calculateChildTargets(drivers map[string][]*resolvedNode, driversSolveOpts map[string][]*client.SolveOpt, opt map[string]Options) map[string][]string {
|
||||
out := make(map[string][]string)
|
||||
for name := range opt {
|
||||
dps := drivers[name]
|
||||
for i, dp := range dps {
|
||||
so := driversSolveOpts[name][i]
|
||||
for k, v := range so.FrontendAttrs {
|
||||
if strings.HasPrefix(k, "context:") && strings.HasPrefix(v, "target:") {
|
||||
target := resultKey(dp.driverIndex, strings.TrimPrefix(v, "target:"))
|
||||
out[target] = append(out[target], resultKey(dp.driverIndex, name))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func waitContextDeps(ctx context.Context, index int, results *waitmap.Map, so *client.SolveOpt) error {
|
||||
m := map[string]string{}
|
||||
for k, v := range so.FrontendAttrs {
|
||||
@@ -1557,8 +1406,10 @@ func waitContextDeps(ctx context.Context, index int, results *waitmap.Map, so *c
|
||||
return nil
|
||||
}
|
||||
|
||||
func notSupported(d driver.Driver, f driver.Feature) error {
|
||||
return errors.Errorf("%s feature is currently not supported for %s driver. Please switch to a different driver (eg. \"docker buildx create --use\")", f, d.Factory().Name())
|
||||
func notSupported(f driver.Feature, d driver.Driver, docs string) error {
|
||||
return errors.Errorf(`%s is not supported for the %s driver.
|
||||
Switch to a different driver, or turn on the containerd image store, and try again.
|
||||
Learn more at %s`, f, d.Factory().Name(), docs)
|
||||
}
|
||||
|
||||
func noDefaultLoad() bool {
|
||||
@@ -1604,12 +1455,6 @@ func handleLowercaseDockerfile(dir, p string) string {
|
||||
return p
|
||||
}
|
||||
|
||||
func wrapWriteCloser(wc io.WriteCloser) func(map[string]string) (io.WriteCloser, error) {
|
||||
return func(map[string]string) (io.WriteCloser, error) {
|
||||
return wc, nil
|
||||
}
|
||||
}
|
||||
|
||||
var nodeIdentifierMu sync.Mutex
|
||||
|
||||
func tryNodeIdentifier(configDir string) (out string) {
|
||||
@@ -1644,43 +1489,6 @@ func noPrintFunc(opt map[string]Options) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func saveLocalState(so client.SolveOpt, opt Options, node builder.Node, configDir string) error {
|
||||
var err error
|
||||
|
||||
if so.Ref == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
lp := opt.Inputs.ContextPath
|
||||
dp := opt.Inputs.DockerfilePath
|
||||
if lp != "" || dp != "" {
|
||||
if lp != "" {
|
||||
lp, err = filepath.Abs(lp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if dp != "" {
|
||||
dp, err = filepath.Abs(dp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
ls, err := localstate.New(configDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ls.SaveRef(node.Builder, node.Name, so.Ref, localstate.State{
|
||||
LocalPath: lp,
|
||||
DockerfilePath: dp,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadSourcePolicy reads a source policy from a file.
|
||||
// The file path is taken from EXPERIMENTAL_BUILDKIT_SOURCE_POLICY env var.
|
||||
// if the env var is not set, this `returns nil, nil`
|
||||
|
305
build/driver.go
Normal file
305
build/driver.go
Normal file
@@ -0,0 +1,305 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/docker/buildx/builder"
|
||||
"github.com/docker/buildx/driver"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/moby/buildkit/client"
|
||||
gateway "github.com/moby/buildkit/frontend/gateway/client"
|
||||
"github.com/moby/buildkit/util/flightcontrol"
|
||||
"github.com/moby/buildkit/util/tracing"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
type resolvedNode struct {
|
||||
resolver *nodeResolver
|
||||
driverIndex int
|
||||
platforms []specs.Platform
|
||||
}
|
||||
|
||||
func (dp resolvedNode) Node() builder.Node {
|
||||
return dp.resolver.nodes[dp.driverIndex]
|
||||
}
|
||||
|
||||
func (dp resolvedNode) Client(ctx context.Context) (*client.Client, error) {
|
||||
clients, err := dp.resolver.boot(ctx, []int{dp.driverIndex}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return clients[0], nil
|
||||
}
|
||||
|
||||
func (dp resolvedNode) BuildOpts(ctx context.Context) (gateway.BuildOpts, error) {
|
||||
opts, err := dp.resolver.opts(ctx, []int{dp.driverIndex}, nil)
|
||||
if err != nil {
|
||||
return gateway.BuildOpts{}, err
|
||||
}
|
||||
return opts[0], nil
|
||||
}
|
||||
|
||||
type matchMaker func(specs.Platform) platforms.MatchComparer
|
||||
|
||||
type nodeResolver struct {
|
||||
nodes []builder.Node
|
||||
clients flightcontrol.Group[*client.Client]
|
||||
opt flightcontrol.Group[gateway.BuildOpts]
|
||||
}
|
||||
|
||||
func resolveDrivers(ctx context.Context, nodes []builder.Node, opt map[string]Options, pw progress.Writer) (map[string][]*resolvedNode, error) {
|
||||
driverRes := newDriverResolver(nodes)
|
||||
drivers, err := driverRes.Resolve(ctx, opt, pw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return drivers, err
|
||||
}
|
||||
|
||||
func newDriverResolver(nodes []builder.Node) *nodeResolver {
|
||||
r := &nodeResolver{
|
||||
nodes: nodes,
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *nodeResolver) Resolve(ctx context.Context, opt map[string]Options, pw progress.Writer) (map[string][]*resolvedNode, error) {
|
||||
if len(r.nodes) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nodes := map[string][]*resolvedNode{}
|
||||
for k, opt := range opt {
|
||||
node, perfect, err := r.resolve(ctx, opt.Platforms, pw, platforms.OnlyStrict, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !perfect {
|
||||
break
|
||||
}
|
||||
nodes[k] = node
|
||||
}
|
||||
if len(nodes) != len(opt) {
|
||||
// if we didn't get a perfect match, we need to boot all drivers
|
||||
allIndexes := make([]int, len(r.nodes))
|
||||
for i := range allIndexes {
|
||||
allIndexes[i] = i
|
||||
}
|
||||
|
||||
clients, err := r.boot(ctx, allIndexes, pw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
eg, egCtx := errgroup.WithContext(ctx)
|
||||
workers := make([][]specs.Platform, len(clients))
|
||||
for i, c := range clients {
|
||||
i, c := i, c
|
||||
if c == nil {
|
||||
continue
|
||||
}
|
||||
eg.Go(func() error {
|
||||
ww, err := c.ListWorkers(egCtx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "listing workers")
|
||||
}
|
||||
|
||||
ps := make(map[string]specs.Platform, len(ww))
|
||||
for _, w := range ww {
|
||||
for _, p := range w.Platforms {
|
||||
pk := platforms.Format(platforms.Normalize(p))
|
||||
ps[pk] = p
|
||||
}
|
||||
}
|
||||
for _, p := range ps {
|
||||
workers[i] = append(workers[i], p)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// then we can attempt to match against all the available platforms
|
||||
// (this time we don't care about imperfect matches)
|
||||
nodes = map[string][]*resolvedNode{}
|
||||
for k, opt := range opt {
|
||||
node, _, err := r.resolve(ctx, opt.Platforms, pw, platforms.Only, func(idx int, n builder.Node) []specs.Platform {
|
||||
return workers[idx]
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodes[k] = node
|
||||
}
|
||||
}
|
||||
|
||||
idxs := make([]int, 0, len(r.nodes))
|
||||
for _, nodes := range nodes {
|
||||
for _, node := range nodes {
|
||||
idxs = append(idxs, node.driverIndex)
|
||||
}
|
||||
}
|
||||
|
||||
// preload capabilities
|
||||
span, ctx := tracing.StartSpan(ctx, "load buildkit capabilities", trace.WithSpanKind(trace.SpanKindInternal))
|
||||
_, err := r.opts(ctx, idxs, pw)
|
||||
tracing.FinishWithError(span, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func (r *nodeResolver) resolve(ctx context.Context, ps []specs.Platform, pw progress.Writer, matcher matchMaker, additional func(idx int, n builder.Node) []specs.Platform) ([]*resolvedNode, bool, error) {
|
||||
if len(r.nodes) == 0 {
|
||||
return nil, true, nil
|
||||
}
|
||||
|
||||
if len(ps) == 0 {
|
||||
ps = []specs.Platform{platforms.DefaultSpec()}
|
||||
}
|
||||
|
||||
perfect := true
|
||||
nodeIdxs := make([]int, 0)
|
||||
for _, p := range ps {
|
||||
idx := r.get(p, matcher, additional)
|
||||
if idx == -1 {
|
||||
idx = 0
|
||||
perfect = false
|
||||
}
|
||||
nodeIdxs = append(nodeIdxs, idx)
|
||||
}
|
||||
|
||||
var nodes []*resolvedNode
|
||||
for i, idx := range nodeIdxs {
|
||||
nodes = append(nodes, &resolvedNode{
|
||||
resolver: r,
|
||||
driverIndex: idx,
|
||||
platforms: []specs.Platform{ps[i]},
|
||||
})
|
||||
}
|
||||
nodes = recombineNodes(nodes)
|
||||
if _, err := r.boot(ctx, nodeIdxs, pw); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return nodes, perfect, nil
|
||||
}
|
||||
|
||||
func (r *nodeResolver) get(p specs.Platform, matcher matchMaker, additionalPlatforms func(int, builder.Node) []specs.Platform) int {
|
||||
best := -1
|
||||
bestPlatform := specs.Platform{}
|
||||
for i, node := range r.nodes {
|
||||
platforms := node.Platforms
|
||||
if additionalPlatforms != nil {
|
||||
platforms = append([]specs.Platform{}, platforms...)
|
||||
platforms = append(platforms, additionalPlatforms(i, node)...)
|
||||
}
|
||||
for _, p2 := range platforms {
|
||||
m := matcher(p2)
|
||||
if !m.Match(p) {
|
||||
continue
|
||||
}
|
||||
|
||||
if best == -1 {
|
||||
best = i
|
||||
bestPlatform = p2
|
||||
continue
|
||||
}
|
||||
if matcher(p2).Less(p, bestPlatform) {
|
||||
best = i
|
||||
bestPlatform = p2
|
||||
}
|
||||
}
|
||||
}
|
||||
return best
|
||||
}
|
||||
|
||||
func (r *nodeResolver) boot(ctx context.Context, idxs []int, pw progress.Writer) ([]*client.Client, error) {
|
||||
clients := make([]*client.Client, len(idxs))
|
||||
|
||||
baseCtx := ctx
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
for i, idx := range idxs {
|
||||
i, idx := i, idx
|
||||
eg.Go(func() error {
|
||||
c, err := r.clients.Do(ctx, fmt.Sprint(idx), func(ctx context.Context) (*client.Client, error) {
|
||||
if r.nodes[idx].Driver == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return driver.Boot(ctx, baseCtx, r.nodes[idx].Driver, pw)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clients[i] = c
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return clients, nil
|
||||
}
|
||||
|
||||
func (r *nodeResolver) opts(ctx context.Context, idxs []int, pw progress.Writer) ([]gateway.BuildOpts, error) {
|
||||
clients, err := r.boot(ctx, idxs, pw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bopts := make([]gateway.BuildOpts, len(clients))
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
for i, idxs := range idxs {
|
||||
i, idx := i, idxs
|
||||
c := clients[i]
|
||||
if c == nil {
|
||||
continue
|
||||
}
|
||||
eg.Go(func() error {
|
||||
opt, err := r.opt.Do(ctx, fmt.Sprint(idx), func(ctx context.Context) (gateway.BuildOpts, error) {
|
||||
opt := gateway.BuildOpts{}
|
||||
_, err := c.Build(ctx, client.SolveOpt{
|
||||
Internal: true,
|
||||
}, "buildx", func(ctx context.Context, c gateway.Client) (*gateway.Result, error) {
|
||||
opt = c.BuildOpts()
|
||||
return nil, nil
|
||||
}, nil)
|
||||
return opt, err
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bopts[i] = opt
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bopts, nil
|
||||
}
|
||||
|
||||
// recombineDriverPairs recombines resolved nodes that are on the same driver
|
||||
// back together into a single node.
|
||||
func recombineNodes(nodes []*resolvedNode) []*resolvedNode {
|
||||
result := make([]*resolvedNode, 0, len(nodes))
|
||||
lookup := map[int]int{}
|
||||
for _, node := range nodes {
|
||||
if idx, ok := lookup[node.driverIndex]; ok {
|
||||
result[idx].platforms = append(result[idx].platforms, node.platforms...)
|
||||
} else {
|
||||
lookup[node.driverIndex] = len(result)
|
||||
result = append(result, node)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
313
build/driver_test.go
Normal file
313
build/driver_test.go
Normal file
@@ -0,0 +1,313 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/docker/buildx/builder"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFindDriverSanity(t *testing.T) {
|
||||
r := makeTestResolver(map[string][]specs.Platform{
|
||||
"aaa": {platforms.DefaultSpec()},
|
||||
})
|
||||
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.DefaultSpec()}, nil, platforms.OnlyStrict, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, 0, res[0].driverIndex)
|
||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
||||
}
|
||||
|
||||
func TestFindDriverEmpty(t *testing.T) {
|
||||
r := makeTestResolver(nil)
|
||||
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.DefaultSpec()}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Nil(t, res)
|
||||
}
|
||||
|
||||
func TestFindDriverWeirdName(t *testing.T) {
|
||||
r := makeTestResolver(map[string][]specs.Platform{
|
||||
"aaa": {platforms.MustParse("linux/amd64")},
|
||||
"bbb": {platforms.MustParse("linux/foobar")},
|
||||
})
|
||||
|
||||
// find first platform
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/foobar")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, 1, res[0].driverIndex)
|
||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
||||
}
|
||||
|
||||
func TestFindDriverUnknown(t *testing.T) {
|
||||
r := makeTestResolver(map[string][]specs.Platform{
|
||||
"aaa": {platforms.MustParse("linux/amd64")},
|
||||
})
|
||||
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.False(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, 0, res[0].driverIndex)
|
||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
||||
}
|
||||
|
||||
func TestSelectNodeSinglePlatform(t *testing.T) {
|
||||
r := makeTestResolver(map[string][]specs.Platform{
|
||||
"aaa": {platforms.MustParse("linux/amd64")},
|
||||
"bbb": {platforms.MustParse("linux/riscv64")},
|
||||
})
|
||||
|
||||
// find first platform
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/amd64")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, 0, res[0].driverIndex)
|
||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
||||
|
||||
// find second platform
|
||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, 1, res[0].driverIndex)
|
||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
||||
|
||||
// find an unknown platform, should match the first driver
|
||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/s390x")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.False(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, 0, res[0].driverIndex)
|
||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
||||
}
|
||||
|
||||
func TestSelectNodeMultiPlatform(t *testing.T) {
|
||||
r := makeTestResolver(map[string][]specs.Platform{
|
||||
"aaa": {platforms.MustParse("linux/amd64"), platforms.MustParse("linux/arm64")},
|
||||
"bbb": {platforms.MustParse("linux/riscv64")},
|
||||
})
|
||||
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/amd64")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, 0, res[0].driverIndex)
|
||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
||||
|
||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm64")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, 0, res[0].driverIndex)
|
||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
||||
|
||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, 1, res[0].driverIndex)
|
||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
||||
}
|
||||
|
||||
func TestSelectNodeNonStrict(t *testing.T) {
|
||||
r := makeTestResolver(map[string][]specs.Platform{
|
||||
"aaa": {platforms.MustParse("linux/amd64")},
|
||||
"bbb": {platforms.MustParse("linux/arm64")},
|
||||
})
|
||||
|
||||
// arm64 should match itself
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm64")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
||||
|
||||
// arm64 may support arm/v8
|
||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v8")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
||||
|
||||
// arm64 may support arm/v7
|
||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
||||
}
|
||||
|
||||
func TestSelectNodeNonStrictARM(t *testing.T) {
|
||||
r := makeTestResolver(map[string][]specs.Platform{
|
||||
"aaa": {platforms.MustParse("linux/amd64")},
|
||||
"bbb": {platforms.MustParse("linux/arm64")},
|
||||
"ccc": {platforms.MustParse("linux/arm/v8")},
|
||||
})
|
||||
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v8")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, "ccc", res[0].Node().Builder)
|
||||
|
||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, "ccc", res[0].Node().Builder)
|
||||
}
|
||||
|
||||
func TestSelectNodeNonStrictLower(t *testing.T) {
|
||||
r := makeTestResolver(map[string][]specs.Platform{
|
||||
"aaa": {platforms.MustParse("linux/amd64")},
|
||||
"bbb": {platforms.MustParse("linux/arm/v7")},
|
||||
})
|
||||
|
||||
// v8 can't be built on v7 (so we should select the default)...
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v8")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.False(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
||||
|
||||
// ...but v6 can be built on v8
|
||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v6")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
||||
}
|
||||
|
||||
func TestSelectNodePreferStart(t *testing.T) {
|
||||
r := makeTestResolver(map[string][]specs.Platform{
|
||||
"aaa": {platforms.MustParse("linux/amd64")},
|
||||
"bbb": {platforms.MustParse("linux/riscv64")},
|
||||
"ccc": {platforms.MustParse("linux/riscv64")},
|
||||
})
|
||||
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
||||
}
|
||||
|
||||
func TestSelectNodePreferExact(t *testing.T) {
|
||||
r := makeTestResolver(map[string][]specs.Platform{
|
||||
"aaa": {platforms.MustParse("linux/arm/v8")},
|
||||
"bbb": {platforms.MustParse("linux/arm/v7")},
|
||||
})
|
||||
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
||||
}
|
||||
|
||||
func TestSelectNodeCurrentPlatform(t *testing.T) {
|
||||
r := makeTestResolver(map[string][]specs.Platform{
|
||||
"aaa": {platforms.MustParse("linux/foobar")},
|
||||
"bbb": {platforms.DefaultSpec()},
|
||||
})
|
||||
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
||||
}
|
||||
|
||||
func TestSelectNodeAdditionalPlatforms(t *testing.T) {
|
||||
r := makeTestResolver(map[string][]specs.Platform{
|
||||
"aaa": {platforms.MustParse("linux/amd64")},
|
||||
"bbb": {platforms.MustParse("linux/arm/v8")},
|
||||
})
|
||||
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
||||
|
||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, func(idx int, n builder.Node) []specs.Platform {
|
||||
if n.Builder == "aaa" {
|
||||
return []specs.Platform{platforms.MustParse("linux/arm/v7")}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
||||
}
|
||||
|
||||
func TestSplitNodeMultiPlatform(t *testing.T) {
|
||||
r := makeTestResolver(map[string][]specs.Platform{
|
||||
"aaa": {platforms.MustParse("linux/amd64"), platforms.MustParse("linux/arm64")},
|
||||
"bbb": {platforms.MustParse("linux/riscv64")},
|
||||
})
|
||||
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{
|
||||
platforms.MustParse("linux/amd64"),
|
||||
platforms.MustParse("linux/arm64"),
|
||||
}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 1)
|
||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
||||
|
||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{
|
||||
platforms.MustParse("linux/amd64"),
|
||||
platforms.MustParse("linux/riscv64"),
|
||||
}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 2)
|
||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
||||
require.Equal(t, "bbb", res[1].Node().Builder)
|
||||
}
|
||||
|
||||
func TestSplitNodeMultiPlatformNoUnify(t *testing.T) {
|
||||
r := makeTestResolver(map[string][]specs.Platform{
|
||||
"aaa": {platforms.MustParse("linux/amd64")},
|
||||
"bbb": {platforms.MustParse("linux/amd64"), platforms.MustParse("linux/riscv64")},
|
||||
})
|
||||
|
||||
// the "best" choice would be the node with both platforms, but we're using
|
||||
// a naive algorithm that doesn't try to unify the platforms
|
||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{
|
||||
platforms.MustParse("linux/amd64"),
|
||||
platforms.MustParse("linux/riscv64"),
|
||||
}, nil, platforms.Only, nil)
|
||||
require.NoError(t, err)
|
||||
require.True(t, perfect)
|
||||
require.Len(t, res, 2)
|
||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
||||
require.Equal(t, "bbb", res[1].Node().Builder)
|
||||
}
|
||||
|
||||
func makeTestResolver(nodes map[string][]specs.Platform) *nodeResolver {
|
||||
var ns []builder.Node
|
||||
for name, platforms := range nodes {
|
||||
ns = append(ns, builder.Node{
|
||||
Builder: name,
|
||||
Platforms: platforms,
|
||||
})
|
||||
}
|
||||
sort.Slice(ns, func(i, j int) bool {
|
||||
return ns[i].Builder < ns[j].Builder
|
||||
})
|
||||
return newDriverResolver(ns)
|
||||
}
|
10
build/git.go
10
build/git.go
@@ -51,21 +51,21 @@ func getGitAttributes(ctx context.Context, contextPath string, dockerfilePath st
|
||||
|
||||
gitc, err := gitutil.New(gitutil.WithContext(ctx), gitutil.WithWorkingDir(wd))
|
||||
if err != nil {
|
||||
if st, err := os.Stat(path.Join(wd, ".git")); err == nil && st.IsDir() {
|
||||
return res, errors.New("buildx: git was not found in the system. Current commit information was not captured by the build")
|
||||
if st, err1 := os.Stat(path.Join(wd, ".git")); err1 == nil && st.IsDir() {
|
||||
return res, errors.Wrap(err, "git was not found in the system")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !gitc.IsInsideWorkTree() {
|
||||
if st, err := os.Stat(path.Join(wd, ".git")); err == nil && st.IsDir() {
|
||||
return res, errors.New("buildx: failed to read current commit information with git rev-parse --is-inside-work-tree")
|
||||
return res, errors.New("failed to read current commit information with git rev-parse --is-inside-work-tree")
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
if sha, err := gitc.FullCommit(); err != nil && !gitutil.IsUnknownRevision(err) {
|
||||
return res, errors.Wrapf(err, "buildx: failed to get git commit")
|
||||
return res, errors.Wrap(err, "failed to get git commit")
|
||||
} else if sha != "" {
|
||||
checkDirty := false
|
||||
if v, ok := os.LookupEnv("BUILDX_GIT_CHECK_DIRTY"); ok {
|
||||
@@ -95,7 +95,7 @@ func getGitAttributes(ctx context.Context, contextPath string, dockerfilePath st
|
||||
|
||||
if setGitLabels {
|
||||
if root, err := gitc.RootDir(); err != nil {
|
||||
return res, errors.Wrapf(err, "buildx: failed to get git root dir")
|
||||
return res, errors.Wrap(err, "failed to get git root dir")
|
||||
} else if root != "" {
|
||||
if dockerfilePath == "" {
|
||||
dockerfilePath = filepath.Join(wd, "Dockerfile")
|
||||
|
43
build/localstate.go
Normal file
43
build/localstate.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/docker/buildx/builder"
|
||||
"github.com/docker/buildx/localstate"
|
||||
"github.com/moby/buildkit/client"
|
||||
)
|
||||
|
||||
func saveLocalState(so *client.SolveOpt, target string, opts Options, node builder.Node, configDir string) error {
|
||||
var err error
|
||||
if so.Ref == "" {
|
||||
return nil
|
||||
}
|
||||
lp := opts.Inputs.ContextPath
|
||||
dp := opts.Inputs.DockerfilePath
|
||||
if lp != "" || dp != "" {
|
||||
if lp != "" {
|
||||
lp, err = filepath.Abs(lp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if dp != "" {
|
||||
dp, err = filepath.Abs(dp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
l, err := localstate.New(configDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return l.SaveRef(node.Builder, node.Name, so.Ref, localstate.State{
|
||||
Target: target,
|
||||
LocalPath: lp,
|
||||
DockerfilePath: dp,
|
||||
GroupRef: opts.GroupRef,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -117,7 +117,7 @@ func NewResultHandle(ctx context.Context, cc *client.Client, opt client.SolveOpt
|
||||
gwClient: c,
|
||||
gwCtx: ctx,
|
||||
}
|
||||
respErr = se
|
||||
respErr = err // return original error to preserve stacktrace
|
||||
close(done)
|
||||
|
||||
// Block until the caller closes the ResultHandle.
|
||||
@@ -160,6 +160,7 @@ func NewResultHandle(ctx context.Context, cc *client.Client, opt client.SolveOpt
|
||||
opt.Ref = ""
|
||||
opt.Exports = nil
|
||||
opt.CacheExports = nil
|
||||
opt.Internal = true
|
||||
_, respErr = cc.Build(ctx, opt, "buildx", func(ctx context.Context, c gateway.Client) (*gateway.Result, error) {
|
||||
res, err := evalDefinition(ctx, c, def)
|
||||
if err != nil {
|
||||
@@ -387,7 +388,7 @@ func populateProcessConfigFromResult(req *gateway.StartRequest, res *gateway.Res
|
||||
} else if img != nil {
|
||||
args = append(args, img.Config.Entrypoint...)
|
||||
}
|
||||
if cfg.Cmd != nil {
|
||||
if !cfg.NoCmd {
|
||||
args = append(args, cfg.Cmd...)
|
||||
} else if img != nil {
|
||||
args = append(args, img.Config.Cmd...)
|
||||
|
@@ -21,7 +21,7 @@ func createTempDockerfileFromURL(ctx context.Context, d *driver.DriverHandle, ur
|
||||
var out string
|
||||
ch, done := progress.NewChannel(pw)
|
||||
defer func() { <-done }()
|
||||
_, err = c.Build(ctx, client.SolveOpt{}, "buildx", func(ctx context.Context, c gwclient.Client) (*gwclient.Result, error) {
|
||||
_, err = c.Build(ctx, client.SolveOpt{Internal: true}, "buildx", func(ctx context.Context, c gwclient.Client) (*gwclient.Result, error) {
|
||||
def, err := llb.HTTP(url, llb.Filename("Dockerfile"), llb.WithCustomNamef("[internal] load %s", url)).Marshal(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -3,10 +3,12 @@ package build
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/buildx/driver"
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/docker/docker/builder/remotecontext/urlutil"
|
||||
"github.com/moby/buildkit/util/gitutil"
|
||||
@@ -57,7 +59,7 @@ func isArchive(header []byte) bool {
|
||||
}
|
||||
|
||||
// toBuildkitExtraHosts converts hosts from docker key:value format to buildkit's csv format
|
||||
func toBuildkitExtraHosts(inp []string, mobyDriver bool) (string, error) {
|
||||
func toBuildkitExtraHosts(ctx context.Context, inp []string, nodeDriver *driver.DriverHandle) (string, error) {
|
||||
if len(inp) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
@@ -67,11 +69,16 @@ func toBuildkitExtraHosts(inp []string, mobyDriver bool) (string, error) {
|
||||
if !ok || host == "" || ip == "" {
|
||||
return "", errors.Errorf("invalid host %s", h)
|
||||
}
|
||||
// Skip IP address validation for "host-gateway" string with moby driver
|
||||
if !mobyDriver || ip != mobyHostGatewayName {
|
||||
if net.ParseIP(ip) == nil {
|
||||
return "", errors.Errorf("invalid host %s", h)
|
||||
// If the IP Address is a "host-gateway", replace this value with the
|
||||
// IP address provided by the worker's label.
|
||||
if ip == mobyHostGatewayName {
|
||||
hgip, err := nodeDriver.HostGatewayIP(ctx)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "unable to derive the IP value for host-gateway")
|
||||
}
|
||||
ip = hgip.String()
|
||||
} else if net.ParseIP(ip) == nil {
|
||||
return "", errors.Errorf("invalid host %s", h)
|
||||
}
|
||||
hosts = append(hosts, host+"="+ip)
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/docker/buildx/util/imagetools"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/moby/buildkit/util/progress/progressui"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
@@ -157,13 +158,14 @@ func (b *Builder) Boot(ctx context.Context) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
printer, err := progress.NewPrinter(context.TODO(), os.Stderr, os.Stderr, progress.PrinterModeAuto)
|
||||
printer, err := progress.NewPrinter(context.TODO(), os.Stderr, progressui.AutoMode)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
baseCtx := ctx
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
errCh := make(chan error, len(toBoot))
|
||||
for _, idx := range toBoot {
|
||||
func(idx int) {
|
||||
eg.Go(func() error {
|
||||
@@ -171,6 +173,7 @@ func (b *Builder) Boot(ctx context.Context) (bool, error) {
|
||||
_, err := driver.Boot(ctx, baseCtx, b.nodes[idx].Driver, pw)
|
||||
if err != nil {
|
||||
b.nodes[idx].Err = err
|
||||
errCh <- err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -178,11 +181,15 @@ func (b *Builder) Boot(ctx context.Context) (bool, error) {
|
||||
}
|
||||
|
||||
err = eg.Wait()
|
||||
close(errCh)
|
||||
err1 := printer.Wait()
|
||||
if err == nil {
|
||||
err = err1
|
||||
}
|
||||
|
||||
if err == nil && len(errCh) == len(toBoot) {
|
||||
return false, <-errCh
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
|
||||
@@ -207,7 +214,7 @@ type driverFactory struct {
|
||||
}
|
||||
|
||||
// Factory returns the driver factory.
|
||||
func (b *Builder) Factory(ctx context.Context) (_ driver.Factory, err error) {
|
||||
func (b *Builder) Factory(ctx context.Context, dialMeta map[string][]string) (_ driver.Factory, err error) {
|
||||
b.driverFactory.once.Do(func() {
|
||||
if b.Driver != "" {
|
||||
b.driverFactory.Factory, err = driver.GetFactory(b.Driver, true)
|
||||
@@ -230,7 +237,7 @@ func (b *Builder) Factory(ctx context.Context) (_ driver.Factory, err error) {
|
||||
if _, err = dockerapi.Ping(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
b.driverFactory.Factory, err = driver.GetDefaultFactory(ctx, ep, dockerapi, false)
|
||||
b.driverFactory.Factory, err = driver.GetDefaultFactory(ctx, ep, dockerapi, false, dialMeta)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package builder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
|
||||
"github.com/docker/buildx/driver"
|
||||
ctxkube "github.com/docker/buildx/driver/kubernetes/context"
|
||||
@@ -24,13 +25,16 @@ type Node struct {
|
||||
Builder string
|
||||
Driver *driver.DriverHandle
|
||||
DriverInfo *driver.Info
|
||||
Platforms []ocispecs.Platform
|
||||
GCPolicy []client.PruneInfo
|
||||
Labels map[string]string
|
||||
ImageOpt imagetools.Opt
|
||||
ProxyConfig map[string]string
|
||||
Version string
|
||||
Err error
|
||||
|
||||
// worker settings
|
||||
IDs []string
|
||||
Platforms []ocispecs.Platform
|
||||
GCPolicy []client.PruneInfo
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
// Nodes returns nodes for this builder.
|
||||
@@ -38,9 +42,35 @@ func (b *Builder) Nodes() []Node {
|
||||
return b.nodes
|
||||
}
|
||||
|
||||
type LoadNodesOption func(*loadNodesOptions)
|
||||
|
||||
type loadNodesOptions struct {
|
||||
data bool
|
||||
dialMeta map[string][]string
|
||||
}
|
||||
|
||||
func WithData() LoadNodesOption {
|
||||
return func(o *loadNodesOptions) {
|
||||
o.data = true
|
||||
}
|
||||
}
|
||||
|
||||
func WithDialMeta(dialMeta map[string][]string) LoadNodesOption {
|
||||
return func(o *loadNodesOptions) {
|
||||
o.dialMeta = dialMeta
|
||||
}
|
||||
}
|
||||
|
||||
// LoadNodes loads and returns nodes for this builder.
|
||||
// TODO: this should be a method on a Node object and lazy load data for each driver.
|
||||
func (b *Builder) LoadNodes(ctx context.Context, withData bool) (_ []Node, err error) {
|
||||
func (b *Builder) LoadNodes(ctx context.Context, opts ...LoadNodesOption) (_ []Node, err error) {
|
||||
lno := loadNodesOptions{
|
||||
data: false,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(&lno)
|
||||
}
|
||||
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
b.nodes = make([]Node, len(b.NodeGroup.Nodes))
|
||||
|
||||
@@ -50,7 +80,7 @@ func (b *Builder) LoadNodes(ctx context.Context, withData bool) (_ []Node, err e
|
||||
}
|
||||
}()
|
||||
|
||||
factory, err := b.Factory(ctx)
|
||||
factory, err := b.Factory(ctx, lno.dialMeta)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -82,12 +112,12 @@ func (b *Builder) LoadNodes(ctx context.Context, withData bool) (_ []Node, err e
|
||||
contextStore := b.opts.dockerCli.ContextStore()
|
||||
|
||||
var kcc driver.KubeClientConfig
|
||||
kcc, err = ctxkube.ConfigFromContext(n.Endpoint, contextStore)
|
||||
kcc, err = ctxkube.ConfigFromEndpoint(n.Endpoint, contextStore)
|
||||
if err != nil {
|
||||
// err is returned if n.Endpoint is non-context name like "unix:///var/run/docker.sock".
|
||||
// try again with name="default".
|
||||
// FIXME(@AkihiroSuda): n should retain real context name.
|
||||
kcc, err = ctxkube.ConfigFromContext("default", contextStore)
|
||||
kcc, err = ctxkube.ConfigFromEndpoint("default", contextStore)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
@@ -109,7 +139,7 @@ func (b *Builder) LoadNodes(ctx context.Context, withData bool) (_ []Node, err e
|
||||
}
|
||||
}
|
||||
|
||||
d, err := driver.GetDriver(ctx, "buildx_buildkit_"+n.Name, factory, n.Endpoint, dockerapi, imageopt.Auth, kcc, n.Flags, n.Files, n.DriverOpts, n.Platforms, b.opts.contextPathHash)
|
||||
d, err := driver.GetDriver(ctx, "buildx_buildkit_"+n.Name, factory, n.Endpoint, dockerapi, imageopt.Auth, kcc, n.Flags, n.Files, n.DriverOpts, n.Platforms, b.opts.contextPathHash, lno.dialMeta)
|
||||
if err != nil {
|
||||
node.Err = err
|
||||
return nil
|
||||
@@ -117,7 +147,7 @@ func (b *Builder) LoadNodes(ctx context.Context, withData bool) (_ []Node, err e
|
||||
node.Driver = d
|
||||
node.ImageOpt = imageopt
|
||||
|
||||
if withData {
|
||||
if lno.data {
|
||||
if err := node.loadData(ctx); err != nil {
|
||||
node.Err = err
|
||||
}
|
||||
@@ -132,7 +162,7 @@ func (b *Builder) LoadNodes(ctx context.Context, withData bool) (_ []Node, err e
|
||||
}
|
||||
|
||||
// TODO: This should be done in the routine loading driver data
|
||||
if withData {
|
||||
if lno.data {
|
||||
kubernetesDriverCount := 0
|
||||
for _, d := range b.nodes {
|
||||
if d.DriverInfo != nil && len(d.DriverInfo.DynamicNodes) > 0 {
|
||||
@@ -188,12 +218,14 @@ func (n *Node) loadData(ctx context.Context) error {
|
||||
return errors.Wrap(err, "listing workers")
|
||||
}
|
||||
for idx, w := range workers {
|
||||
n.IDs = append(n.IDs, w.ID)
|
||||
n.Platforms = append(n.Platforms, w.Platforms...)
|
||||
if idx == 0 {
|
||||
n.GCPolicy = w.GCPolicy
|
||||
n.Labels = w.Labels
|
||||
}
|
||||
}
|
||||
sort.Strings(n.IDs)
|
||||
n.Platforms = platformutil.Dedupe(n.Platforms)
|
||||
inf, err := driverClient.Info(ctx)
|
||||
if err != nil {
|
||||
|
109
commands/bake.go
109
commands/bake.go
@@ -4,13 +4,16 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/docker/buildx/bake"
|
||||
"github.com/docker/buildx/build"
|
||||
"github.com/docker/buildx/builder"
|
||||
"github.com/docker/buildx/localstate"
|
||||
"github.com/docker/buildx/util/buildflags"
|
||||
"github.com/docker/buildx/util/cobrautil/completion"
|
||||
"github.com/docker/buildx/util/confutil"
|
||||
@@ -19,7 +22,9 @@ import (
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/docker/buildx/util/tracing"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/moby/buildkit/identity"
|
||||
"github.com/moby/buildkit/util/appcontext"
|
||||
"github.com/moby/buildkit/util/progress/progressui"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -95,8 +100,6 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions, cFlags com
|
||||
defer cancel()
|
||||
|
||||
var nodes []builder.Node
|
||||
var files []bake.File
|
||||
var inp *bake.Input
|
||||
var progressConsoleDesc, progressTextDesc string
|
||||
|
||||
// instance only needed for reading remote bake files or building
|
||||
@@ -111,7 +114,7 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions, cFlags com
|
||||
if err = updateLastActivity(dockerCli, b.NodeGroup); err != nil {
|
||||
return errors.Wrapf(err, "failed to update builder last activity time")
|
||||
}
|
||||
nodes, err = b.LoadNodes(ctx, false)
|
||||
nodes, err = b.LoadNodes(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -124,7 +127,8 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions, cFlags com
|
||||
term = true
|
||||
}
|
||||
|
||||
printer, err := progress.NewPrinter(ctx2, os.Stderr, os.Stderr, cFlags.progress,
|
||||
progressMode := progressui.DisplayMode(cFlags.progress)
|
||||
printer, err := progress.NewPrinter(ctx2, os.Stderr, progressMode,
|
||||
progress.WithDesc(progressTextDesc, progressConsoleDesc),
|
||||
)
|
||||
if err != nil {
|
||||
@@ -137,21 +141,21 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions, cFlags com
|
||||
if err == nil {
|
||||
err = err1
|
||||
}
|
||||
if err == nil && cFlags.progress != progress.PrinterModeQuiet {
|
||||
if err == nil && progressMode != progressui.QuietMode {
|
||||
desktop.PrintBuildDetails(os.Stderr, printer.BuildRefs(), term)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if url != "" {
|
||||
files, inp, err = bake.ReadRemoteFiles(ctx, nodes, url, in.files, printer)
|
||||
} else {
|
||||
files, err = bake.ReadLocalFiles(in.files, dockerCli.In())
|
||||
}
|
||||
files, inp, err := readBakeFiles(ctx, nodes, url, in.files, dockerCli.In(), printer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return errors.New("couldn't find a bake definition")
|
||||
}
|
||||
|
||||
tgts, grps, err := bake.ReadTargets(ctx, files, targets, overrides, map[string]string{
|
||||
// don't forget to update documentation if you add a new
|
||||
// built-in variable: docs/bake-reference.md#built-in-variables
|
||||
@@ -181,14 +185,16 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions, cFlags com
|
||||
return err
|
||||
}
|
||||
|
||||
def := struct {
|
||||
Group map[string]*bake.Group `json:"group,omitempty"`
|
||||
Target map[string]*bake.Target `json:"target"`
|
||||
}{
|
||||
Group: grps,
|
||||
Target: tgts,
|
||||
}
|
||||
|
||||
if in.printOnly {
|
||||
dt, err := json.MarshalIndent(struct {
|
||||
Group map[string]*bake.Group `json:"group,omitempty"`
|
||||
Target map[string]*bake.Target `json:"target"`
|
||||
}{
|
||||
grps,
|
||||
tgts,
|
||||
}, "", " ")
|
||||
dt, err := json.MarshalIndent(def, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -201,6 +207,28 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions, cFlags com
|
||||
return nil
|
||||
}
|
||||
|
||||
// local state group
|
||||
groupRef := identity.NewID()
|
||||
var refs []string
|
||||
for k, b := range bo {
|
||||
b.Ref = identity.NewID()
|
||||
b.GroupRef = groupRef
|
||||
refs = append(refs, b.Ref)
|
||||
bo[k] = b
|
||||
}
|
||||
dt, err := json.Marshal(def)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := saveLocalStateGroup(dockerCli, groupRef, localstate.StateGroup{
|
||||
Definition: dt,
|
||||
Targets: targets,
|
||||
Inputs: overrides,
|
||||
Refs: refs,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := build.Build(ctx, nodes, bo, dockerutil.NewClient(dockerCli), confutil.ConfigDir(dockerCli), printer)
|
||||
if err != nil {
|
||||
return wrapBuildError(err, true)
|
||||
@@ -257,3 +285,50 @@ func bakeCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func saveLocalStateGroup(dockerCli command.Cli, ref string, lsg localstate.StateGroup) error {
|
||||
l, err := localstate.New(confutil.ConfigDir(dockerCli))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return l.SaveGroup(ref, lsg)
|
||||
}
|
||||
|
||||
func readBakeFiles(ctx context.Context, nodes []builder.Node, url string, names []string, stdin io.Reader, pw progress.Writer) (files []bake.File, inp *bake.Input, err error) {
|
||||
var lnames []string
|
||||
var rnames []string
|
||||
for _, v := range names {
|
||||
if strings.HasPrefix(v, "cwd://") {
|
||||
lnames = append(lnames, strings.TrimPrefix(v, "cwd://"))
|
||||
} else {
|
||||
rnames = append(rnames, v)
|
||||
}
|
||||
}
|
||||
|
||||
if url != "" {
|
||||
var rfiles []bake.File
|
||||
rfiles, inp, err = bake.ReadRemoteFiles(ctx, nodes, url, rnames, pw)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
files = append(files, rfiles...)
|
||||
}
|
||||
|
||||
if len(lnames) > 0 || url == "" {
|
||||
var lfiles []bake.File
|
||||
progress.Wrap("[internal] load local bake definitions", pw.Write, func(sub progress.SubLogger) error {
|
||||
if url != "" {
|
||||
lfiles, err = bake.ReadLocalFiles(lnames, stdin, sub)
|
||||
} else {
|
||||
lfiles, err = bake.ReadLocalFiles(append(lnames, rnames...), stdin, sub)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
files = append(files, lfiles...)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/containerd/console"
|
||||
"github.com/docker/buildx/build"
|
||||
"github.com/docker/buildx/builder"
|
||||
"github.com/docker/buildx/commands/debug"
|
||||
"github.com/docker/buildx/controller"
|
||||
cbuild "github.com/docker/buildx/controller/build"
|
||||
"github.com/docker/buildx/controller/control"
|
||||
@@ -44,6 +45,7 @@ import (
|
||||
"github.com/moby/buildkit/solver/errdefs"
|
||||
"github.com/moby/buildkit/util/appcontext"
|
||||
"github.com/moby/buildkit/util/grpcerrors"
|
||||
"github.com/moby/buildkit/util/progress/progressui"
|
||||
"github.com/morikuni/aec"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -54,6 +56,7 @@ import (
|
||||
|
||||
type buildOptions struct {
|
||||
allow []string
|
||||
annotations []string
|
||||
buildArgs []string
|
||||
cacheFrom []string
|
||||
cacheTo []string
|
||||
@@ -76,9 +79,6 @@ type buildOptions struct {
|
||||
target string
|
||||
ulimits *dockeropts.UlimitOpt
|
||||
|
||||
invoke *invokeConfig
|
||||
noBuild bool
|
||||
|
||||
attests []string
|
||||
sbom string
|
||||
provenance string
|
||||
@@ -94,18 +94,32 @@ type buildOptions struct {
|
||||
exportLoad bool
|
||||
|
||||
control.ControlOptions
|
||||
|
||||
invokeConfig *invokeConfig
|
||||
}
|
||||
|
||||
func (o *buildOptions) toControllerOptions() (*controllerapi.BuildOptions, error) {
|
||||
var err error
|
||||
|
||||
buildArgs, err := listToMap(o.buildArgs, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
labels, err := listToMap(o.labels, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opts := controllerapi.BuildOptions{
|
||||
Allow: o.allow,
|
||||
BuildArgs: listToMap(o.buildArgs, true),
|
||||
Annotations: o.annotations,
|
||||
BuildArgs: buildArgs,
|
||||
CgroupParent: o.cgroupParent,
|
||||
ContextPath: o.contextPath,
|
||||
DockerfileName: o.dockerfileName,
|
||||
ExtraHosts: o.extraHosts,
|
||||
Labels: listToMap(o.labels, false),
|
||||
Labels: labels,
|
||||
NetworkMode: o.networkMode,
|
||||
NoCacheFilter: o.noCacheFilter,
|
||||
Platforms: o.platforms,
|
||||
@@ -185,20 +199,15 @@ func (o *buildOptions) toControllerOptions() (*controllerapi.BuildOptions, error
|
||||
return &opts, nil
|
||||
}
|
||||
|
||||
func (o *buildOptions) toProgress() (string, error) {
|
||||
switch o.progress {
|
||||
case progress.PrinterModeAuto, progress.PrinterModeTty, progress.PrinterModePlain, progress.PrinterModeQuiet:
|
||||
default:
|
||||
return "", errors.Errorf("progress=%s is not a valid progress option", o.progress)
|
||||
}
|
||||
|
||||
func (o *buildOptions) toDisplayMode() (progressui.DisplayMode, error) {
|
||||
progress := progressui.DisplayMode(o.progress)
|
||||
if o.quiet {
|
||||
if o.progress != progress.PrinterModeAuto && o.progress != progress.PrinterModeQuiet {
|
||||
if progress != progressui.AutoMode && progress != progressui.QuietMode {
|
||||
return "", errors.Errorf("progress=%s and quiet cannot be used together", o.progress)
|
||||
}
|
||||
return progress.PrinterModeQuiet, nil
|
||||
return progressui.QuietMode, nil
|
||||
}
|
||||
return o.progress, nil
|
||||
return progress, nil
|
||||
}
|
||||
|
||||
func runBuild(dockerCli command.Cli, options buildOptions) (err error) {
|
||||
@@ -234,7 +243,7 @@ func runBuild(dockerCli command.Cli, options buildOptions) (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = b.LoadNodes(ctx, false)
|
||||
_, err = b.LoadNodes(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -246,12 +255,12 @@ func runBuild(dockerCli command.Cli, options buildOptions) (err error) {
|
||||
|
||||
ctx2, cancel := context.WithCancel(context.TODO())
|
||||
defer cancel()
|
||||
progressMode, err := options.toProgress()
|
||||
progressMode, err := options.toDisplayMode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var printer *progress.Printer
|
||||
printer, err = progress.NewPrinter(ctx2, os.Stderr, os.Stderr, progressMode,
|
||||
printer, err = progress.NewPrinter(ctx2, os.Stderr, progressMode,
|
||||
progress.WithDesc(
|
||||
fmt.Sprintf("building with %q instance using %s driver", b.Name, b.Driver),
|
||||
fmt.Sprintf("%s:%s", b.Driver, b.Name),
|
||||
@@ -279,7 +288,7 @@ func runBuild(dockerCli command.Cli, options buildOptions) (err error) {
|
||||
return retErr
|
||||
}
|
||||
|
||||
if progressMode != progress.PrinterModeQuiet {
|
||||
if progressMode != progressui.QuietMode {
|
||||
desktop.PrintBuildDetails(os.Stderr, printer.BuildRefs(), term)
|
||||
} else {
|
||||
fmt.Println(getImageID(resp.ExporterResponse))
|
||||
@@ -320,11 +329,10 @@ func runBasicBuild(ctx context.Context, dockerCli command.Cli, opts *controllera
|
||||
}
|
||||
|
||||
func runControllerBuild(ctx context.Context, dockerCli command.Cli, opts *controllerapi.BuildOptions, options buildOptions, printer *progress.Printer) (*client.SolveResponse, error) {
|
||||
if options.invoke != nil && (options.dockerfileName == "-" || options.contextPath == "-") {
|
||||
if options.invokeConfig != nil && (options.dockerfileName == "-" || options.contextPath == "-") {
|
||||
// stdin must be usable for monitor
|
||||
return nil, errors.Errorf("Dockerfile or context from stdin is not supported with invoke")
|
||||
}
|
||||
|
||||
c, err := controller.NewController(ctx, options.ControlOptions, dockerCli, printer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -347,56 +355,54 @@ func runControllerBuild(ctx context.Context, dockerCli command.Cli, opts *contro
|
||||
var resp *client.SolveResponse
|
||||
f := ioset.NewSingleForwarder()
|
||||
f.SetReader(dockerCli.In())
|
||||
if !options.noBuild {
|
||||
pr, pw := io.Pipe()
|
||||
f.SetWriter(pw, func() io.WriteCloser {
|
||||
pw.Close() // propagate EOF
|
||||
logrus.Debug("propagating stdin close")
|
||||
return nil
|
||||
})
|
||||
pr, pw := io.Pipe()
|
||||
f.SetWriter(pw, func() io.WriteCloser {
|
||||
pw.Close() // propagate EOF
|
||||
logrus.Debug("propagating stdin close")
|
||||
return nil
|
||||
})
|
||||
|
||||
ref, resp, err = c.Build(ctx, *opts, pr, printer)
|
||||
if err != nil {
|
||||
var be *controllererrors.BuildError
|
||||
if errors.As(err, &be) {
|
||||
ref = be.Ref
|
||||
retErr = err
|
||||
// We can proceed to monitor
|
||||
} else {
|
||||
return nil, errors.Wrapf(err, "failed to build")
|
||||
}
|
||||
}
|
||||
|
||||
if err := pw.Close(); err != nil {
|
||||
logrus.Debug("failed to close stdin pipe writer")
|
||||
}
|
||||
if err := pr.Close(); err != nil {
|
||||
logrus.Debug("failed to close stdin pipe reader")
|
||||
ref, resp, err = c.Build(ctx, *opts, pr, printer)
|
||||
if err != nil {
|
||||
var be *controllererrors.BuildError
|
||||
if errors.As(err, &be) {
|
||||
ref = be.Ref
|
||||
retErr = err
|
||||
// We can proceed to monitor
|
||||
} else {
|
||||
return nil, errors.Wrapf(err, "failed to build")
|
||||
}
|
||||
}
|
||||
|
||||
// post-build operations
|
||||
if options.invoke != nil && options.invoke.needsMonitor(retErr) {
|
||||
if err := pw.Close(); err != nil {
|
||||
logrus.Debug("failed to close stdin pipe writer")
|
||||
}
|
||||
if err := pr.Close(); err != nil {
|
||||
logrus.Debug("failed to close stdin pipe reader")
|
||||
}
|
||||
|
||||
if options.invokeConfig != nil && options.invokeConfig.needsDebug(retErr) {
|
||||
// Print errors before launching monitor
|
||||
if err := printError(retErr, printer); err != nil {
|
||||
logrus.Warnf("failed to print error information: %v", err)
|
||||
}
|
||||
|
||||
pr2, pw2 := io.Pipe()
|
||||
f.SetWriter(pw2, func() io.WriteCloser {
|
||||
pw2.Close() // propagate EOF
|
||||
return nil
|
||||
})
|
||||
con := console.Current()
|
||||
if err := con.SetRaw(); err != nil {
|
||||
if err := c.Disconnect(ctx, ref); err != nil {
|
||||
logrus.Warnf("disconnect error: %v", err)
|
||||
}
|
||||
return nil, errors.Errorf("failed to configure terminal: %v", err)
|
||||
}
|
||||
err = monitor.RunMonitor(ctx, ref, opts, options.invoke.InvokeConfig, c, pr2, os.Stdout, os.Stderr, printer)
|
||||
con.Reset()
|
||||
monitorBuildResult, err := options.invokeConfig.runDebug(ctx, ref, opts, c, pr2, os.Stdout, os.Stderr, printer)
|
||||
if err := pw2.Close(); err != nil {
|
||||
logrus.Debug("failed to close monitor stdin pipe reader")
|
||||
}
|
||||
if err != nil {
|
||||
logrus.Warnf("failed to run monitor: %v", err)
|
||||
}
|
||||
if monitorBuildResult != nil {
|
||||
// Update return values with the last build result from monitor
|
||||
resp, retErr = monitorBuildResult.Resp, monitorBuildResult.Err
|
||||
}
|
||||
} else {
|
||||
if err := c.Disconnect(ctx, ref); err != nil {
|
||||
logrus.Warnf("disconnect error: %v", err)
|
||||
@@ -406,10 +412,37 @@ func runControllerBuild(ctx context.Context, dockerCli command.Cli, opts *contro
|
||||
return resp, retErr
|
||||
}
|
||||
|
||||
func buildCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
||||
options := buildOptions{}
|
||||
func printError(err error, printer *progress.Printer) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if err := printer.Pause(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer printer.Unpause()
|
||||
for _, s := range errdefs.Sources(err) {
|
||||
s.Print(os.Stderr)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
func newDebuggableBuild(dockerCli command.Cli, rootOpts *rootOptions) debug.DebuggableCmd {
|
||||
return &debuggableBuild{dockerCli: dockerCli, rootOpts: rootOpts}
|
||||
}
|
||||
|
||||
type debuggableBuild struct {
|
||||
dockerCli command.Cli
|
||||
rootOpts *rootOptions
|
||||
}
|
||||
|
||||
func (b *debuggableBuild) NewDebugger(cfg *debug.DebugConfig) *cobra.Command {
|
||||
return buildCmd(b.dockerCli, b.rootOpts, cfg)
|
||||
}
|
||||
|
||||
func buildCmd(dockerCli command.Cli, rootOpts *rootOptions, debugConfig *debug.DebugConfig) *cobra.Command {
|
||||
cFlags := &commonFlags{}
|
||||
var invokeFlag string
|
||||
options := &buildOptions{}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "build [OPTIONS] PATH | URL | -",
|
||||
@@ -431,15 +464,15 @@ func buildCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
||||
options.progress = cFlags.progress
|
||||
cmd.Flags().VisitAll(checkWarnedFlags)
|
||||
|
||||
if invokeFlag != "" {
|
||||
invoke, err := parseInvokeConfig(invokeFlag)
|
||||
if err != nil {
|
||||
if debugConfig != nil && (debugConfig.InvokeFlag != "" || debugConfig.OnFlag != "") {
|
||||
iConfig := new(invokeConfig)
|
||||
if err := iConfig.parseInvokeConfig(debugConfig.InvokeFlag, debugConfig.OnFlag); err != nil {
|
||||
return err
|
||||
}
|
||||
options.invoke = &invoke
|
||||
options.noBuild = invokeFlag == "debug-shell"
|
||||
options.invokeConfig = iConfig
|
||||
}
|
||||
return runBuild(dockerCli, options)
|
||||
|
||||
return runBuild(dockerCli, *options)
|
||||
},
|
||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return nil, cobra.ShellCompDirectiveFilterDirs
|
||||
@@ -458,13 +491,15 @@ func buildCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
||||
|
||||
flags.StringSliceVar(&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")
|
||||
|
||||
flags.StringArrayVar(&options.buildArgs, "build-arg", []string{}, "Set build-time variables")
|
||||
|
||||
flags.StringArrayVar(&options.cacheFrom, "cache-from", []string{}, `External cache sources (e.g., "user/app:cache", "type=local,src=path/to/dir")`)
|
||||
|
||||
flags.StringArrayVar(&options.cacheTo, "cache-to", []string{}, `Cache export destinations (e.g., "user/app:cache", "type=local,dest=path/to/dir")`)
|
||||
|
||||
flags.StringVar(&options.cgroupParent, "cgroup-parent", "", "Optional parent cgroup for the container")
|
||||
flags.StringVar(&options.cgroupParent, "cgroup-parent", "", `Set the parent cgroup for the "RUN" instructions during build`)
|
||||
flags.SetAnnotation("cgroup-parent", annotation.ExternalURL, []string{"https://docs.docker.com/engine/reference/commandline/build/#cgroup-parent"})
|
||||
|
||||
flags.StringArrayVar(&options.contexts, "build-context", []string{}, "Additional build contexts (e.g., name=path)")
|
||||
@@ -487,7 +522,8 @@ func buildCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
||||
flags.StringArrayVar(&options.platforms, "platform", platformsDefault, "Set target platform for build")
|
||||
|
||||
if isExperimental() {
|
||||
flags.StringVar(&options.printFunc, "print", "", "Print result of information request (e.g., outline, targets) [experimental]")
|
||||
flags.StringVar(&options.printFunc, "print", "", "Print result of information request (e.g., outline, targets)")
|
||||
flags.SetAnnotation("print", "experimentalCLI", nil)
|
||||
}
|
||||
|
||||
flags.BoolVar(&options.exportPush, "push", false, `Shorthand for "--output=type=registry"`)
|
||||
@@ -514,10 +550,13 @@ func buildCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
||||
flags.StringVar(&options.provenance, "provenance", "", `Shorthand for "--attest=type=provenance"`)
|
||||
|
||||
if isExperimental() {
|
||||
flags.StringVar(&invokeFlag, "invoke", "", "Invoke a command after the build [experimental]")
|
||||
flags.StringVar(&options.Root, "root", "", "Specify root directory of server to connect [experimental]")
|
||||
flags.BoolVar(&options.Detach, "detach", false, "Detach buildx server (supported only on linux) [experimental]")
|
||||
flags.StringVar(&options.ServerConfig, "server-config", "", "Specify buildx server config file (used only when launching new server) [experimental]")
|
||||
// TODO: move this to debug command if needed
|
||||
flags.StringVar(&options.Root, "root", "", "Specify root directory of server to connect")
|
||||
flags.SetAnnotation("root", "experimentalCLI", nil)
|
||||
flags.BoolVar(&options.Detach, "detach", false, "Detach buildx server (supported only on linux)")
|
||||
flags.SetAnnotation("detach", "experimentalCLI", nil)
|
||||
flags.StringVar(&options.ServerConfig, "server-config", "", "Specify buildx server config file (used only when launching new server)")
|
||||
flags.SetAnnotation("server-config", "experimentalCLI", nil)
|
||||
}
|
||||
|
||||
// hidden flags
|
||||
@@ -540,6 +579,7 @@ func buildCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
||||
flags.BoolVar(&ignoreBool, "squash", false, "Squash newly built layers into a single new layer")
|
||||
flags.MarkHidden("squash")
|
||||
flags.SetAnnotation("squash", "flag-warn", []string{"experimental flag squash is removed with BuildKit. You should squash inside build using a multi-stage Dockerfile for efficiency."})
|
||||
flags.SetAnnotation("squash", "experimentalCLI", nil)
|
||||
|
||||
flags.StringVarP(&ignore, "memory", "m", "", "Memory limit")
|
||||
flags.MarkHidden("memory")
|
||||
@@ -673,109 +713,24 @@ func updateLastActivity(dockerCli command.Cli, ng *store.NodeGroup) error {
|
||||
return txn.UpdateLastActivity(ng)
|
||||
}
|
||||
|
||||
type invokeConfig struct {
|
||||
controllerapi.InvokeConfig
|
||||
invokeFlag string
|
||||
}
|
||||
|
||||
func (cfg *invokeConfig) needsMonitor(retErr error) bool {
|
||||
switch cfg.invokeFlag {
|
||||
case "debug-shell":
|
||||
return true
|
||||
case "on-error":
|
||||
return retErr != nil
|
||||
default:
|
||||
return cfg.invokeFlag != ""
|
||||
}
|
||||
}
|
||||
|
||||
func parseInvokeConfig(invoke string) (cfg invokeConfig, err error) {
|
||||
cfg.invokeFlag = invoke
|
||||
cfg.Tty = true
|
||||
switch invoke {
|
||||
case "default", "debug-shell":
|
||||
return cfg, nil
|
||||
case "on-error":
|
||||
// NOTE: we overwrite the command to run because the original one should fail on the failed step.
|
||||
// TODO: make this configurable via flags or restorable from LLB.
|
||||
// Discussion: https://github.com/docker/buildx/pull/1640#discussion_r1113295900
|
||||
cfg.Cmd = []string{"/bin/sh"}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
csvReader := csv.NewReader(strings.NewReader(invoke))
|
||||
csvReader.LazyQuotes = true
|
||||
fields, err := csvReader.Read()
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
if len(fields) == 1 && !strings.Contains(fields[0], "=") {
|
||||
cfg.Cmd = []string{fields[0]}
|
||||
return cfg, nil
|
||||
}
|
||||
cfg.NoUser = true
|
||||
cfg.NoCwd = true
|
||||
for _, field := range fields {
|
||||
parts := strings.SplitN(field, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return cfg, errors.Errorf("invalid value %s", field)
|
||||
}
|
||||
key := strings.ToLower(parts[0])
|
||||
value := parts[1]
|
||||
switch key {
|
||||
case "args":
|
||||
cfg.Cmd = append(cfg.Cmd, maybeJSONArray(value)...)
|
||||
case "entrypoint":
|
||||
cfg.Entrypoint = append(cfg.Entrypoint, maybeJSONArray(value)...)
|
||||
if cfg.Cmd == nil {
|
||||
cfg.Cmd = []string{}
|
||||
}
|
||||
case "env":
|
||||
cfg.Env = append(cfg.Env, maybeJSONArray(value)...)
|
||||
case "user":
|
||||
cfg.User = value
|
||||
cfg.NoUser = false
|
||||
case "cwd":
|
||||
cfg.Cwd = value
|
||||
cfg.NoCwd = false
|
||||
case "tty":
|
||||
cfg.Tty, err = strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return cfg, errors.Errorf("failed to parse tty: %v", err)
|
||||
}
|
||||
default:
|
||||
return cfg, errors.Errorf("unknown key %q", key)
|
||||
}
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func maybeJSONArray(v string) []string {
|
||||
var list []string
|
||||
if err := json.Unmarshal([]byte(v), &list); err == nil {
|
||||
return list
|
||||
}
|
||||
return []string{v}
|
||||
}
|
||||
|
||||
func listToMap(values []string, defaultEnv bool) map[string]string {
|
||||
func listToMap(values []string, defaultEnv bool) (map[string]string, error) {
|
||||
result := make(map[string]string, len(values))
|
||||
for _, value := range values {
|
||||
kv := strings.SplitN(value, "=", 2)
|
||||
if len(kv) == 1 {
|
||||
if defaultEnv {
|
||||
v, ok := os.LookupEnv(kv[0])
|
||||
if ok {
|
||||
result[kv[0]] = v
|
||||
}
|
||||
} else {
|
||||
result[kv[0]] = ""
|
||||
k, v, hasValue := strings.Cut(value, "=")
|
||||
if k == "" {
|
||||
return nil, errors.Errorf("invalid key-value pair %q: empty key", value)
|
||||
}
|
||||
if hasValue {
|
||||
result[k] = v
|
||||
} else if defaultEnv {
|
||||
if envVal, ok := os.LookupEnv(k); ok {
|
||||
result[k] = envVal
|
||||
}
|
||||
} else {
|
||||
result[kv[0]] = kv[1]
|
||||
result[k] = ""
|
||||
}
|
||||
}
|
||||
return result
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func dockerUlimitToControllerUlimit(u *dockeropts.UlimitOpt) *controllerapi.UlimitOpt {
|
||||
@@ -793,8 +748,8 @@ func dockerUlimitToControllerUlimit(u *dockeropts.UlimitOpt) *controllerapi.Ulim
|
||||
return &controllerapi.UlimitOpt{Values: values}
|
||||
}
|
||||
|
||||
func printWarnings(w io.Writer, warnings []client.VertexWarning, mode string) {
|
||||
if len(warnings) == 0 || mode == progress.PrinterModeQuiet {
|
||||
func printWarnings(w io.Writer, warnings []client.VertexWarning, mode progressui.DisplayMode) {
|
||||
if len(warnings) == 0 || mode == progressui.QuietMode {
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(w, "\n ")
|
||||
@@ -866,3 +821,108 @@ func printValue(printer printFunc, version string, format string, res map[string
|
||||
}
|
||||
return printer([]byte(res["result.json"]), os.Stdout)
|
||||
}
|
||||
|
||||
type invokeConfig struct {
|
||||
controllerapi.InvokeConfig
|
||||
onFlag string
|
||||
invokeFlag string
|
||||
}
|
||||
|
||||
func (cfg *invokeConfig) needsDebug(retErr error) bool {
|
||||
switch cfg.onFlag {
|
||||
case "always":
|
||||
return true
|
||||
case "error":
|
||||
return retErr != nil
|
||||
default:
|
||||
return cfg.invokeFlag != ""
|
||||
}
|
||||
}
|
||||
|
||||
func (cfg *invokeConfig) runDebug(ctx context.Context, ref string, options *controllerapi.BuildOptions, c control.BuildxController, stdin io.ReadCloser, stdout io.WriteCloser, stderr console.File, progress *progress.Printer) (*monitor.MonitorBuildResult, error) {
|
||||
con := console.Current()
|
||||
if err := con.SetRaw(); err != nil {
|
||||
// TODO: run disconnect in build command (on error case)
|
||||
if err := c.Disconnect(ctx, ref); err != nil {
|
||||
logrus.Warnf("disconnect error: %v", err)
|
||||
}
|
||||
return nil, errors.Errorf("failed to configure terminal: %v", err)
|
||||
}
|
||||
defer con.Reset()
|
||||
return monitor.RunMonitor(ctx, ref, options, cfg.InvokeConfig, c, stdin, stdout, stderr, progress)
|
||||
}
|
||||
|
||||
func (cfg *invokeConfig) parseInvokeConfig(invoke, on string) error {
|
||||
cfg.onFlag = on
|
||||
cfg.invokeFlag = invoke
|
||||
cfg.Tty = true
|
||||
cfg.NoCmd = true
|
||||
switch invoke {
|
||||
case "default", "":
|
||||
return nil
|
||||
case "on-error":
|
||||
// NOTE: we overwrite the command to run because the original one should fail on the failed step.
|
||||
// TODO: make this configurable via flags or restorable from LLB.
|
||||
// Discussion: https://github.com/docker/buildx/pull/1640#discussion_r1113295900
|
||||
cfg.Cmd = []string{"/bin/sh"}
|
||||
cfg.NoCmd = false
|
||||
return nil
|
||||
}
|
||||
|
||||
csvReader := csv.NewReader(strings.NewReader(invoke))
|
||||
csvReader.LazyQuotes = true
|
||||
fields, err := csvReader.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(fields) == 1 && !strings.Contains(fields[0], "=") {
|
||||
cfg.Cmd = []string{fields[0]}
|
||||
cfg.NoCmd = false
|
||||
return nil
|
||||
}
|
||||
cfg.NoUser = true
|
||||
cfg.NoCwd = true
|
||||
for _, field := range fields {
|
||||
parts := strings.SplitN(field, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return errors.Errorf("invalid value %s", field)
|
||||
}
|
||||
key := strings.ToLower(parts[0])
|
||||
value := parts[1]
|
||||
switch key {
|
||||
case "args":
|
||||
cfg.Cmd = append(cfg.Cmd, maybeJSONArray(value)...)
|
||||
cfg.NoCmd = false
|
||||
case "entrypoint":
|
||||
cfg.Entrypoint = append(cfg.Entrypoint, maybeJSONArray(value)...)
|
||||
if cfg.Cmd == nil {
|
||||
cfg.Cmd = []string{}
|
||||
cfg.NoCmd = false
|
||||
}
|
||||
case "env":
|
||||
cfg.Env = append(cfg.Env, maybeJSONArray(value)...)
|
||||
case "user":
|
||||
cfg.User = value
|
||||
cfg.NoUser = false
|
||||
case "cwd":
|
||||
cfg.Cwd = value
|
||||
cfg.NoCwd = false
|
||||
case "tty":
|
||||
cfg.Tty, err = strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return errors.Errorf("failed to parse tty: %v", err)
|
||||
}
|
||||
default:
|
||||
return errors.Errorf("unknown key %q", key)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func maybeJSONArray(v string) []string {
|
||||
var list []string
|
||||
if err := json.Unmarshal([]byte(v), &list); err == nil {
|
||||
return list
|
||||
}
|
||||
return []string{v}
|
||||
}
|
||||
|
@@ -72,6 +72,7 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Ensure the file lock gets released no matter what happens.
|
||||
defer release()
|
||||
|
||||
name := in.name
|
||||
@@ -122,7 +123,7 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
|
||||
if len(args) > 0 {
|
||||
arg = args[0]
|
||||
}
|
||||
f, err := driver.GetDefaultFactory(ctx, arg, dockerCli.Client(), true)
|
||||
f, err := driver.GetDefaultFactory(ctx, arg, dockerCli.Client(), true, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -269,7 +270,7 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, 20*time.Second)
|
||||
defer cancel()
|
||||
|
||||
nodes, err := b.LoadNodes(timeoutCtx, true)
|
||||
nodes, err := b.LoadNodes(timeoutCtx, builder.WithData())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -300,6 +301,10 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// The store is no longer used from this point.
|
||||
// Release it so we aren't holding the file lock during the boot.
|
||||
release()
|
||||
|
||||
if in.bootstrap {
|
||||
if _, err = b.Boot(ctx); err != nil {
|
||||
return err
|
||||
|
@@ -1,70 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/docker/buildx/controller"
|
||||
"github.com/docker/buildx/controller/control"
|
||||
controllerapi "github.com/docker/buildx/controller/pb"
|
||||
"github.com/docker/buildx/monitor"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func debugShellCmd(dockerCli command.Cli) *cobra.Command {
|
||||
var options control.ControlOptions
|
||||
var progressMode string
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "debug-shell",
|
||||
Short: "Start a monitor",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
printer, err := progress.NewPrinter(context.TODO(), os.Stderr, os.Stderr, progressMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
c, err := controller.NewController(ctx, options, dockerCli, printer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := c.Close(); err != nil {
|
||||
logrus.Warnf("failed to close server connection %v", err)
|
||||
}
|
||||
}()
|
||||
con := console.Current()
|
||||
if err := con.SetRaw(); err != nil {
|
||||
return errors.Errorf("failed to configure terminal: %v", err)
|
||||
}
|
||||
|
||||
err = monitor.RunMonitor(ctx, "", nil, controllerapi.InvokeConfig{
|
||||
Tty: true,
|
||||
}, c, dockerCli.In(), os.Stdout, os.Stderr, printer)
|
||||
con.Reset()
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
|
||||
flags.StringVar(&options.Root, "root", "", "Specify root directory of server to connect [experimental]")
|
||||
flags.BoolVar(&options.Detach, "detach", runtime.GOOS == "linux", "Detach buildx server (supported only on linux) [experimental]")
|
||||
flags.StringVar(&options.ServerConfig, "server-config", "", "Specify buildx server config file (used only when launching new server) [experimental]")
|
||||
flags.StringVar(&progressMode, "progress", "auto", `Set type of progress output ("auto", "plain", "tty"). Use plain to show container output`)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func addDebugShellCommand(cmd *cobra.Command, dockerCli command.Cli) {
|
||||
cmd.AddCommand(
|
||||
debugShellCmd(dockerCli),
|
||||
)
|
||||
}
|
96
commands/debug/root.go
Normal file
96
commands/debug/root.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/docker/buildx/controller"
|
||||
"github.com/docker/buildx/controller/control"
|
||||
controllerapi "github.com/docker/buildx/controller/pb"
|
||||
"github.com/docker/buildx/monitor"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/moby/buildkit/util/progress/progressui"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// DebugConfig is a user-specified configuration for the debugger.
|
||||
type DebugConfig struct {
|
||||
// InvokeFlag is a flag to configure the launched debugger and the commaned executed on the debugger.
|
||||
InvokeFlag string
|
||||
|
||||
// OnFlag is a flag to configure the timing of launching the debugger.
|
||||
OnFlag string
|
||||
}
|
||||
|
||||
// DebuggableCmd is a command that supports debugger with recognizing the user-specified DebugConfig.
|
||||
type DebuggableCmd interface {
|
||||
// NewDebugger returns the new *cobra.Command with support for the debugger with recognizing DebugConfig.
|
||||
NewDebugger(*DebugConfig) *cobra.Command
|
||||
}
|
||||
|
||||
func RootCmd(dockerCli command.Cli, children ...DebuggableCmd) *cobra.Command {
|
||||
var controlOptions control.ControlOptions
|
||||
var progressMode string
|
||||
var options DebugConfig
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "debug",
|
||||
Short: "Start debugger",
|
||||
Args: cobra.NoArgs,
|
||||
Annotations: map[string]string{
|
||||
"experimentalCLI": "",
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
printer, err := progress.NewPrinter(context.TODO(), os.Stderr, progressui.DisplayMode(progressMode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
c, err := controller.NewController(ctx, controlOptions, dockerCli, printer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := c.Close(); err != nil {
|
||||
logrus.Warnf("failed to close server connection %v", err)
|
||||
}
|
||||
}()
|
||||
con := console.Current()
|
||||
if err := con.SetRaw(); err != nil {
|
||||
return errors.Errorf("failed to configure terminal: %v", err)
|
||||
}
|
||||
|
||||
_, err = monitor.RunMonitor(ctx, "", nil, controllerapi.InvokeConfig{
|
||||
Tty: true,
|
||||
}, c, dockerCli.In(), os.Stdout, os.Stderr, printer)
|
||||
con.Reset()
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
flags.StringVar(&options.InvokeFlag, "invoke", "", "Launch a monitor with executing specified command")
|
||||
flags.SetAnnotation("invoke", "experimentalCLI", nil)
|
||||
flags.StringVar(&options.OnFlag, "on", "error", "When to launch the monitor ([always, error])")
|
||||
flags.SetAnnotation("on", "experimentalCLI", nil)
|
||||
|
||||
flags.StringVar(&controlOptions.Root, "root", "", "Specify root directory of server to connect for the monitor")
|
||||
flags.SetAnnotation("root", "experimentalCLI", nil)
|
||||
flags.BoolVar(&controlOptions.Detach, "detach", runtime.GOOS == "linux", "Detach buildx server for the monitor (supported only on linux)")
|
||||
flags.SetAnnotation("detach", "experimentalCLI", nil)
|
||||
flags.StringVar(&controlOptions.ServerConfig, "server-config", "", "Specify buildx server config file for the monitor (used only when launching new server)")
|
||||
flags.SetAnnotation("server-config", "experimentalCLI", nil)
|
||||
flags.StringVar(&progressMode, "progress", "auto", `Set type of progress output ("auto", "plain", "tty") for the monitor. Use plain to show container output`)
|
||||
|
||||
for _, c := range children {
|
||||
cmd.AddCommand(c.NewDebugger(&options))
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
@@ -39,7 +39,7 @@ func runDiskUsage(dockerCli command.Cli, opts duOptions) error {
|
||||
return err
|
||||
}
|
||||
|
||||
nodes, err := b.LoadNodes(ctx, false)
|
||||
nodes, err := b.LoadNodes(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -7,13 +7,14 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/buildx/builder"
|
||||
"github.com/docker/buildx/util/cobrautil/completion"
|
||||
"github.com/docker/buildx/util/imagetools"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/moby/buildkit/util/appcontext"
|
||||
"github.com/moby/buildkit/util/progress/progressui"
|
||||
"github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
@@ -25,6 +26,7 @@ type createOptions struct {
|
||||
builder string
|
||||
files []string
|
||||
tags []string
|
||||
annotations []string
|
||||
dryrun bool
|
||||
actionAppend bool
|
||||
progress string
|
||||
@@ -154,7 +156,7 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
dt, desc, err := r.Combine(ctx, srcs)
|
||||
dt, desc, err := r.Combine(ctx, srcs, in.annotations)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -169,7 +171,7 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
|
||||
|
||||
ctx2, cancel := context.WithCancel(context.TODO())
|
||||
defer cancel()
|
||||
printer, err := progress.NewPrinter(ctx2, os.Stderr, os.Stderr, in.progress)
|
||||
printer, err := progress.NewPrinter(ctx2, os.Stderr, progressui.DisplayMode(in.progress))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -283,6 +285,7 @@ func createCmd(dockerCli command.Cli, opts RootOptions) *cobra.Command {
|
||||
flags.BoolVar(&options.dryrun, "dry-run", false, "Show final image instead of pushing")
|
||||
flags.BoolVar(&options.actionAppend, "append", false, "Append to existing manifest")
|
||||
flags.StringVar(&options.progress, "progress", "auto", `Set type of progress output ("auto", "plain", "tty"). Use plain to show container output`)
|
||||
flags.StringArrayVarP(&options.annotations, "annotation", "", []string{}, "Add annotation to the image")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ func runInspect(dockerCli command.Cli, in inspectOptions) error {
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, 20*time.Second)
|
||||
defer cancel()
|
||||
|
||||
nodes, err := b.LoadNodes(timeoutCtx, true)
|
||||
nodes, err := b.LoadNodes(timeoutCtx, builder.WithData())
|
||||
if in.bootstrap {
|
||||
var ok bool
|
||||
ok, err = b.Boot(ctx)
|
||||
@@ -48,7 +48,7 @@ func runInspect(dockerCli command.Cli, in inspectOptions) error {
|
||||
return err
|
||||
}
|
||||
if ok {
|
||||
nodes, err = b.LoadNodes(timeoutCtx, true)
|
||||
nodes, err = b.LoadNodes(timeoutCtx, builder.WithData())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,10 @@ func runInspect(dockerCli command.Cli, in inspectOptions) error {
|
||||
if nodes[i].Version != "" {
|
||||
fmt.Fprintf(w, "Buildkit:\t%s\n", nodes[i].Version)
|
||||
}
|
||||
fmt.Fprintf(w, "Platforms:\t%s\n", strings.Join(platformutil.FormatInGroups(n.Node.Platforms, n.Platforms), ", "))
|
||||
platforms := platformutil.FormatInGroups(n.Node.Platforms, n.Platforms)
|
||||
if len(platforms) > 0 {
|
||||
fmt.Fprintf(w, "Platforms:\t%s\n", strings.Join(platforms, ", "))
|
||||
}
|
||||
if debug.IsEnabled() {
|
||||
fmt.Fprintf(w, "Features:\n")
|
||||
features := nodes[i].Driver.Features(ctx)
|
||||
|
@@ -49,7 +49,7 @@ func runLs(dockerCli command.Cli, in lsOptions) error {
|
||||
for _, b := range builders {
|
||||
func(b *builder.Builder) {
|
||||
eg.Go(func() error {
|
||||
_, _ = b.LoadNodes(timeoutCtx, true)
|
||||
_, _ = b.LoadNodes(timeoutCtx, builder.WithData())
|
||||
return nil
|
||||
})
|
||||
}(b)
|
||||
|
@@ -60,7 +60,7 @@ func runPrune(dockerCli command.Cli, opts pruneOptions) error {
|
||||
return err
|
||||
}
|
||||
|
||||
nodes, err := b.LoadNodes(ctx, false)
|
||||
nodes, err := b.LoadNodes(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -55,7 +55,7 @@ func runRm(dockerCli command.Cli, in rmOptions) error {
|
||||
return err
|
||||
}
|
||||
|
||||
nodes, err := b.LoadNodes(ctx, false)
|
||||
nodes, err := b.LoadNodes(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -139,7 +139,7 @@ func rmAllInactive(ctx context.Context, txn *store.Txn, dockerCli command.Cli, i
|
||||
for _, b := range builders {
|
||||
func(b *builder.Builder) {
|
||||
eg.Go(func() error {
|
||||
nodes, err := b.LoadNodes(timeoutCtx, true)
|
||||
nodes, err := b.LoadNodes(timeoutCtx, builder.WithData())
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot load %s", b.Name)
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package commands
|
||||
import (
|
||||
"os"
|
||||
|
||||
debugcmd "github.com/docker/buildx/commands/debug"
|
||||
imagetoolscmd "github.com/docker/buildx/commands/imagetools"
|
||||
"github.com/docker/buildx/controller/remote"
|
||||
"github.com/docker/buildx/util/cobrautil/completion"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli-plugins/plugin"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/debug"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
@@ -40,6 +42,11 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
|
||||
cmd.TraverseChildren = true
|
||||
cmd.DisableFlagsInUseLine = true
|
||||
cli.DisableFlagsInUseLine(cmd)
|
||||
|
||||
// DEBUG=1 should perform the same as --debug at the docker root level
|
||||
if debug.IsEnabled() {
|
||||
debug.Enable()
|
||||
}
|
||||
}
|
||||
|
||||
logrus.SetFormatter(&logutil.Formatter{})
|
||||
@@ -52,17 +59,6 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
|
||||
"using default config store",
|
||||
))
|
||||
|
||||
// filter out useless commandConn.CloseWrite warning message that can occur
|
||||
// when listing builder instances with "buildx ls" for those that are
|
||||
// unreachable: "commandConn.CloseWrite: commandconn: failed to wait: signal: killed"
|
||||
// https://github.com/docker/cli/blob/3fb4fb83dfb5db0c0753a8316f21aea54dab32c5/cli/connhelper/commandconn/commandconn.go#L203-L214
|
||||
logrus.AddHook(logutil.NewFilter([]logrus.Level{
|
||||
logrus.WarnLevel,
|
||||
},
|
||||
"commandConn.CloseWrite:",
|
||||
"commandConn.CloseRead:",
|
||||
))
|
||||
|
||||
addCommands(cmd, dockerCli)
|
||||
return cmd
|
||||
}
|
||||
@@ -76,7 +72,7 @@ func addCommands(cmd *cobra.Command, dockerCli command.Cli) {
|
||||
rootFlags(opts, cmd.PersistentFlags())
|
||||
|
||||
cmd.AddCommand(
|
||||
buildCmd(dockerCli, opts),
|
||||
buildCmd(dockerCli, opts, nil),
|
||||
bakeCmd(dockerCli, opts),
|
||||
createCmd(dockerCli),
|
||||
rmCmd(dockerCli, opts),
|
||||
@@ -92,8 +88,10 @@ func addCommands(cmd *cobra.Command, dockerCli command.Cli) {
|
||||
imagetoolscmd.RootCmd(dockerCli, imagetoolscmd.RootOptions{Builder: &opts.builder}),
|
||||
)
|
||||
if isExperimental() {
|
||||
cmd.AddCommand(debugcmd.RootCmd(dockerCli,
|
||||
newDebuggableBuild(dockerCli, opts),
|
||||
))
|
||||
remote.AddControllerCommands(cmd, dockerCli)
|
||||
addDebugShellCommand(cmd, dockerCli)
|
||||
}
|
||||
|
||||
cmd.RegisterFlagCompletionFunc( //nolint:errcheck
|
||||
|
@@ -25,7 +25,7 @@ func runStop(dockerCli command.Cli, in stopOptions) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nodes, err := b.LoadNodes(ctx, false)
|
||||
nodes, err := b.LoadNodes(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -35,10 +35,7 @@ func runUse(dockerCli command.Cli, in useOptions) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := txn.SetCurrent(ep, "", false, false); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return txn.SetCurrent(ep, "", false, false)
|
||||
}
|
||||
list, err := dockerCli.ContextStore().List()
|
||||
if err != nil {
|
||||
@@ -58,11 +55,7 @@ func runUse(dockerCli command.Cli, in useOptions) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := txn.SetCurrent(ep, in.builder, in.isGlobal, in.isDefault); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return txn.SetCurrent(ep, in.builder, in.isGlobal, in.isDefault)
|
||||
}
|
||||
|
||||
func useCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
||||
|
@@ -53,7 +53,9 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
|
||||
InStream: inStream,
|
||||
NamedContexts: contexts,
|
||||
},
|
||||
Ref: in.Ref,
|
||||
BuildArgs: in.BuildArgs,
|
||||
CgroupParent: in.CgroupParent,
|
||||
ExtraHosts: in.ExtraHosts,
|
||||
Labels: in.Labels,
|
||||
NetworkMode: in.NetworkMode,
|
||||
@@ -64,6 +66,7 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
|
||||
Tags: in.Tags,
|
||||
Target: in.Target,
|
||||
Ulimits: controllerUlimitOpt2DockerUlimit(in.Ulimits),
|
||||
GroupRef: in.GroupRef,
|
||||
}
|
||||
|
||||
platforms, err := platformutil.Parse(in.Platforms)
|
||||
@@ -73,7 +76,7 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
|
||||
opts.Platforms = platforms
|
||||
|
||||
dockerConfig := config.LoadDefaultConfigFile(os.Stderr)
|
||||
opts.Session = append(opts.Session, authprovider.NewDockerAuthProvider(dockerConfig))
|
||||
opts.Session = append(opts.Session, authprovider.NewDockerAuthProvider(dockerConfig, nil))
|
||||
|
||||
secrets, err := controllerapi.CreateSecrets(in.Secrets)
|
||||
if err != nil {
|
||||
@@ -129,6 +132,17 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
annotations, err := buildflags.ParseAnnotations(in.Annotations)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, o := range outputs {
|
||||
for k, v := range annotations {
|
||||
o.Attrs[k.String()] = v
|
||||
}
|
||||
}
|
||||
|
||||
opts.Exports = outputs
|
||||
|
||||
opts.CacheFrom = controllerapi.CreateCaches(in.CacheFrom)
|
||||
@@ -168,7 +182,7 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
|
||||
if err = updateLastActivity(dockerCli, b.NodeGroup); err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "failed to update builder last activity time")
|
||||
}
|
||||
nodes, err := b.LoadNodes(ctx, false)
|
||||
nodes, err := b.LoadNodes(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@@ -299,6 +299,9 @@ type BuildOptions struct {
|
||||
ExportPush bool `protobuf:"varint,26,opt,name=ExportPush,proto3" json:"ExportPush,omitempty"`
|
||||
ExportLoad bool `protobuf:"varint,27,opt,name=ExportLoad,proto3" json:"ExportLoad,omitempty"`
|
||||
SourcePolicy *pb.Policy `protobuf:"bytes,28,opt,name=SourcePolicy,proto3" json:"SourcePolicy,omitempty"`
|
||||
Ref string `protobuf:"bytes,29,opt,name=Ref,proto3" json:"Ref,omitempty"`
|
||||
GroupRef string `protobuf:"bytes,30,opt,name=GroupRef,proto3" json:"GroupRef,omitempty"`
|
||||
Annotations []string `protobuf:"bytes,31,rep,name=Annotations,proto3" json:"Annotations,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -524,6 +527,27 @@ func (m *BuildOptions) GetSourcePolicy() *pb.Policy {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *BuildOptions) GetRef() string {
|
||||
if m != nil {
|
||||
return m.Ref
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *BuildOptions) GetGroupRef() string {
|
||||
if m != nil {
|
||||
return m.GroupRef
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *BuildOptions) GetAnnotations() []string {
|
||||
if m != nil {
|
||||
return m.Annotations
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ExportEntry struct {
|
||||
Type string `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"`
|
||||
Attrs map[string]string `protobuf:"bytes,2,rep,name=Attrs,proto3" json:"Attrs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
@@ -1527,6 +1551,7 @@ func (m *InitMessage) GetInvokeConfig() *InvokeConfig {
|
||||
type InvokeConfig struct {
|
||||
Entrypoint []string `protobuf:"bytes,1,rep,name=Entrypoint,proto3" json:"Entrypoint,omitempty"`
|
||||
Cmd []string `protobuf:"bytes,2,rep,name=Cmd,proto3" json:"Cmd,omitempty"`
|
||||
NoCmd bool `protobuf:"varint,11,opt,name=NoCmd,proto3" json:"NoCmd,omitempty"`
|
||||
Env []string `protobuf:"bytes,3,rep,name=Env,proto3" json:"Env,omitempty"`
|
||||
User string `protobuf:"bytes,4,opt,name=User,proto3" json:"User,omitempty"`
|
||||
NoUser bool `protobuf:"varint,5,opt,name=NoUser,proto3" json:"NoUser,omitempty"`
|
||||
@@ -1578,6 +1603,13 @@ func (m *InvokeConfig) GetCmd() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *InvokeConfig) GetNoCmd() bool {
|
||||
if m != nil {
|
||||
return m.NoCmd
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *InvokeConfig) GetEnv() []string {
|
||||
if m != nil {
|
||||
return m.Env
|
||||
@@ -2046,125 +2078,128 @@ func init() {
|
||||
func init() { proto.RegisterFile("controller.proto", fileDescriptor_ed7f10298fa1d90f) }
|
||||
|
||||
var fileDescriptor_ed7f10298fa1d90f = []byte{
|
||||
// 1881 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x58, 0x5f, 0x6f, 0xdb, 0xc8,
|
||||
0x11, 0x2f, 0x25, 0x59, 0x7f, 0x46, 0x96, 0xe3, 0x6c, 0x9d, 0x74, 0xc3, 0xa4, 0x17, 0x87, 0x49,
|
||||
0xae, 0x42, 0x53, 0x48, 0x77, 0xbe, 0xa6, 0xbe, 0x5c, 0xee, 0x80, 0xda, 0xb2, 0x05, 0xfb, 0x90,
|
||||
0xd8, 0xc6, 0xca, 0xc9, 0xa1, 0x2d, 0xd0, 0x80, 0x92, 0xd6, 0x32, 0x21, 0x8a, 0xab, 0x72, 0x57,
|
||||
0xb6, 0xd5, 0xa7, 0xbe, 0xf4, 0xad, 0xe8, 0xf7, 0x28, 0xfa, 0x11, 0xfa, 0xd2, 0x7e, 0xa1, 0xa2,
|
||||
0x1f, 0xa1, 0xd8, 0x3f, 0xa4, 0x48, 0x4b, 0x94, 0xed, 0xf6, 0x49, 0x3b, 0xc3, 0xdf, 0x6f, 0x76,
|
||||
0x67, 0x38, 0x3b, 0x33, 0x14, 0xac, 0xf7, 0x58, 0x20, 0x42, 0xe6, 0xfb, 0x34, 0x6c, 0x8c, 0x43,
|
||||
0x26, 0x18, 0xda, 0xe8, 0x4e, 0x3c, 0xbf, 0x7f, 0xd5, 0x48, 0x3c, 0xb8, 0xf8, 0xd2, 0x7e, 0x3b,
|
||||
0xf0, 0xc4, 0xf9, 0xa4, 0xdb, 0xe8, 0xb1, 0x51, 0x73, 0xc4, 0xba, 0xd3, 0xa6, 0x42, 0x0d, 0x3d,
|
||||
0xd1, 0x74, 0xc7, 0x5e, 0x93, 0xd3, 0xf0, 0xc2, 0xeb, 0x51, 0xde, 0x34, 0xa4, 0xe8, 0x57, 0x9b,
|
||||
0xb4, 0x5f, 0x67, 0x92, 0x39, 0x9b, 0x84, 0x3d, 0x3a, 0x66, 0xbe, 0xd7, 0x9b, 0x36, 0xc7, 0xdd,
|
||||
0xa6, 0x5e, 0x69, 0x9a, 0x53, 0x87, 0x8d, 0x77, 0x1e, 0x17, 0x27, 0x21, 0xeb, 0x51, 0xce, 0x29,
|
||||
0x27, 0xf4, 0x0f, 0x13, 0xca, 0x05, 0x5a, 0x87, 0x3c, 0xa1, 0x67, 0xd8, 0xda, 0xb4, 0xea, 0x15,
|
||||
0x22, 0x97, 0xce, 0x09, 0x3c, 0xb8, 0x86, 0xe4, 0x63, 0x16, 0x70, 0x8a, 0xb6, 0x61, 0xe5, 0x30,
|
||||
0x38, 0x63, 0x1c, 0x5b, 0x9b, 0xf9, 0x7a, 0x75, 0xeb, 0x59, 0x63, 0x91, 0x73, 0x0d, 0xc3, 0x93,
|
||||
0x48, 0xa2, 0xf1, 0x0e, 0x87, 0x6a, 0x42, 0x8b, 0x9e, 0x40, 0x25, 0x12, 0xf7, 0xcc, 0xc6, 0x33,
|
||||
0x05, 0x6a, 0xc3, 0xea, 0x61, 0x70, 0xc1, 0x86, 0xb4, 0xc5, 0x82, 0x33, 0x6f, 0x80, 0x73, 0x9b,
|
||||
0x56, 0xbd, 0xba, 0xe5, 0x2c, 0xde, 0x2c, 0x89, 0x24, 0x29, 0x9e, 0xf3, 0x3d, 0xe0, 0x3d, 0x8f,
|
||||
0xf7, 0x58, 0x10, 0xd0, 0x5e, 0xe4, 0x4c, 0xa6, 0xd3, 0xe9, 0x33, 0xe5, 0xae, 0x9d, 0xc9, 0x79,
|
||||
0x0c, 0x8f, 0x16, 0xd8, 0xd2, 0x61, 0x71, 0x7e, 0x0f, 0xab, 0xbb, 0xf2, 0x6c, 0xd9, 0xc6, 0xbf,
|
||||
0x85, 0xd2, 0xf1, 0x58, 0x78, 0x2c, 0xe0, 0xcb, 0xbd, 0x51, 0x66, 0x0c, 0x92, 0x44, 0x14, 0xe7,
|
||||
0x9f, 0x55, 0xb3, 0x81, 0x51, 0xa0, 0x4d, 0xa8, 0xb6, 0x58, 0x20, 0xe8, 0x95, 0x38, 0x71, 0xc5,
|
||||
0xb9, 0xd9, 0x28, 0xa9, 0x42, 0x9f, 0xc3, 0xda, 0x1e, 0xeb, 0x0d, 0x69, 0x78, 0xe6, 0xf9, 0xf4,
|
||||
0xc8, 0x1d, 0x51, 0xe3, 0xd2, 0x35, 0x2d, 0xfa, 0x4e, 0x7a, 0xed, 0x05, 0xa2, 0x3d, 0x09, 0x7a,
|
||||
0x38, 0xaf, 0x8e, 0xf6, 0x34, 0xeb, 0xad, 0x1a, 0x18, 0x99, 0x31, 0xd0, 0xef, 0xa0, 0x26, 0xcd,
|
||||
0xf4, 0xcd, 0xd6, 0x1c, 0x17, 0x54, 0x62, 0xbc, 0xbe, 0xd9, 0xbb, 0x46, 0x8a, 0xb7, 0x1f, 0x88,
|
||||
0x70, 0x4a, 0xd2, 0xb6, 0xd0, 0x06, 0xac, 0xec, 0xf8, 0x3e, 0xbb, 0xc4, 0x2b, 0x9b, 0xf9, 0x7a,
|
||||
0x85, 0x68, 0x01, 0xfd, 0x0a, 0x4a, 0x3b, 0x42, 0x50, 0x2e, 0x38, 0x2e, 0xaa, 0xcd, 0x9e, 0x2c,
|
||||
0xde, 0x4c, 0x83, 0x48, 0x04, 0x46, 0xc7, 0x50, 0x51, 0xfb, 0xef, 0x84, 0x03, 0x8e, 0x4b, 0x8a,
|
||||
0xf9, 0xe5, 0x2d, 0x8e, 0x19, 0x73, 0xf4, 0x11, 0x67, 0x36, 0xd0, 0x3e, 0x54, 0x5a, 0x6e, 0xef,
|
||||
0x9c, 0xb6, 0x43, 0x36, 0xc2, 0x65, 0x65, 0xf0, 0x67, 0x8b, 0x0d, 0x2a, 0x98, 0x31, 0x68, 0xcc,
|
||||
0xc4, 0x4c, 0xb4, 0x03, 0x25, 0x25, 0x9c, 0x32, 0x5c, 0xb9, 0x9b, 0x91, 0x88, 0x87, 0x1c, 0x58,
|
||||
0x6d, 0x0d, 0x42, 0x36, 0x19, 0x9f, 0xb8, 0x21, 0x0d, 0x04, 0x06, 0xf5, 0xaa, 0x53, 0x3a, 0xf4,
|
||||
0x16, 0x4a, 0xfb, 0x57, 0x63, 0x16, 0x0a, 0x8e, 0xab, 0xcb, 0x2e, 0xaf, 0x06, 0x99, 0x0d, 0x0c,
|
||||
0x03, 0x7d, 0x06, 0xb0, 0x7f, 0x25, 0x42, 0xf7, 0x80, 0xc9, 0xb0, 0xaf, 0xaa, 0xd7, 0x91, 0xd0,
|
||||
0xa0, 0x36, 0x14, 0xdf, 0xb9, 0x5d, 0xea, 0x73, 0x5c, 0x53, 0xb6, 0x1b, 0xb7, 0x08, 0xac, 0x26,
|
||||
0xe8, 0x8d, 0x0c, 0x5b, 0xe6, 0xf5, 0x11, 0x15, 0x97, 0x2c, 0x1c, 0xbe, 0x67, 0x7d, 0x8a, 0xd7,
|
||||
0x74, 0x5e, 0x27, 0x54, 0xe8, 0x05, 0xd4, 0x8e, 0x98, 0x0e, 0x9e, 0xe7, 0x0b, 0x1a, 0xe2, 0x7b,
|
||||
0xea, 0x30, 0x69, 0xa5, 0xba, 0xcb, 0xbe, 0x2b, 0xce, 0x58, 0x38, 0xe2, 0x78, 0x5d, 0x21, 0x66,
|
||||
0x0a, 0x99, 0x41, 0x1d, 0xda, 0x0b, 0xa9, 0xe0, 0xf8, 0xfe, 0xb2, 0x0c, 0xd2, 0x20, 0x12, 0x81,
|
||||
0x11, 0x86, 0x52, 0xe7, 0x7c, 0xd4, 0xf1, 0xfe, 0x48, 0x31, 0xda, 0xb4, 0xea, 0x79, 0x12, 0x89,
|
||||
0xe8, 0x15, 0xe4, 0x3b, 0x9d, 0x03, 0xfc, 0x63, 0x65, 0xed, 0x51, 0x86, 0xb5, 0xce, 0x01, 0x91,
|
||||
0x28, 0x84, 0xa0, 0x70, 0xea, 0x0e, 0x38, 0xde, 0x50, 0xe7, 0x52, 0x6b, 0xf4, 0x10, 0x8a, 0xa7,
|
||||
0x6e, 0x38, 0xa0, 0x02, 0x3f, 0x50, 0x3e, 0x1b, 0x09, 0xbd, 0x81, 0xd2, 0x07, 0xdf, 0x1b, 0x79,
|
||||
0x82, 0xe3, 0x87, 0xcb, 0x2e, 0xa7, 0x06, 0x1d, 0x8f, 0x05, 0x89, 0xf0, 0xf2, 0xb4, 0x2a, 0xde,
|
||||
0x34, 0xc4, 0x3f, 0x51, 0x36, 0x23, 0x51, 0x3e, 0x31, 0xe1, 0xc2, 0x78, 0xd3, 0xaa, 0x97, 0x49,
|
||||
0x24, 0xca, 0xa3, 0x9d, 0x4c, 0x7c, 0x1f, 0x3f, 0x52, 0x6a, 0xb5, 0xd6, 0xef, 0x5e, 0xa6, 0xc1,
|
||||
0xc9, 0x84, 0x9f, 0x63, 0x5b, 0x3d, 0x49, 0x68, 0x66, 0xcf, 0xdf, 0x31, 0xb7, 0x8f, 0x1f, 0x27,
|
||||
0x9f, 0x4b, 0x0d, 0x3a, 0x84, 0xd5, 0x8e, 0x6a, 0x4b, 0x27, 0xaa, 0x19, 0xe1, 0x27, 0xca, 0x8f,
|
||||
0x97, 0x0d, 0xd9, 0xb9, 0x1a, 0x51, 0xe7, 0x92, 0x3e, 0x24, 0x9b, 0x57, 0x43, 0x83, 0x49, 0x8a,
|
||||
0x6a, 0xff, 0x1a, 0xd0, 0x7c, 0xd5, 0x90, 0xd5, 0x76, 0x48, 0xa7, 0x51, 0xb5, 0x1d, 0xd2, 0xa9,
|
||||
0x2c, 0x1c, 0x17, 0xae, 0x3f, 0x89, 0x6a, 0x9e, 0x16, 0xbe, 0xc9, 0x7d, 0x6d, 0xd9, 0xdf, 0xc2,
|
||||
0x5a, 0xfa, 0x42, 0xdf, 0x89, 0xfd, 0x06, 0xaa, 0x89, 0xac, 0xbd, 0x0b, 0xd5, 0xf9, 0x97, 0x05,
|
||||
0xd5, 0xc4, 0xd5, 0x52, 0x49, 0x30, 0x1d, 0x53, 0x43, 0x56, 0x6b, 0xb4, 0x0b, 0x2b, 0x3b, 0x42,
|
||||
0x84, 0xb2, 0x45, 0xc8, 0x3c, 0xfa, 0xc5, 0x8d, 0x17, 0xb4, 0xa1, 0xe0, 0xfa, 0x0a, 0x69, 0xaa,
|
||||
0xbc, 0x41, 0x7b, 0x94, 0x0b, 0x2f, 0x70, 0xe5, 0x2d, 0x53, 0x15, 0xbd, 0x42, 0x92, 0x2a, 0xfb,
|
||||
0x6b, 0x80, 0x19, 0xed, 0x4e, 0x3e, 0xfc, 0xdd, 0x82, 0xfb, 0x73, 0x55, 0x68, 0xa1, 0x27, 0x07,
|
||||
0x69, 0x4f, 0xb6, 0x6e, 0x59, 0xd1, 0xe6, 0xfd, 0xf9, 0x3f, 0x4e, 0x7b, 0x04, 0x45, 0x5d, 0xfa,
|
||||
0x17, 0x9e, 0xd0, 0x86, 0xf2, 0x9e, 0xc7, 0xdd, 0xae, 0x4f, 0xfb, 0x8a, 0x5a, 0x26, 0xb1, 0xac,
|
||||
0xfa, 0x8e, 0x3a, 0xbd, 0x8e, 0x9e, 0x16, 0x1c, 0x7d, 0xc7, 0xd1, 0x1a, 0xe4, 0xe2, 0x99, 0x25,
|
||||
0x77, 0xb8, 0x27, 0xc1, 0xb2, 0xe1, 0x6a, 0x57, 0x2b, 0x44, 0x0b, 0x4e, 0x1b, 0x8a, 0xba, 0x6a,
|
||||
0xcc, 0xe1, 0x6d, 0x28, 0xb7, 0x3d, 0x9f, 0xaa, 0xbe, 0xad, 0xcf, 0x1c, 0xcb, 0xd2, 0xbd, 0xfd,
|
||||
0xe0, 0xc2, 0x6c, 0x2b, 0x97, 0xce, 0x76, 0xa2, 0x3d, 0x4b, 0x3f, 0x54, 0x27, 0x37, 0x7e, 0xa8,
|
||||
0xfe, 0xfd, 0x10, 0x8a, 0x6d, 0x16, 0x8e, 0x5c, 0x61, 0x8c, 0x19, 0xc9, 0x71, 0x60, 0xed, 0x30,
|
||||
0xe0, 0x63, 0xda, 0x13, 0xd9, 0x63, 0xde, 0x31, 0xdc, 0x8b, 0x31, 0x66, 0xc0, 0x4b, 0xcc, 0x29,
|
||||
0xd6, 0xdd, 0xe7, 0x94, 0xbf, 0x59, 0x50, 0x89, 0x2b, 0x11, 0x6a, 0x41, 0x51, 0xbd, 0x8d, 0x68,
|
||||
0x5a, 0x7c, 0x75, 0x43, 0xe9, 0x6a, 0x7c, 0x54, 0x68, 0xd3, 0x11, 0x34, 0xd5, 0xfe, 0x01, 0xaa,
|
||||
0x09, 0xf5, 0x82, 0x04, 0xd8, 0x4a, 0x26, 0x40, 0x66, 0x29, 0xd7, 0x9b, 0x24, 0xd3, 0x63, 0x0f,
|
||||
0x8a, 0x5a, 0xb9, 0x30, 0xac, 0x08, 0x0a, 0x07, 0x6e, 0xa8, 0x53, 0x23, 0x4f, 0xd4, 0x5a, 0xea,
|
||||
0x3a, 0xec, 0x4c, 0xa8, 0xd7, 0x93, 0x27, 0x6a, 0xed, 0xfc, 0xc3, 0x82, 0x9a, 0x19, 0xfd, 0x4c,
|
||||
0x04, 0x29, 0xac, 0xeb, 0x1b, 0x4a, 0xc3, 0x48, 0x67, 0xfc, 0x7f, 0xb3, 0x24, 0x94, 0x11, 0xb4,
|
||||
0x71, 0x9d, 0xab, 0xa3, 0x31, 0x67, 0xd2, 0x6e, 0xc1, 0x83, 0x85, 0xd0, 0x3b, 0x5d, 0x91, 0x97,
|
||||
0x70, 0x7f, 0x36, 0xd4, 0x66, 0xe7, 0xc9, 0x06, 0xa0, 0x24, 0xcc, 0x0c, 0xbd, 0x4f, 0xa1, 0x2a,
|
||||
0x3f, 0x12, 0xb2, 0x69, 0x0e, 0xac, 0x6a, 0x80, 0x89, 0x0c, 0x82, 0xc2, 0x90, 0x4e, 0x75, 0x36,
|
||||
0x54, 0x88, 0x5a, 0x3b, 0x7f, 0xb5, 0xe4, 0xac, 0x3f, 0x9e, 0x88, 0xf7, 0x94, 0x73, 0x77, 0x20,
|
||||
0x13, 0xb0, 0x70, 0x18, 0x78, 0xc2, 0x64, 0xdf, 0xe7, 0x59, 0x33, 0xff, 0x78, 0x22, 0x24, 0xcc,
|
||||
0xb0, 0x0e, 0x7e, 0x44, 0x14, 0x0b, 0x6d, 0x43, 0x61, 0xcf, 0x15, 0xae, 0xc9, 0x85, 0x8c, 0x09,
|
||||
0x47, 0x22, 0x12, 0x44, 0x29, 0xee, 0x96, 0xe4, 0x87, 0xcd, 0x78, 0x22, 0x9c, 0x17, 0xb0, 0x7e,
|
||||
0xdd, 0xfa, 0x02, 0xd7, 0xbe, 0x82, 0x6a, 0xc2, 0x8a, 0xba, 0xb7, 0xc7, 0x6d, 0x05, 0x28, 0x13,
|
||||
0xb9, 0x94, 0xbe, 0xc6, 0x07, 0x59, 0xd5, 0x7b, 0x38, 0xf7, 0xa0, 0xa6, 0x4c, 0xc7, 0x11, 0xfc,
|
||||
0x53, 0x0e, 0x4a, 0x91, 0x89, 0xed, 0x94, 0xdf, 0xcf, 0xb2, 0xfc, 0x9e, 0x77, 0xf9, 0x35, 0x14,
|
||||
0x64, 0xfd, 0x30, 0x2e, 0x67, 0x8c, 0x07, 0xed, 0x7e, 0x82, 0x26, 0xe1, 0xe8, 0x3b, 0x28, 0x12,
|
||||
0xca, 0xe5, 0x28, 0xa3, 0x87, 0xfe, 0xe7, 0x8b, 0x89, 0x1a, 0x33, 0x23, 0x1b, 0x92, 0xa4, 0x77,
|
||||
0xbc, 0x41, 0xe0, 0xfa, 0xb8, 0xb0, 0x8c, 0xae, 0x31, 0x09, 0xba, 0x56, 0xcc, 0xc2, 0xfd, 0x67,
|
||||
0x0b, 0xaa, 0x4b, 0x43, 0xbd, 0xfc, 0xb3, 0x6c, 0xee, 0x53, 0x31, 0xff, 0x3f, 0x7e, 0x2a, 0xfe,
|
||||
0xdb, 0x4a, 0x1b, 0x52, 0x53, 0x8d, 0xbc, 0x4f, 0x63, 0xe6, 0x05, 0xc2, 0xa4, 0x6c, 0x42, 0x23,
|
||||
0x0f, 0xda, 0x1a, 0xf5, 0x4d, 0xd1, 0x97, 0xcb, 0x59, 0xf1, 0xce, 0x9b, 0xe2, 0x2d, 0x93, 0xe0,
|
||||
0x03, 0xa7, 0xa1, 0x0a, 0x51, 0x85, 0xa8, 0xb5, 0xac, 0xd7, 0x47, 0x4c, 0x69, 0x57, 0x54, 0xb6,
|
||||
0x18, 0x49, 0xd9, 0xbb, 0xec, 0xe3, 0xa2, 0x76, 0xbc, 0x75, 0xa9, 0xba, 0xd0, 0x11, 0x93, 0xba,
|
||||
0x92, 0x02, 0x6a, 0x41, 0xe2, 0x4e, 0xc5, 0x14, 0x97, 0x75, 0xaa, 0x9d, 0x8a, 0xa9, 0x6c, 0x28,
|
||||
0x84, 0xf9, 0x7e, 0xd7, 0xed, 0x0d, 0x71, 0x45, 0x77, 0xb2, 0x48, 0x96, 0x93, 0x9e, 0x8c, 0xae,
|
||||
0xe7, 0xfa, 0xea, 0x9b, 0xa0, 0x4c, 0x22, 0xd1, 0xd9, 0x81, 0x4a, 0x9c, 0x14, 0xb2, 0x47, 0xb5,
|
||||
0xfb, 0x2a, 0xe8, 0x35, 0x92, 0x6b, 0xf7, 0xa3, 0x7c, 0xce, 0xcd, 0xe7, 0x73, 0x3e, 0x91, 0xcf,
|
||||
0xdb, 0x50, 0x4b, 0xa5, 0x87, 0x04, 0x11, 0x76, 0xc9, 0x8d, 0x21, 0xb5, 0x96, 0xba, 0x16, 0xf3,
|
||||
0xf5, 0x57, 0x6f, 0x8d, 0xa8, 0xb5, 0xf3, 0x1c, 0x6a, 0xa9, 0xc4, 0x58, 0x54, 0x81, 0x9d, 0x67,
|
||||
0x50, 0xeb, 0x08, 0x57, 0x4c, 0x96, 0xfc, 0x4d, 0xf1, 0x1f, 0x0b, 0xd6, 0x22, 0x8c, 0xa9, 0x31,
|
||||
0xbf, 0x84, 0xf2, 0x05, 0x0d, 0x05, 0xbd, 0x8a, 0xbb, 0x0e, 0x9e, 0x1f, 0x34, 0x3f, 0x2a, 0x04,
|
||||
0x89, 0x91, 0xe8, 0x1b, 0x28, 0x73, 0x65, 0x87, 0x46, 0x13, 0xcb, 0x67, 0x59, 0x2c, 0xb3, 0x5f,
|
||||
0x8c, 0x47, 0x4d, 0x28, 0xf8, 0x6c, 0xc0, 0xd5, 0x7b, 0xaf, 0x6e, 0x3d, 0xce, 0xe2, 0xbd, 0x63,
|
||||
0x03, 0xa2, 0x80, 0xe8, 0x2d, 0x94, 0x2f, 0xdd, 0x30, 0xf0, 0x82, 0x41, 0xf4, 0xb5, 0xfc, 0x34,
|
||||
0x8b, 0xf4, 0x83, 0xc6, 0x91, 0x98, 0xe0, 0xd4, 0xe4, 0x75, 0x39, 0x63, 0x26, 0x26, 0xce, 0x6f,
|
||||
0x64, 0xd6, 0x4a, 0xd1, 0xb8, 0x7f, 0x08, 0x35, 0x9d, 0xf9, 0x1f, 0x69, 0xc8, 0xe5, 0xfc, 0x67,
|
||||
0x2d, 0xbb, 0x9d, 0xbb, 0x49, 0x28, 0x49, 0x33, 0x9d, 0x4f, 0xa6, 0xb1, 0x45, 0x0a, 0x99, 0x4b,
|
||||
0x63, 0xb7, 0x37, 0x74, 0x07, 0xd1, 0x7b, 0x8a, 0x44, 0xf9, 0xe4, 0xc2, 0xec, 0xa7, 0x2f, 0x68,
|
||||
0x24, 0xca, 0xdc, 0x0c, 0xe9, 0x85, 0xc7, 0x67, 0xa3, 0x68, 0x2c, 0x6f, 0xfd, 0xa5, 0x04, 0xd0,
|
||||
0x8a, 0xcf, 0x83, 0x4e, 0x60, 0x45, 0xed, 0x87, 0x9c, 0xa5, 0x6d, 0x52, 0xf9, 0x6d, 0x3f, 0xbf,
|
||||
0x45, 0x2b, 0x45, 0x1f, 0x65, 0xf2, 0xab, 0xf1, 0x06, 0xbd, 0xc8, 0x2a, 0x08, 0xc9, 0x09, 0xc9,
|
||||
0x7e, 0x79, 0x03, 0xca, 0xd8, 0xfd, 0x00, 0x45, 0x9d, 0x05, 0x28, 0xab, 0xea, 0x25, 0xf3, 0xd6,
|
||||
0x7e, 0xb1, 0x1c, 0xa4, 0x8d, 0x7e, 0x61, 0x21, 0x62, 0x6a, 0x22, 0x72, 0x96, 0x34, 0x3d, 0x73,
|
||||
0x63, 0xb2, 0x02, 0x90, 0xea, 0x2f, 0x75, 0x0b, 0x7d, 0x0f, 0x45, 0x5d, 0xd5, 0xd0, 0x4f, 0x17,
|
||||
0x13, 0x22, 0x7b, 0xcb, 0x1f, 0xd7, 0xad, 0x2f, 0x2c, 0xf4, 0x1e, 0x0a, 0xb2, 0x9d, 0xa3, 0x8c,
|
||||
0xde, 0x94, 0x98, 0x05, 0x6c, 0x67, 0x19, 0xc4, 0x44, 0xf1, 0x13, 0xc0, 0x6c, 0xa8, 0x40, 0x19,
|
||||
0xff, 0x79, 0xcc, 0x4d, 0x27, 0x76, 0xfd, 0x66, 0xa0, 0xd9, 0xe0, 0xbd, 0xec, 0xa8, 0x67, 0x0c,
|
||||
0x65, 0xf6, 0xd2, 0xf8, 0x1a, 0xd9, 0xce, 0x32, 0x88, 0x31, 0x77, 0x0e, 0xb5, 0xd4, 0x7f, 0xa2,
|
||||
0xe8, 0xe7, 0xd9, 0x4e, 0x5e, 0xff, 0x8b, 0xd5, 0x7e, 0x75, 0x2b, 0xac, 0xd9, 0x49, 0x24, 0xa7,
|
||||
0x32, 0xf3, 0x18, 0x35, 0x6e, 0xf2, 0x3b, 0xfd, 0xff, 0xa6, 0xdd, 0xbc, 0x35, 0x5e, 0xef, 0xba,
|
||||
0x5b, 0xf8, 0x6d, 0x6e, 0xdc, 0xed, 0x16, 0xd5, 0x5f, 0xc5, 0x5f, 0xfd, 0x37, 0x00, 0x00, 0xff,
|
||||
0xff, 0xc1, 0x4b, 0x2d, 0x65, 0xc8, 0x16, 0x00, 0x00,
|
||||
// 1922 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x58, 0x5f, 0x73, 0x1b, 0x49,
|
||||
0x11, 0x67, 0x25, 0x59, 0x7f, 0x5a, 0x96, 0xcf, 0x19, 0x9c, 0x30, 0xd9, 0xe4, 0x12, 0x67, 0x93,
|
||||
0x1c, 0x2a, 0x42, 0xc9, 0x77, 0x3e, 0x82, 0x2f, 0x97, 0xbb, 0x2a, 0x6c, 0xd9, 0xc2, 0xbe, 0x4a,
|
||||
0x6c, 0xd7, 0xca, 0xc9, 0x15, 0x50, 0xc5, 0xd5, 0x5a, 0x1a, 0xcb, 0x5b, 0x5a, 0xed, 0x88, 0x9d,
|
||||
0x91, 0x6d, 0xf1, 0xc4, 0x03, 0xbc, 0x51, 0x14, 0x5f, 0x83, 0xe2, 0x23, 0xf0, 0xc4, 0x37, 0xe2,
|
||||
0x23, 0x50, 0xd3, 0x33, 0xbb, 0x5a, 0x59, 0x5a, 0xd9, 0x86, 0x27, 0x4d, 0xf7, 0xfe, 0xba, 0x7b,
|
||||
0xba, 0xa7, 0xa7, 0xbb, 0x47, 0xb0, 0xda, 0xe1, 0xa1, 0x8c, 0x78, 0x10, 0xb0, 0xa8, 0x31, 0x8c,
|
||||
0xb8, 0xe4, 0x64, 0xed, 0x74, 0xe4, 0x07, 0xdd, 0xab, 0x46, 0xea, 0xc3, 0xc5, 0x17, 0xf6, 0xdb,
|
||||
0x9e, 0x2f, 0xcf, 0x47, 0xa7, 0x8d, 0x0e, 0x1f, 0x6c, 0x0c, 0xf8, 0xe9, 0x78, 0x03, 0x51, 0x7d,
|
||||
0x5f, 0x6e, 0x78, 0x43, 0x7f, 0x43, 0xb0, 0xe8, 0xc2, 0xef, 0x30, 0xb1, 0x61, 0x84, 0xe2, 0x5f,
|
||||
0xad, 0xd2, 0x7e, 0x9d, 0x29, 0x2c, 0xf8, 0x28, 0xea, 0xb0, 0x21, 0x0f, 0xfc, 0xce, 0x78, 0x63,
|
||||
0x78, 0xba, 0xa1, 0x57, 0x5a, 0xcc, 0xa9, 0xc3, 0xda, 0x3b, 0x5f, 0xc8, 0xe3, 0x88, 0x77, 0x98,
|
||||
0x10, 0x4c, 0xb8, 0xec, 0x0f, 0x23, 0x26, 0x24, 0x59, 0x85, 0xbc, 0xcb, 0xce, 0xa8, 0xb5, 0x6e,
|
||||
0xd5, 0x2b, 0xae, 0x5a, 0x3a, 0xc7, 0x70, 0xff, 0x1a, 0x52, 0x0c, 0x79, 0x28, 0x18, 0xd9, 0x82,
|
||||
0xa5, 0x83, 0xf0, 0x8c, 0x0b, 0x6a, 0xad, 0xe7, 0xeb, 0xd5, 0xcd, 0x67, 0x8d, 0x79, 0xce, 0x35,
|
||||
0x8c, 0x9c, 0x42, 0xba, 0x1a, 0xef, 0x08, 0xa8, 0xa6, 0xb8, 0xe4, 0x31, 0x54, 0x62, 0x72, 0xd7,
|
||||
0x18, 0x9e, 0x30, 0x48, 0x0b, 0x96, 0x0f, 0xc2, 0x0b, 0xde, 0x67, 0x4d, 0x1e, 0x9e, 0xf9, 0x3d,
|
||||
0x9a, 0x5b, 0xb7, 0xea, 0xd5, 0x4d, 0x67, 0xbe, 0xb1, 0x34, 0xd2, 0x9d, 0x92, 0x73, 0xbe, 0x03,
|
||||
0xba, 0xeb, 0x8b, 0x0e, 0x0f, 0x43, 0xd6, 0x89, 0x9d, 0xc9, 0x74, 0x7a, 0x7a, 0x4f, 0xb9, 0x6b,
|
||||
0x7b, 0x72, 0x1e, 0xc1, 0xc3, 0x39, 0xba, 0x74, 0x58, 0x9c, 0xdf, 0xc3, 0xf2, 0x8e, 0xda, 0x5b,
|
||||
0xb6, 0xf2, 0x6f, 0xa0, 0x74, 0x34, 0x94, 0x3e, 0x0f, 0xc5, 0x62, 0x6f, 0x50, 0x8d, 0x41, 0xba,
|
||||
0xb1, 0x88, 0xf3, 0xf7, 0x65, 0x63, 0xc0, 0x30, 0xc8, 0x3a, 0x54, 0x9b, 0x3c, 0x94, 0xec, 0x4a,
|
||||
0x1e, 0x7b, 0xf2, 0xdc, 0x18, 0x4a, 0xb3, 0xc8, 0x67, 0xb0, 0xb2, 0xcb, 0x3b, 0x7d, 0x16, 0x9d,
|
||||
0xf9, 0x01, 0x3b, 0xf4, 0x06, 0xcc, 0xb8, 0x74, 0x8d, 0x4b, 0xbe, 0x55, 0x5e, 0xfb, 0xa1, 0x6c,
|
||||
0x8d, 0xc2, 0x0e, 0xcd, 0xe3, 0xd6, 0x9e, 0x66, 0x9d, 0xaa, 0x81, 0xb9, 0x13, 0x09, 0xf2, 0x3b,
|
||||
0xa8, 0x29, 0x35, 0x5d, 0x63, 0x5a, 0xd0, 0x02, 0x26, 0xc6, 0xeb, 0x9b, 0xbd, 0x6b, 0x4c, 0xc9,
|
||||
0xed, 0x85, 0x32, 0x1a, 0xbb, 0xd3, 0xba, 0xc8, 0x1a, 0x2c, 0x6d, 0x07, 0x01, 0xbf, 0xa4, 0x4b,
|
||||
0xeb, 0xf9, 0x7a, 0xc5, 0xd5, 0x04, 0xf9, 0x25, 0x94, 0xb6, 0xa5, 0x64, 0x42, 0x0a, 0x5a, 0x44,
|
||||
0x63, 0x8f, 0xe7, 0x1b, 0xd3, 0x20, 0x37, 0x06, 0x93, 0x23, 0xa8, 0xa0, 0xfd, 0xed, 0xa8, 0x27,
|
||||
0x68, 0x09, 0x25, 0xbf, 0xb8, 0xc5, 0x36, 0x13, 0x19, 0xbd, 0xc5, 0x89, 0x0e, 0xb2, 0x07, 0x95,
|
||||
0xa6, 0xd7, 0x39, 0x67, 0xad, 0x88, 0x0f, 0x68, 0x19, 0x15, 0xfe, 0x74, 0xbe, 0x42, 0x84, 0x19,
|
||||
0x85, 0x46, 0x4d, 0x22, 0x49, 0xb6, 0xa1, 0x84, 0xc4, 0x09, 0xa7, 0x95, 0xbb, 0x29, 0x89, 0xe5,
|
||||
0x88, 0x03, 0xcb, 0xcd, 0x5e, 0xc4, 0x47, 0xc3, 0x63, 0x2f, 0x62, 0xa1, 0xa4, 0x80, 0x47, 0x3d,
|
||||
0xc5, 0x23, 0x6f, 0xa1, 0xb4, 0x77, 0x35, 0xe4, 0x91, 0x14, 0xb4, 0xba, 0xe8, 0xf2, 0x6a, 0x90,
|
||||
0x31, 0x60, 0x24, 0xc8, 0x13, 0x80, 0xbd, 0x2b, 0x19, 0x79, 0xfb, 0x5c, 0x85, 0x7d, 0x19, 0x8f,
|
||||
0x23, 0xc5, 0x21, 0x2d, 0x28, 0xbe, 0xf3, 0x4e, 0x59, 0x20, 0x68, 0x0d, 0x75, 0x37, 0x6e, 0x11,
|
||||
0x58, 0x2d, 0xa0, 0x0d, 0x19, 0x69, 0x95, 0xd7, 0x87, 0x4c, 0x5e, 0xf2, 0xa8, 0xff, 0x9e, 0x77,
|
||||
0x19, 0x5d, 0xd1, 0x79, 0x9d, 0x62, 0x91, 0x17, 0x50, 0x3b, 0xe4, 0x3a, 0x78, 0x7e, 0x20, 0x59,
|
||||
0x44, 0x3f, 0xc1, 0xcd, 0x4c, 0x33, 0xf1, 0x2e, 0x07, 0x9e, 0x3c, 0xe3, 0xd1, 0x40, 0xd0, 0x55,
|
||||
0x44, 0x4c, 0x18, 0x2a, 0x83, 0xda, 0xac, 0x13, 0x31, 0x29, 0xe8, 0xbd, 0x45, 0x19, 0xa4, 0x41,
|
||||
0x6e, 0x0c, 0x26, 0x14, 0x4a, 0xed, 0xf3, 0x41, 0xdb, 0xff, 0x23, 0xa3, 0x64, 0xdd, 0xaa, 0xe7,
|
||||
0xdd, 0x98, 0x24, 0xaf, 0x20, 0xdf, 0x6e, 0xef, 0xd3, 0x1f, 0xa3, 0xb6, 0x87, 0x19, 0xda, 0xda,
|
||||
0xfb, 0xae, 0x42, 0x11, 0x02, 0x85, 0x13, 0xaf, 0x27, 0xe8, 0x1a, 0xee, 0x0b, 0xd7, 0xe4, 0x01,
|
||||
0x14, 0x4f, 0xbc, 0xa8, 0xc7, 0x24, 0xbd, 0x8f, 0x3e, 0x1b, 0x8a, 0xbc, 0x81, 0xd2, 0x87, 0xc0,
|
||||
0x1f, 0xf8, 0x52, 0xd0, 0x07, 0x8b, 0x2e, 0xa7, 0x06, 0x1d, 0x0d, 0xa5, 0x1b, 0xe3, 0xd5, 0x6e,
|
||||
0x31, 0xde, 0x2c, 0xa2, 0x3f, 0x41, 0x9d, 0x31, 0xa9, 0xbe, 0x98, 0x70, 0x51, 0xba, 0x6e, 0xd5,
|
||||
0xcb, 0x6e, 0x4c, 0xaa, 0xad, 0x1d, 0x8f, 0x82, 0x80, 0x3e, 0x44, 0x36, 0xae, 0xf5, 0xd9, 0xab,
|
||||
0x34, 0x38, 0x1e, 0x89, 0x73, 0x6a, 0xe3, 0x97, 0x14, 0x67, 0xf2, 0xfd, 0x1d, 0xf7, 0xba, 0xf4,
|
||||
0x51, 0xfa, 0xbb, 0xe2, 0x90, 0x03, 0x58, 0x6e, 0x63, 0x5b, 0x3a, 0xc6, 0x66, 0x44, 0x1f, 0xa3,
|
||||
0x1f, 0x2f, 0x1b, 0xaa, 0x73, 0x35, 0xe2, 0xce, 0xa5, 0x7c, 0x48, 0x37, 0xaf, 0x86, 0x06, 0xbb,
|
||||
0x53, 0xa2, 0x71, 0x5d, 0xfd, 0x74, 0x52, 0x57, 0x6d, 0x28, 0xff, 0x5a, 0x25, 0xb9, 0x62, 0x3f,
|
||||
0x41, 0x76, 0x42, 0xab, 0x64, 0xda, 0x0e, 0x43, 0x2e, 0x3d, 0x5d, 0x77, 0x9f, 0x62, 0xb8, 0xd3,
|
||||
0x2c, 0xfb, 0x57, 0x40, 0x66, 0xab, 0x90, 0xb2, 0xd2, 0x67, 0xe3, 0xb8, 0x7a, 0xf7, 0xd9, 0x58,
|
||||
0x15, 0xa2, 0x0b, 0x2f, 0x18, 0xc5, 0x35, 0x54, 0x13, 0x5f, 0xe7, 0xbe, 0xb2, 0xec, 0x6f, 0x60,
|
||||
0x65, 0xba, 0x40, 0xdc, 0x49, 0xfa, 0x0d, 0x54, 0x53, 0xb7, 0xe0, 0x2e, 0xa2, 0xce, 0xbf, 0x2d,
|
||||
0xa8, 0xa6, 0xae, 0x2a, 0x26, 0xd5, 0x78, 0xc8, 0x8c, 0x30, 0xae, 0xc9, 0x0e, 0x2c, 0x6d, 0x4b,
|
||||
0x19, 0xa9, 0x96, 0xa3, 0xf2, 0xf2, 0xe7, 0x37, 0x5e, 0xf8, 0x06, 0xc2, 0xf5, 0x95, 0xd4, 0xa2,
|
||||
0x2a, 0x88, 0xbb, 0x4c, 0x48, 0x3f, 0xc4, 0x90, 0x61, 0x87, 0xa8, 0xb8, 0x69, 0x96, 0xfd, 0x15,
|
||||
0xc0, 0x44, 0xec, 0x4e, 0x3e, 0xfc, 0xd3, 0x82, 0x7b, 0x33, 0x55, 0x6d, 0xae, 0x27, 0xfb, 0xd3,
|
||||
0x9e, 0x6c, 0xde, 0xb2, 0x42, 0xce, 0xfa, 0xf3, 0x7f, 0xec, 0xf6, 0x10, 0x8a, 0xba, 0x95, 0xcc,
|
||||
0xdd, 0xa1, 0x0d, 0xe5, 0x5d, 0x5f, 0x78, 0xa7, 0x01, 0xeb, 0xa2, 0x68, 0xd9, 0x4d, 0x68, 0xec,
|
||||
0x63, 0xb8, 0x7b, 0x1d, 0x3d, 0x4d, 0x38, 0xba, 0x66, 0x90, 0x15, 0xc8, 0x25, 0x33, 0x50, 0xee,
|
||||
0x60, 0x57, 0x81, 0x55, 0x03, 0xd7, 0xae, 0x56, 0x5c, 0x4d, 0x38, 0x2d, 0x28, 0xea, 0x2a, 0x34,
|
||||
0x83, 0xb7, 0xa1, 0xdc, 0xf2, 0x03, 0x86, 0x73, 0x80, 0xde, 0x73, 0x42, 0x2b, 0xf7, 0xf6, 0xc2,
|
||||
0x0b, 0x63, 0x56, 0x2d, 0x9d, 0xad, 0x54, 0xbb, 0x57, 0x7e, 0xe0, 0x64, 0x60, 0xfc, 0xc0, 0x79,
|
||||
0xe0, 0x01, 0x14, 0x5b, 0x3c, 0x1a, 0x78, 0xd2, 0x28, 0x33, 0x94, 0xe3, 0xc0, 0xca, 0x41, 0x28,
|
||||
0x86, 0xac, 0x23, 0xb3, 0xc7, 0xc6, 0x23, 0xf8, 0x24, 0xc1, 0x98, 0x81, 0x31, 0x35, 0xf7, 0x58,
|
||||
0x77, 0x9f, 0x7b, 0xfe, 0x61, 0x41, 0x25, 0xa9, 0x6c, 0xa4, 0x09, 0x45, 0x3c, 0x8d, 0x78, 0xfa,
|
||||
0x7c, 0x75, 0x43, 0x29, 0x6c, 0x7c, 0x44, 0xb4, 0xe9, 0x30, 0x5a, 0xd4, 0xfe, 0x1e, 0xaa, 0x29,
|
||||
0xf6, 0x9c, 0x04, 0xd8, 0x4c, 0x27, 0x40, 0x66, 0x6b, 0xd0, 0x46, 0xd2, 0xe9, 0xb1, 0x0b, 0x45,
|
||||
0xcd, 0x9c, 0x1b, 0x56, 0x02, 0x85, 0x7d, 0x2f, 0xd2, 0xa9, 0x91, 0x77, 0x71, 0xad, 0x78, 0x6d,
|
||||
0x7e, 0x26, 0xf1, 0x78, 0xf2, 0x2e, 0xae, 0x9d, 0x7f, 0x59, 0x50, 0x33, 0xa3, 0xa4, 0x89, 0x20,
|
||||
0x83, 0x55, 0x7d, 0x43, 0x59, 0x14, 0xf3, 0x8c, 0xff, 0x6f, 0x16, 0x84, 0x32, 0x86, 0x36, 0xae,
|
||||
0xcb, 0xea, 0x68, 0xcc, 0xa8, 0xb4, 0x9b, 0x70, 0x7f, 0x2e, 0xf4, 0x4e, 0x57, 0xe4, 0x25, 0xdc,
|
||||
0x9b, 0x0c, 0xc9, 0xd9, 0x79, 0xb2, 0x06, 0x24, 0x0d, 0x33, 0x43, 0xf4, 0x53, 0xa8, 0xaa, 0x47,
|
||||
0x47, 0xb6, 0x98, 0x03, 0xcb, 0x1a, 0x60, 0x22, 0x43, 0xa0, 0xd0, 0x67, 0x63, 0x9d, 0x0d, 0x15,
|
||||
0x17, 0xd7, 0xce, 0xdf, 0x2c, 0xf5, 0x76, 0x18, 0x8e, 0xe4, 0x7b, 0x26, 0x84, 0xd7, 0x53, 0x09,
|
||||
0x58, 0x38, 0x08, 0x7d, 0x69, 0xb2, 0xef, 0xb3, 0xac, 0x37, 0xc4, 0x70, 0x24, 0x15, 0xcc, 0x48,
|
||||
0xed, 0xff, 0xc8, 0x45, 0x29, 0xb2, 0x05, 0x85, 0x5d, 0x4f, 0x7a, 0x26, 0x17, 0x32, 0x26, 0x26,
|
||||
0x85, 0x48, 0x09, 0x2a, 0x72, 0xa7, 0xa4, 0x1e, 0x4a, 0xc3, 0x91, 0x74, 0x5e, 0xc0, 0xea, 0x75,
|
||||
0xed, 0x73, 0x5c, 0xfb, 0x12, 0xaa, 0x29, 0x2d, 0x78, 0x6f, 0x8f, 0x5a, 0x08, 0x28, 0xbb, 0x6a,
|
||||
0xa9, 0x7c, 0x4d, 0x36, 0xb2, 0xac, 0x6d, 0x38, 0x9f, 0x40, 0x0d, 0x55, 0x27, 0x11, 0xfc, 0x53,
|
||||
0x0e, 0x4a, 0xb1, 0x8a, 0xad, 0x29, 0xbf, 0x9f, 0x65, 0xf9, 0x3d, 0xeb, 0xf2, 0x6b, 0x28, 0xa8,
|
||||
0xfa, 0x61, 0x5c, 0xce, 0x18, 0x37, 0x5a, 0xdd, 0x94, 0x98, 0x82, 0x93, 0x6f, 0xa1, 0xe8, 0x32,
|
||||
0xa1, 0x46, 0x23, 0xfd, 0x88, 0x78, 0x3e, 0x5f, 0x50, 0x63, 0x26, 0xc2, 0x46, 0x48, 0x89, 0xb7,
|
||||
0xfd, 0x5e, 0xe8, 0x05, 0xb4, 0xb0, 0x48, 0x5c, 0x63, 0x52, 0xe2, 0x9a, 0x31, 0x09, 0xf7, 0x5f,
|
||||
0x2c, 0xa8, 0x2e, 0x0c, 0xf5, 0xe2, 0x67, 0xde, 0xcc, 0xd3, 0x33, 0xff, 0x3f, 0x3e, 0x3d, 0xff,
|
||||
0x9c, 0x9b, 0x56, 0x84, 0x53, 0x92, 0xba, 0x4f, 0x43, 0xee, 0x87, 0xd2, 0xa4, 0x6c, 0x8a, 0xa3,
|
||||
0x36, 0xda, 0x1c, 0x74, 0x4d, 0xd1, 0x57, 0x4b, 0x75, 0xcd, 0x0e, 0xb9, 0xe2, 0x55, 0x31, 0x0d,
|
||||
0x34, 0x31, 0x29, 0xe9, 0x79, 0x53, 0xd2, 0x55, 0x6a, 0x7c, 0x10, 0x2c, 0xc2, 0xc0, 0x55, 0x5c,
|
||||
0x5c, 0xab, 0x2a, 0x7e, 0xc8, 0x91, 0xbb, 0x84, 0xc2, 0x86, 0x42, 0x2b, 0x97, 0x5d, 0x5a, 0xd4,
|
||||
0xe1, 0x68, 0x5e, 0xc6, 0x56, 0x2e, 0xbb, 0xb4, 0x94, 0x58, 0xb9, 0x44, 0x2b, 0x27, 0x72, 0x4c,
|
||||
0xcb, 0x3a, 0x01, 0x4f, 0xe4, 0x58, 0xb5, 0x19, 0x97, 0x07, 0xc1, 0xa9, 0xd7, 0xe9, 0xd3, 0x8a,
|
||||
0xee, 0x6f, 0x31, 0xad, 0xe6, 0x49, 0x15, 0x73, 0xdf, 0x0b, 0xf0, 0xe5, 0x51, 0x76, 0x63, 0xd2,
|
||||
0xd9, 0x86, 0x4a, 0x92, 0x2a, 0xaa, 0x73, 0xb5, 0xba, 0x78, 0x14, 0x35, 0x37, 0xd7, 0xea, 0xc6,
|
||||
0x59, 0x9e, 0x9b, 0xcd, 0xf2, 0x7c, 0x2a, 0xcb, 0xb7, 0xa0, 0x36, 0x95, 0x34, 0x0a, 0xe4, 0xf2,
|
||||
0x4b, 0x61, 0x14, 0xe1, 0x5a, 0xf1, 0x9a, 0x3c, 0xd0, 0x6f, 0xeb, 0x9a, 0x8b, 0x6b, 0xe7, 0x39,
|
||||
0xd4, 0xa6, 0xd2, 0x65, 0x5e, 0x5d, 0x76, 0x9e, 0x41, 0xad, 0x2d, 0x3d, 0x39, 0x5a, 0xf0, 0x67,
|
||||
0xc8, 0x7f, 0x2c, 0x58, 0x89, 0x31, 0xa6, 0xf2, 0xfc, 0x02, 0xca, 0x17, 0x2c, 0x92, 0xec, 0x2a,
|
||||
0xe9, 0x45, 0x74, 0x76, 0x9c, 0xfd, 0x88, 0x08, 0x37, 0x41, 0x92, 0xaf, 0xa1, 0x2c, 0x50, 0x0f,
|
||||
0x8b, 0xe7, 0x98, 0x27, 0x59, 0x52, 0xc6, 0x5e, 0x82, 0x27, 0x1b, 0x50, 0x08, 0x78, 0x4f, 0xe0,
|
||||
0xb9, 0x57, 0x37, 0x1f, 0x65, 0xc9, 0xbd, 0xe3, 0x3d, 0x17, 0x81, 0xe4, 0x2d, 0x94, 0x2f, 0xbd,
|
||||
0x28, 0xf4, 0xc3, 0x5e, 0xfc, 0x26, 0x7f, 0x9a, 0x25, 0xf4, 0xbd, 0xc6, 0xb9, 0x89, 0x80, 0x53,
|
||||
0x53, 0x97, 0xe8, 0x8c, 0x9b, 0x98, 0x38, 0xbf, 0x51, 0xb9, 0xac, 0x48, 0xe3, 0xfe, 0x01, 0xd4,
|
||||
0xf4, 0x7d, 0xf8, 0xc8, 0x22, 0xa1, 0xa6, 0x42, 0x6b, 0xd1, 0x9d, 0xdd, 0x49, 0x43, 0xdd, 0x69,
|
||||
0x49, 0xe7, 0x07, 0xd3, 0xee, 0x62, 0x86, 0xca, 0xa5, 0xa1, 0xd7, 0xe9, 0x7b, 0xbd, 0xf8, 0x9c,
|
||||
0x62, 0x52, 0x7d, 0xb9, 0x30, 0xf6, 0xf4, 0xb5, 0x8d, 0x49, 0x95, 0x9b, 0x11, 0xbb, 0xf0, 0xc5,
|
||||
0x64, 0x40, 0x4d, 0xe8, 0xcd, 0xbf, 0x96, 0x00, 0x9a, 0xc9, 0x7e, 0xc8, 0x31, 0x2c, 0xa1, 0x3d,
|
||||
0xe2, 0x2c, 0x6c, 0x9e, 0xe8, 0xb7, 0xfd, 0xfc, 0x16, 0x0d, 0x96, 0x7c, 0x54, 0xc9, 0x8f, 0x43,
|
||||
0x0f, 0x79, 0x91, 0x55, 0x26, 0xd2, 0x73, 0x93, 0xfd, 0xf2, 0x06, 0x94, 0xd1, 0xfb, 0x01, 0x8a,
|
||||
0x3a, 0x0b, 0x48, 0x56, 0x2d, 0x4c, 0xe7, 0xad, 0xfd, 0x62, 0x31, 0x48, 0x2b, 0xfd, 0xdc, 0x22,
|
||||
0xae, 0xa9, 0x94, 0xc4, 0x59, 0xd0, 0x0a, 0xcd, 0x8d, 0xc9, 0x0a, 0xc0, 0x54, 0xd7, 0xa9, 0x5b,
|
||||
0xe4, 0x3b, 0x28, 0xea, 0x5a, 0x47, 0x3e, 0x9d, 0x2f, 0x10, 0xeb, 0x5b, 0xfc, 0xb9, 0x6e, 0x7d,
|
||||
0x6e, 0x91, 0xf7, 0x50, 0x50, 0x4d, 0x9e, 0x64, 0x74, 0xac, 0xd4, 0x84, 0x60, 0x3b, 0x8b, 0x20,
|
||||
0x26, 0x8a, 0x3f, 0x00, 0x4c, 0x46, 0x0d, 0x92, 0xf1, 0xcf, 0xca, 0xcc, 0xcc, 0x62, 0xd7, 0x6f,
|
||||
0x06, 0x1a, 0x03, 0xef, 0x55, 0x9f, 0x3d, 0xe3, 0x24, 0xb3, 0xc3, 0x26, 0xd7, 0xc8, 0x76, 0x16,
|
||||
0x41, 0x8c, 0xba, 0x73, 0xa8, 0x4d, 0xfd, 0xf3, 0x4a, 0x7e, 0x96, 0xed, 0xe4, 0xf5, 0x3f, 0x72,
|
||||
0xed, 0x57, 0xb7, 0xc2, 0x1a, 0x4b, 0x32, 0x3d, 0xab, 0x99, 0xcf, 0xa4, 0x71, 0x93, 0xdf, 0xd3,
|
||||
0xff, 0xa2, 0xda, 0x1b, 0xb7, 0xc6, 0x6b, 0xab, 0x3b, 0x85, 0xdf, 0xe6, 0x86, 0xa7, 0xa7, 0x45,
|
||||
0xfc, 0x43, 0xfa, 0xcb, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xe3, 0x77, 0x0e, 0x2f, 0x2e, 0x17,
|
||||
0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
@@ -77,6 +77,9 @@ message BuildOptions {
|
||||
bool ExportPush = 26;
|
||||
bool ExportLoad = 27;
|
||||
moby.buildkit.v1.sourcepolicy.Policy SourcePolicy = 28;
|
||||
string Ref = 29;
|
||||
string GroupRef = 30;
|
||||
repeated string Annotations = 31;
|
||||
}
|
||||
|
||||
message ExportEntry {
|
||||
@@ -192,6 +195,7 @@ message InitMessage {
|
||||
message InvokeConfig {
|
||||
repeated string Entrypoint = 1;
|
||||
repeated string Cmd = 2;
|
||||
bool NoCmd = 11; // Do not set cmd but use the image's default
|
||||
repeated string Env = 3;
|
||||
string User = 4;
|
||||
bool NoUser = 5; // Do not set user but use the image's default
|
||||
|
@@ -236,6 +236,7 @@ func TestResolvePaths(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ResolveOptionPaths(&tt.options)
|
||||
require.NoError(t, err)
|
||||
|
@@ -137,7 +137,7 @@ func (m *Manager) StartProcess(pid string, resultCtx *build.ResultHandle, cfg *p
|
||||
go func() {
|
||||
var err error
|
||||
if err = ctr.Exec(ctx, cfg, in.Stdin, in.Stdout, in.Stderr); err != nil {
|
||||
logrus.Errorf("failed to exec process: %v", err)
|
||||
logrus.Debugf("process error: %v", err)
|
||||
}
|
||||
logrus.Debugf("finished process %s %v", pid, cfg.Entrypoint)
|
||||
m.processes.Delete(pid)
|
||||
|
@@ -15,7 +15,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/buildx/build"
|
||||
cbuild "github.com/docker/buildx/controller/build"
|
||||
"github.com/docker/buildx/controller/control"
|
||||
|
@@ -57,9 +57,7 @@ func (m *Server) ListProcesses(ctx context.Context, req *pb.ListProcessesRequest
|
||||
return nil, errors.Errorf("unknown ref %q", req.Ref)
|
||||
}
|
||||
res = new(pb.ListProcessesResponse)
|
||||
for _, p := range s.processes.ListProcesses() {
|
||||
res.Infos = append(res.Infos, p)
|
||||
}
|
||||
res.Infos = append(res.Infos, s.processes.ListProcesses()...)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
variable "GO_VERSION" {
|
||||
default = "1.20"
|
||||
default = null
|
||||
}
|
||||
variable "DOCS_FORMATS" {
|
||||
default = "md"
|
||||
|
@@ -12,18 +12,118 @@ You can define your Bake file in the following file formats:
|
||||
|
||||
By default, Bake uses the following lookup order to find the configuration file:
|
||||
|
||||
1. `docker-bake.override.hcl`
|
||||
2. `docker-bake.hcl`
|
||||
3. `docker-bake.override.json`
|
||||
4. `docker-bake.json`
|
||||
5. `docker-compose.yaml`
|
||||
6. `docker-compose.yml`
|
||||
1. `compose.yaml`
|
||||
2. `compose.yml`
|
||||
3. `docker-compose.yml`
|
||||
4. `docker-compose.yaml`
|
||||
5. `docker-bake.json`
|
||||
6. `docker-bake.override.json`
|
||||
7. `docker-bake.hcl`
|
||||
8. `docker-bake.override.hcl`
|
||||
|
||||
Bake searches for the file in the current working directory.
|
||||
You can specify the file location explicitly using the `--file` flag:
|
||||
|
||||
```console
|
||||
$ docker buildx bake --file=../docker/bake.hcl --print
|
||||
$ docker buildx bake --file ../docker/bake.hcl --print
|
||||
```
|
||||
|
||||
If you don't specify a file explicitly, Bake searches for the file in the
|
||||
current working directory. If more than one Bake file is found, all files are
|
||||
merged into a single definition. Files are merged according to the lookup
|
||||
order. That means that if your project contains both a `compose.yaml` file and
|
||||
a `docker-bake.hcl` file, Bake loads the `compose.yaml` file first, and then
|
||||
the `docker-bake.hcl` file.
|
||||
|
||||
If merged files contain duplicate attribute definitions, those definitions are
|
||||
either merged or overridden by the last occurrence, depending on the attribute.
|
||||
The following attributes are overridden by the last occurrence:
|
||||
|
||||
- `target.cache-to`
|
||||
- `target.dockerfile-inline`
|
||||
- `target.dockerfile`
|
||||
- `target.outputs`
|
||||
- `target.platforms`
|
||||
- `target.pull`
|
||||
- `target.tags`
|
||||
- `target.target`
|
||||
|
||||
For example, if `compose.yaml` and `docker-bake.hcl` both define the `tags`
|
||||
attribute, the `docker-bake.hcl` is used.
|
||||
|
||||
```console
|
||||
$ cat compose.yaml
|
||||
services:
|
||||
webapp:
|
||||
build:
|
||||
context: .
|
||||
tags:
|
||||
- bar
|
||||
$ cat docker-bake.hcl
|
||||
target "webapp" {
|
||||
tags = ["foo"]
|
||||
}
|
||||
$ docker buildx bake --print webapp
|
||||
{
|
||||
"group": {
|
||||
"default": {
|
||||
"targets": [
|
||||
"webapp"
|
||||
]
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"webapp": {
|
||||
"context": ".",
|
||||
"dockerfile": "Dockerfile",
|
||||
"tags": [
|
||||
"foo"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
All other attributes are merged. For example, if `compose.yaml` and
|
||||
`docker-bake.hcl` both define unique entries for the `labels` attribute, all
|
||||
entries are included. Duplicate entries for the same label are overridden.
|
||||
|
||||
```console
|
||||
$ cat compose.yaml
|
||||
services:
|
||||
webapp:
|
||||
build:
|
||||
context: .
|
||||
labels:
|
||||
com.example.foo: "foo"
|
||||
com.example.name: "Alice"
|
||||
$ cat docker-bake.hcl
|
||||
target "webapp" {
|
||||
labels = {
|
||||
"com.example.bar" = "bar"
|
||||
"com.example.name" = "Bob"
|
||||
}
|
||||
}
|
||||
$ docker buildx bake --print webapp
|
||||
{
|
||||
"group": {
|
||||
"default": {
|
||||
"targets": [
|
||||
"webapp"
|
||||
]
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"webapp": {
|
||||
"context": ".",
|
||||
"dockerfile": "Dockerfile",
|
||||
"labels": {
|
||||
"com.example.foo": "foo",
|
||||
"com.example.bar": "bar",
|
||||
"com.example.name": "Bob"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Syntax
|
||||
@@ -115,6 +215,7 @@ The following table shows the complete list of attributes that you can assign to
|
||||
| Name | Type | Description |
|
||||
| ----------------------------------------------- | ------- | -------------------------------------------------------------------- |
|
||||
| [`args`](#targetargs) | Map | Build arguments |
|
||||
| [`annotations`](#targetannotations) | List | Exporter annotations |
|
||||
| [`attest`](#targetattest) | List | Build attestations |
|
||||
| [`cache-from`](#targetcache-from) | List | External cache sources |
|
||||
| [`cache-to`](#targetcache-to) | List | External cache destinations |
|
||||
@@ -171,6 +272,26 @@ target "db" {
|
||||
}
|
||||
```
|
||||
|
||||
### `target.annotations`
|
||||
|
||||
The `annotations` attribute is a shortcut to allow you to easily set a list of
|
||||
annotations on the target.
|
||||
|
||||
```hcl
|
||||
target "default" {
|
||||
output = ["type=image,name=foo"]
|
||||
annotations = ["key=value"]
|
||||
}
|
||||
```
|
||||
|
||||
is the same as
|
||||
|
||||
```hcl
|
||||
target "default" {
|
||||
output = ["type=image,name=foo,annotation.key=value"]
|
||||
}
|
||||
```
|
||||
|
||||
### `target.attest`
|
||||
|
||||
The `attest` attribute lets you apply [build attestations][attestations] to the target.
|
||||
|
@@ -19,11 +19,13 @@ your environment.
|
||||
$ export BUILDX_EXPERIMENTAL=1
|
||||
```
|
||||
|
||||
To start a debug session for a build, you can use the `--invoke` flag with the
|
||||
build command to specify a command to launch in the resulting image.
|
||||
To start a debug session for a build, you can use the `buildx debug` command with `--invoke` flag to specify a command to launch in the resulting image.
|
||||
`buildx debug` command provides `buildx debug build` subcommand that provides the same features as the normal `buildx build` command but allows launching the debugger session after the build.
|
||||
|
||||
Arguments available after `buildx debug build` are the same as the normal `buildx build`.
|
||||
|
||||
```console
|
||||
$ docker buildx build --invoke /bin/sh .
|
||||
$ docker buildx debug --invoke /bin/sh build .
|
||||
[+] Building 4.2s (19/19) FINISHED
|
||||
=> [internal] connecting to local controller 0.0s
|
||||
=> [internal] load build definition from Dockerfile 0.0s
|
||||
@@ -56,16 +58,16 @@ Supported keys are `args` (can be JSON array format), `entrypoint` (can be JSON
|
||||
Example:
|
||||
|
||||
```
|
||||
$ docker buildx build --invoke 'entrypoint=["sh"],"args=[""-c"", ""env | grep -e FOO -e AAA""]","env=[""FOO=bar"", ""AAA=bbb""]"' .
|
||||
$ docker buildx debug --invoke 'entrypoint=["sh"],"args=[""-c"", ""env | grep -e FOO -e AAA""]","env=[""FOO=bar"", ""AAA=bbb""]"' build .
|
||||
```
|
||||
|
||||
#### `on-error`
|
||||
#### `on` flag
|
||||
|
||||
If you want to start a debug session when a build fails, you can use
|
||||
`--invoke=on-error` to start a debug session when the build fails.
|
||||
`--on=error` to start a debug session when the build fails.
|
||||
|
||||
```console
|
||||
$ docker buildx build --invoke on-error .
|
||||
$ docker buildx debug --on=error build .
|
||||
[+] Building 4.2s (19/19) FINISHED
|
||||
=> [internal] connecting to local controller 0.0s
|
||||
=> [internal] load build definition from Dockerfile 0.0s
|
||||
@@ -85,13 +87,13 @@ Interactive container was restarted with process "edmzor60nrag7rh1mbi4o9lm8". Pr
|
||||
|
||||
This allows you to explore the state of the image when the build failed.
|
||||
|
||||
#### `debug-shell`
|
||||
#### Launch the debug session directly with `buildx debug` subcommand
|
||||
|
||||
If you want to drop into a debug session without first starting the build, you
|
||||
can use `--invoke=debug-shell` to start a debug session.
|
||||
can use `buildx debug` command to start a debug session.
|
||||
|
||||
```
|
||||
$ docker buildx build --invoke debug-shell .
|
||||
$ docker buildx debug
|
||||
[+] Building 4.2s (19/19) FINISHED
|
||||
=> [internal] connecting to local controller 0.0s
|
||||
(buildx)
|
||||
@@ -116,12 +118,12 @@ Available commands are:
|
||||
disconnect disconnect a client from a buildx server. Specific session ID can be specified an arg
|
||||
exec execute a process in the interactive container
|
||||
exit exits monitor
|
||||
help shows this message
|
||||
help shows this message. Optionally pass a command name as an argument to print the detailed usage.
|
||||
kill kill buildx server
|
||||
list list buildx sessions
|
||||
ps list processes invoked by "exec". Use "attach" to attach IO to that process
|
||||
reload reloads the context and build it
|
||||
rollback re-runs the interactive container with initial rootfs contents
|
||||
rollback re-runs the interactive container with the step's rootfs contents
|
||||
```
|
||||
|
||||
## Build controllers
|
||||
@@ -135,15 +137,15 @@ To detach the build process from the CLI, you can use the `--detach=true` flag w
|
||||
the build command.
|
||||
|
||||
```console
|
||||
$ docker buildx build --detach=true --invoke /bin/sh .
|
||||
$ docker buildx debug --invoke /bin/sh build --detach=true .
|
||||
```
|
||||
|
||||
If you start a debugging session using the `--invoke` flag with a detached
|
||||
build, then you can attach to it using the `buildx debug-shell` subcommand to
|
||||
build, then you can attach to it using the `buildx debug` command to
|
||||
immediately enter the monitor mode.
|
||||
|
||||
```console
|
||||
$ docker buildx debug-shell
|
||||
$ docker buildx debug
|
||||
[+] Building 0.0s (1/1) FINISHED
|
||||
=> [internal] connecting to remote controller
|
||||
(buildx) list
|
||||
|
@@ -9,24 +9,21 @@ Extended build capabilities with BuildKit
|
||||
|
||||
### Subcommands
|
||||
|
||||
| Name | Description |
|
||||
|:-----------------------------------------------|:-------------------------------------------|
|
||||
| [`_INTERNAL_SERVE`](buildx__INTERNAL_SERVE.md) | |
|
||||
| [`bake`](buildx_bake.md) | Build from a file |
|
||||
| [`build`](buildx_build.md) | Start a build |
|
||||
| [`create`](buildx_create.md) | Create a new builder instance |
|
||||
| [`debug-shell`](buildx_debug-shell.md) | Start a monitor |
|
||||
| [`du`](buildx_du.md) | Disk usage |
|
||||
| [`imagetools`](buildx_imagetools.md) | Commands to work on images in registry |
|
||||
| [`inspect`](buildx_inspect.md) | Inspect current builder instance |
|
||||
| [`install`](buildx_install.md) | Install buildx as a 'docker builder' alias |
|
||||
| [`ls`](buildx_ls.md) | List builder instances |
|
||||
| [`prune`](buildx_prune.md) | Remove build cache |
|
||||
| [`rm`](buildx_rm.md) | Remove a builder instance |
|
||||
| [`stop`](buildx_stop.md) | Stop builder instance |
|
||||
| [`uninstall`](buildx_uninstall.md) | Uninstall the 'docker builder' alias |
|
||||
| [`use`](buildx_use.md) | Set the current builder instance |
|
||||
| [`version`](buildx_version.md) | Show buildx version information |
|
||||
| Name | Description |
|
||||
|:-------------------------------------|:---------------------------------------|
|
||||
| [`bake`](buildx_bake.md) | Build from a file |
|
||||
| [`build`](buildx_build.md) | Start a build |
|
||||
| [`create`](buildx_create.md) | Create a new builder instance |
|
||||
| [`debug`](buildx_debug.md) | Start debugger |
|
||||
| [`du`](buildx_du.md) | Disk usage |
|
||||
| [`imagetools`](buildx_imagetools.md) | Commands to work on images in registry |
|
||||
| [`inspect`](buildx_inspect.md) | Inspect current builder instance |
|
||||
| [`ls`](buildx_ls.md) | List builder instances |
|
||||
| [`prune`](buildx_prune.md) | Remove build cache |
|
||||
| [`rm`](buildx_rm.md) | Remove a builder instance |
|
||||
| [`stop`](buildx_stop.md) | Stop builder instance |
|
||||
| [`use`](buildx_use.md) | Set the current builder instance |
|
||||
| [`version`](buildx_version.md) | Show buildx version information |
|
||||
|
||||
|
||||
### Options
|
||||
|
@@ -17,17 +17,17 @@ Start a build
|
||||
|:-------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------|:----------|:----------------------------------------------------------------------------------------------------|
|
||||
| [`--add-host`](https://docs.docker.com/engine/reference/commandline/build/#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`) |
|
||||
| `--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 |
|
||||
| [`--build-context`](#build-context) | `stringArray` | | Additional build contexts (e.g., name=path) |
|
||||
| [`--builder`](#builder) | `string` | | Override the configured builder instance |
|
||||
| [`--cache-from`](#cache-from) | `stringArray` | | External cache sources (e.g., `user/app:cache`, `type=local,src=path/to/dir`) |
|
||||
| [`--cache-to`](#cache-to) | `stringArray` | | Cache export destinations (e.g., `user/app:cache`, `type=local,dest=path/to/dir`) |
|
||||
| [`--cgroup-parent`](https://docs.docker.com/engine/reference/commandline/build/#cgroup-parent) | `string` | | Optional parent cgroup for the container |
|
||||
| `--detach` | | | Detach buildx server (supported only on linux) [experimental] |
|
||||
| [`--cgroup-parent`](https://docs.docker.com/engine/reference/commandline/build/#cgroup-parent) | `string` | | Set the parent cgroup for the `RUN` instructions during build |
|
||||
| `--detach` | | | Detach buildx server (supported only on linux) |
|
||||
| [`-f`](https://docs.docker.com/engine/reference/commandline/build/#file), [`--file`](https://docs.docker.com/engine/reference/commandline/build/#file) | `string` | | Name of the Dockerfile (default: `PATH/Dockerfile`) |
|
||||
| `--iidfile` | `string` | | Write the image ID to the file |
|
||||
| `--invoke` | `string` | | Invoke a command after the build [experimental] |
|
||||
| `--label` | `stringArray` | | Set metadata for an image |
|
||||
| [`--load`](#load) | | | Shorthand for `--output=type=docker` |
|
||||
| [`--metadata-file`](#metadata-file) | `string` | | Write build result metadata to the file |
|
||||
@@ -36,16 +36,16 @@ Start a build
|
||||
| `--no-cache-filter` | `stringArray` | | Do not cache specified stages |
|
||||
| [`-o`](#output), [`--output`](#output) | `stringArray` | | Output destination (format: `type=local,dest=path`) |
|
||||
| [`--platform`](#platform) | `stringArray` | | Set target platform for build |
|
||||
| `--print` | `string` | | Print result of information request (e.g., outline, targets) [experimental] |
|
||||
| `--print` | `string` | | Print result of information request (e.g., outline, targets) |
|
||||
| [`--progress`](#progress) | `string` | `auto` | Set type of progress output (`auto`, `plain`, `tty`). Use plain to show container output |
|
||||
| [`--provenance`](#provenance) | `string` | | Shorthand for `--attest=type=provenance` |
|
||||
| `--pull` | | | Always attempt to pull all referenced images |
|
||||
| [`--push`](#push) | | | Shorthand for `--output=type=registry` |
|
||||
| `-q`, `--quiet` | | | Suppress the build output and print image ID on success |
|
||||
| `--root` | `string` | | Specify root directory of server to connect [experimental] |
|
||||
| `--root` | `string` | | Specify root directory of server to connect |
|
||||
| [`--sbom`](#sbom) | `string` | | Shorthand for `--attest=type=sbom` |
|
||||
| [`--secret`](#secret) | `stringArray` | | Secret to expose to the build (format: `id=mysecret[,src=/local/secret]`) |
|
||||
| `--server-config` | `string` | | Specify buildx server config file (used only when launching new server) [experimental] |
|
||||
| `--server-config` | `string` | | Specify buildx server config file (used only when launching new server) |
|
||||
| [`--shm-size`](#shm-size) | `bytes` | `0` | Size of `/dev/shm` |
|
||||
| [`--ssh`](#ssh) | `stringArray` | | SSH agent socket or keys to expose to the build (format: `default\|<id>[=<socket>\|<key>[,<key>]]`) |
|
||||
| [`-t`](https://docs.docker.com/engine/reference/commandline/build/#tag), [`--tag`](https://docs.docker.com/engine/reference/commandline/build/#tag) | `stringArray` | | Name and optionally a tag (format: `name:tag`) |
|
||||
@@ -125,7 +125,6 @@ Same as [`docker build` command](https://docs.docker.com/engine/reference/comman
|
||||
There are also useful built-in build args like:
|
||||
|
||||
* `BUILDKIT_CONTEXT_KEEP_GIT_DIR=<bool>` trigger git context to keep the `.git` directory
|
||||
* `BUILDKIT_INLINE_BUILDINFO_ATTRS=<bool>` inline build info attributes in image config or not
|
||||
* `BUILDKIT_INLINE_CACHE=<bool>` inline cache metadata to image config or not
|
||||
* `BUILDKIT_MULTI_PLATFORM=<bool>` opt into deterministic output regardless of multi-platform output or not
|
||||
|
||||
@@ -286,26 +285,6 @@ $ cat metadata.json
|
||||
```
|
||||
```json
|
||||
{
|
||||
"containerimage.buildinfo": {
|
||||
"frontend": "dockerfile.v0",
|
||||
"attrs": {
|
||||
"context": "https://github.com/crazy-max/buildkit-buildsources-test.git#master",
|
||||
"filename": "Dockerfile",
|
||||
"source": "docker/dockerfile:master"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"type": "docker-image",
|
||||
"ref": "docker.io/docker/buildx-bin:0.6.1@sha256:a652ced4a4141977c7daaed0a074dcd9844a78d7d2615465b12f433ae6dd29f0",
|
||||
"pin": "sha256:a652ced4a4141977c7daaed0a074dcd9844a78d7d2615465b12f433ae6dd29f0"
|
||||
},
|
||||
{
|
||||
"type": "docker-image",
|
||||
"ref": "docker.io/library/alpine:3.13",
|
||||
"pin": "sha256:026f721af4cf2843e07bba648e158fb35ecc876d822130633cc49f707f0fc88c"
|
||||
}
|
||||
]
|
||||
},
|
||||
"containerimage.config.digest": "sha256:2937f66a9722f7f4a2df583de2f8cb97fc9196059a410e7f00072fc918930e66",
|
||||
"containerimage.descriptor": {
|
||||
"annotations": {
|
||||
|
@@ -141,7 +141,7 @@ to achieve that.
|
||||
|
||||
Passes additional driver-specific options.
|
||||
|
||||
Note: When using quoted values for example for the `nodeselector` or
|
||||
Note: When using quoted values for the `nodeselector`, `annotations`, `labels` or
|
||||
`tolerations` options, ensure that quotes are escaped correctly for your shell.
|
||||
|
||||
#### `docker` driver
|
||||
@@ -150,9 +150,18 @@ No driver options.
|
||||
|
||||
#### `docker-container` driver
|
||||
|
||||
- `image=IMAGE` - Sets the container image to be used for running buildkit.
|
||||
- `network=NETMODE` - Sets the network mode for running the buildkit container.
|
||||
- `cgroup-parent=CGROUP` - Sets the cgroup parent of the buildkit container if docker is using the "cgroupfs" driver. Defaults to `/docker/buildx`.
|
||||
- `image=IMAGE` - Sets the BuildKit image to use for the container.
|
||||
- `memory=MEMORY` - Sets the amount of memory the container can use.
|
||||
- `memory-swap=MEMORY_SWAP` - Sets the memory swap limit for the container.
|
||||
- `cpu-quota=CPU_QUOTA` - Imposes a CPU CFS quota on the container.
|
||||
- `cpu-period=CPU_PERIOD` - Sets the CPU CFS scheduler period for the container.
|
||||
- `cpu-shares=CPU_SHARES` - Configures CPU shares (relative weight) of the container.
|
||||
- `cpuset-cpus=CPUSET_CPUS` - Limits the set of CPU cores the container can use.
|
||||
- `cpuset-mems=CPUSET_MEMS` - Limits the set of CPU memory nodes the container can use.
|
||||
- `network=NETMODE` - Sets the network mode for the container.
|
||||
- `cgroup-parent=CGROUP` - Sets the cgroup parent of the container if docker is using the "cgroupfs" driver. Defaults to `/docker/buildx`.
|
||||
|
||||
Before you configure the resource limits for the container, read about [configuring runtime resource constraints for containers](https://docs.docker.com/config/containers/resource_constraints/).
|
||||
|
||||
#### `kubernetes` driver
|
||||
|
||||
@@ -165,6 +174,8 @@ No driver options.
|
||||
- `limits.memory` - Sets the limit memory value specified in bytes or with a valid suffix. Example `limits.memory=500Mi`, `limits.memory=4G`
|
||||
- `serviceaccount` - Sets the created pod's service account. Example `serviceaccount=example-sa`
|
||||
- `"nodeselector=label1=value1,label2=value2"` - Sets the kv of `Pod` nodeSelector. No Defaults. Example `nodeselector=kubernetes.io/arch=arm64`
|
||||
- `"annotations=domain/thing1=value1,domain/thing2=value2"` - Sets additional annotations on the deployments and pods. No Defaults. Example `annotations=example.com/owner=sarah`
|
||||
- `"labels=domain/thing1=value1,domain/thing2=value2"` - Sets additional labels on the deployments and pods. No Defaults. Example `labels=example.com/team=rd`
|
||||
- `"tolerations=key=foo,value=bar;key=foo2,operator=exists;key=foo3,effect=NoSchedule"` - Sets the `Pod` tolerations. Accepts the same values as the kube manifest tolera>tions. Key-value pairs are separated by `,`, tolerations are separated by `;`. No Defaults. Example `tolerations=operator=exists`
|
||||
- `rootless=(true|false)` - Run the container as a non-root user without `securityContext.privileged`. Needs Kubernetes 1.19 or later. [Using Ubuntu host kernel is recommended](https://github.com/moby/buildkit/blob/master/docs/rootless.md). Defaults to false.
|
||||
- `loadbalance=(sticky|random)` - Load-balancing strategy. If set to "sticky", the pod is chosen using the hash of the context path. Defaults to "sticky"
|
||||
@@ -221,7 +232,7 @@ building for the same platform.
|
||||
|
||||
```console
|
||||
$ docker buildx create --platform linux/amd64
|
||||
$ docker buildx create --platform linux/arm64,linux/arm/v8
|
||||
$ docker buildx create --platform linux/arm64,linux/arm/v7
|
||||
```
|
||||
|
||||
### <a name="use"></a> Automatically switch to the newly created builder (--use)
|
||||
|
@@ -1,18 +0,0 @@
|
||||
# docker buildx debug-shell
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Start a monitor
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:------------------|:---------|:--------|:-----------------------------------------------------------------------------------------|
|
||||
| `--builder` | `string` | | Override the configured builder instance |
|
||||
| `--detach` | | | Detach buildx server (supported only on linux) [experimental] |
|
||||
| `--progress` | `string` | `auto` | Set type of progress output (`auto`, `plain`, `tty`). Use plain to show container output |
|
||||
| `--root` | `string` | | Specify root directory of server to connect [experimental] |
|
||||
| `--server-config` | `string` | | Specify buildx server config file (used only when launching new server) [experimental] |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
27
docs/reference/buildx_debug.md
Normal file
27
docs/reference/buildx_debug.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# docker buildx debug
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Start debugger
|
||||
|
||||
### Subcommands
|
||||
|
||||
| Name | Description |
|
||||
|:---------------------------------|:--------------|
|
||||
| [`build`](buildx_debug_build.md) | Start a build |
|
||||
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:------------------|:---------|:--------|:---------------------------------------------------------------------------------------------------------|
|
||||
| `--builder` | `string` | | Override the configured builder instance |
|
||||
| `--detach` | | | Detach buildx server for the monitor (supported only on linux) |
|
||||
| `--invoke` | `string` | | Launch a monitor with executing specified command |
|
||||
| `--on` | `string` | `error` | When to launch the monitor ([always, error]) |
|
||||
| `--progress` | `string` | `auto` | Set type of progress output (`auto`, `plain`, `tty`) for the monitor. Use plain to show container output |
|
||||
| `--root` | `string` | | Specify root directory of server to connect for the monitor |
|
||||
| `--server-config` | `string` | | Specify buildx server config file for the monitor (used only when launching new server) |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
53
docs/reference/buildx_debug_build.md
Normal file
53
docs/reference/buildx_debug_build.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# docker buildx debug build
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Start a build
|
||||
|
||||
### Aliases
|
||||
|
||||
`docker buildx debug build`, `docker buildx debug b`
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:-------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------|:----------|:----------------------------------------------------------------------------------------------------|
|
||||
| [`--add-host`](https://docs.docker.com/engine/reference/commandline/build/#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`) |
|
||||
| `--annotation` | `stringArray` | | Add annotation to the image |
|
||||
| `--attest` | `stringArray` | | Attestation parameters (format: `type=sbom,generator=image`) |
|
||||
| `--build-arg` | `stringArray` | | Set build-time variables |
|
||||
| `--build-context` | `stringArray` | | Additional build contexts (e.g., name=path) |
|
||||
| `--builder` | `string` | | Override the configured builder instance |
|
||||
| `--cache-from` | `stringArray` | | External cache sources (e.g., `user/app:cache`, `type=local,src=path/to/dir`) |
|
||||
| `--cache-to` | `stringArray` | | Cache export destinations (e.g., `user/app:cache`, `type=local,dest=path/to/dir`) |
|
||||
| [`--cgroup-parent`](https://docs.docker.com/engine/reference/commandline/build/#cgroup-parent) | `string` | | Set the parent cgroup for the `RUN` instructions during build |
|
||||
| `--detach` | | | Detach buildx server (supported only on linux) |
|
||||
| [`-f`](https://docs.docker.com/engine/reference/commandline/build/#file), [`--file`](https://docs.docker.com/engine/reference/commandline/build/#file) | `string` | | Name of the Dockerfile (default: `PATH/Dockerfile`) |
|
||||
| `--iidfile` | `string` | | Write the image ID to the file |
|
||||
| `--label` | `stringArray` | | Set metadata for an image |
|
||||
| `--load` | | | Shorthand for `--output=type=docker` |
|
||||
| `--metadata-file` | `string` | | Write build result metadata to the file |
|
||||
| `--network` | `string` | `default` | Set the networking mode for the `RUN` instructions during build |
|
||||
| `--no-cache` | | | Do not use cache when building the image |
|
||||
| `--no-cache-filter` | `stringArray` | | Do not cache specified stages |
|
||||
| `-o`, `--output` | `stringArray` | | Output destination (format: `type=local,dest=path`) |
|
||||
| `--platform` | `stringArray` | | Set target platform for build |
|
||||
| `--print` | `string` | | Print result of information request (e.g., outline, targets) |
|
||||
| `--progress` | `string` | `auto` | Set type of progress output (`auto`, `plain`, `tty`). Use plain to show container output |
|
||||
| `--provenance` | `string` | | Shorthand for `--attest=type=provenance` |
|
||||
| `--pull` | | | Always attempt to pull all referenced images |
|
||||
| `--push` | | | Shorthand for `--output=type=registry` |
|
||||
| `-q`, `--quiet` | | | Suppress the build output and print image ID on success |
|
||||
| `--root` | `string` | | Specify root directory of server to connect |
|
||||
| `--sbom` | `string` | | Shorthand for `--attest=type=sbom` |
|
||||
| `--secret` | `stringArray` | | Secret to expose to the build (format: `id=mysecret[,src=/local/secret]`) |
|
||||
| `--server-config` | `string` | | Specify buildx server config file (used only when launching new server) |
|
||||
| `--shm-size` | `bytes` | `0` | Size of `/dev/shm` |
|
||||
| `--ssh` | `stringArray` | | SSH agent socket or keys to expose to the build (format: `default\|<id>[=<socket>\|<key>[,<key>]]`) |
|
||||
| [`-t`](https://docs.docker.com/engine/reference/commandline/build/#tag), [`--tag`](https://docs.docker.com/engine/reference/commandline/build/#tag) | `stringArray` | | Name and optionally a tag (format: `name:tag`) |
|
||||
| [`--target`](https://docs.docker.com/engine/reference/commandline/build/#target) | `string` | | Set the target build stage to build |
|
||||
| `--ulimit` | `ulimit` | | Ulimit options |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
@@ -11,6 +11,7 @@ Create a new image based on source images
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:---------------------------------|:--------------|:--------|:-----------------------------------------------------------------------------------------|
|
||||
| `--annotation` | `stringArray` | | Add annotation to the image |
|
||||
| [`--append`](#append) | | | Append to existing manifest |
|
||||
| [`--builder`](#builder) | `string` | | Override the configured builder instance |
|
||||
| [`--dry-run`](#dry-run) | | | Show final image instead of pushing |
|
||||
|
@@ -1,11 +0,0 @@
|
||||
# buildx install
|
||||
|
||||
```
|
||||
docker buildx install
|
||||
```
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Install buildx as a 'docker builder' alias
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
@@ -1,11 +0,0 @@
|
||||
# buildx uninstall
|
||||
|
||||
```
|
||||
docker buildx uninstall
|
||||
```
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Uninstall the 'docker builder' alias
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
@@ -17,11 +17,13 @@ import (
|
||||
"github.com/docker/buildx/util/confutil"
|
||||
"github.com/docker/buildx/util/imagetools"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/docker/cli/opts"
|
||||
dockertypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
dockerclient "github.com/docker/docker/client"
|
||||
"github.com/docker/docker/errdefs"
|
||||
dockerarchive "github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
@@ -31,7 +33,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
volumeStateSuffix = "_state"
|
||||
volumeStateSuffix = "_state"
|
||||
buildkitdConfigFile = "buildkitd.toml"
|
||||
)
|
||||
|
||||
type Driver struct {
|
||||
@@ -39,6 +42,13 @@ type Driver struct {
|
||||
factory driver.Factory
|
||||
netMode string
|
||||
image string
|
||||
memory opts.MemBytes
|
||||
memorySwap opts.MemSwapBytes
|
||||
cpuQuota int64
|
||||
cpuPeriod int64
|
||||
cpuShares int64
|
||||
cpusetCpus string
|
||||
cpusetMems string
|
||||
cgroupParent string
|
||||
env []string
|
||||
}
|
||||
@@ -64,10 +74,7 @@ func (d *Driver) Bootstrap(ctx context.Context, l progress.Logger) error {
|
||||
if err := d.start(ctx, sub); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.wait(ctx, sub); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return d.wait(ctx, sub)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -105,12 +112,10 @@ func (d *Driver) create(ctx context.Context, l progress.SubLogger) error {
|
||||
Image: imageName,
|
||||
Env: d.env,
|
||||
}
|
||||
if d.InitConfig.BuildkitFlags != nil {
|
||||
cfg.Cmd = d.InitConfig.BuildkitFlags
|
||||
}
|
||||
cfg.Cmd = getBuildkitFlags(d.InitConfig)
|
||||
|
||||
useInit := true // let it cleanup exited processes created by BuildKit's container API
|
||||
if err := l.Wrap("creating container "+d.Name, func() error {
|
||||
return l.Wrap("creating container "+d.Name, func() error {
|
||||
hc := &container.HostConfig{
|
||||
Privileged: true,
|
||||
Mounts: []mount.Mount{
|
||||
@@ -125,6 +130,27 @@ func (d *Driver) create(ctx context.Context, l progress.SubLogger) error {
|
||||
if d.netMode != "" {
|
||||
hc.NetworkMode = container.NetworkMode(d.netMode)
|
||||
}
|
||||
if d.memory != 0 {
|
||||
hc.Resources.Memory = int64(d.memory)
|
||||
}
|
||||
if d.memorySwap != 0 {
|
||||
hc.Resources.MemorySwap = int64(d.memorySwap)
|
||||
}
|
||||
if d.cpuQuota != 0 {
|
||||
hc.Resources.CPUQuota = d.cpuQuota
|
||||
}
|
||||
if d.cpuPeriod != 0 {
|
||||
hc.Resources.CPUPeriod = d.cpuPeriod
|
||||
}
|
||||
if d.cpuShares != 0 {
|
||||
hc.Resources.CPUShares = d.cpuShares
|
||||
}
|
||||
if d.cpusetCpus != "" {
|
||||
hc.Resources.CpusetCpus = d.cpusetCpus
|
||||
}
|
||||
if d.cpusetMems != "" {
|
||||
hc.Resources.CpusetMems = d.cpusetMems
|
||||
}
|
||||
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
|
||||
@@ -148,23 +174,19 @@ func (d *Driver) create(ctx context.Context, l progress.SubLogger) error {
|
||||
|
||||
}
|
||||
_, err := d.DockerAPI.ContainerCreate(ctx, cfg, hc, &network.NetworkingConfig{}, nil, d.Name)
|
||||
if err != nil {
|
||||
if err != nil && !errdefs.IsConflict(err) {
|
||||
return err
|
||||
}
|
||||
if err := d.copyToContainer(ctx, d.InitConfig.Files); err != nil {
|
||||
return err
|
||||
if err == nil {
|
||||
if err := d.copyToContainer(ctx, d.InitConfig.Files); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.start(ctx, l); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := d.start(ctx, l); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.wait(ctx, l); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return d.wait(ctx, l)
|
||||
})
|
||||
}
|
||||
|
||||
func (d *Driver) wait(ctx context.Context, l progress.SubLogger) error {
|
||||
@@ -227,7 +249,9 @@ func (d *Driver) copyToContainer(ctx context.Context, files map[string][]byte) e
|
||||
return err
|
||||
}
|
||||
defer srcArchive.Close()
|
||||
return d.DockerAPI.CopyToContainer(ctx, d.Name, "/", srcArchive, dockertypes.CopyToContainerOptions{})
|
||||
|
||||
baseDir := path.Dir(confutil.DefaultBuildKitConfigDir)
|
||||
return d.DockerAPI.CopyToContainer(ctx, d.Name, baseDir, srcArchive, dockertypes.CopyToContainerOptions{})
|
||||
}
|
||||
|
||||
func (d *Driver) exec(ctx context.Context, cmd []string) (string, net.Conn, error) {
|
||||
@@ -396,6 +420,10 @@ func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Driver) HostGatewayIP(ctx context.Context) (net.IP, error) {
|
||||
return nil, errors.New("host-gateway is not supported by the docker-container driver")
|
||||
}
|
||||
|
||||
func demuxConn(c net.Conn) net.Conn {
|
||||
pr, pw := io.Pipe()
|
||||
// TODO: rewrite parser with Reader() to avoid goroutine switch
|
||||
@@ -439,15 +467,34 @@ func writeConfigFiles(m map[string][]byte) (_ string, err error) {
|
||||
os.RemoveAll(tmpDir)
|
||||
}
|
||||
}()
|
||||
configDir := filepath.Base(confutil.DefaultBuildKitConfigDir)
|
||||
for f, dt := range m {
|
||||
f = path.Join(confutil.DefaultBuildKitConfigDir, f)
|
||||
p := filepath.Join(tmpDir, f)
|
||||
if err := os.MkdirAll(filepath.Dir(p), 0700); err != nil {
|
||||
p := filepath.Join(tmpDir, configDir, f)
|
||||
if err := os.MkdirAll(filepath.Dir(p), 0755); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := os.WriteFile(p, dt, 0600); err != nil {
|
||||
if err := os.WriteFile(p, dt, 0644); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return tmpDir, nil
|
||||
}
|
||||
|
||||
func getBuildkitFlags(initConfig driver.InitConfig) []string {
|
||||
flags := initConfig.BuildkitFlags
|
||||
if _, ok := initConfig.Files[buildkitdConfigFile]; ok {
|
||||
// There's no way for us to determine the appropriate default configuration
|
||||
// path and the default path can vary depending on if the image is normal
|
||||
// or rootless.
|
||||
//
|
||||
// In order to ensure that --config works, copy to a specific path and
|
||||
// specify the location.
|
||||
//
|
||||
// This should be appended before the user-specified arguments
|
||||
// so that this option could be overwritten by the user.
|
||||
newFlags := make([]string, 0, len(flags)+2)
|
||||
newFlags = append(newFlags, "--config", path.Join("/etc/buildkit", buildkitdConfigFile))
|
||||
flags = append(newFlags, flags...)
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package docker
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/buildx/driver"
|
||||
@@ -28,7 +29,7 @@ func (*factory) Usage() string {
|
||||
return "docker-container"
|
||||
}
|
||||
|
||||
func (*factory) Priority(ctx context.Context, endpoint string, api dockerclient.APIClient) int {
|
||||
func (*factory) Priority(ctx context.Context, endpoint string, api dockerclient.APIClient, dialMeta map[string][]string) int {
|
||||
if api == nil {
|
||||
return priorityUnsupported
|
||||
}
|
||||
@@ -49,6 +50,36 @@ func (f *factory) New(ctx context.Context, cfg driver.InitConfig) (driver.Driver
|
||||
}
|
||||
case k == "image":
|
||||
d.image = v
|
||||
case k == "memory":
|
||||
if err := d.memory.Set(v); err == nil {
|
||||
return nil, err
|
||||
}
|
||||
case k == "memory-swap":
|
||||
if err := d.memorySwap.Set(v); err == nil {
|
||||
return nil, err
|
||||
}
|
||||
case k == "cpu-period":
|
||||
vv, err := strconv.ParseInt(v, 10, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.cpuPeriod = vv
|
||||
case k == "cpu-quota":
|
||||
vv, err := strconv.ParseInt(v, 10, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.cpuQuota = vv
|
||||
case k == "cpu-shares":
|
||||
vv, err := strconv.ParseInt(v, 10, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.cpuShares = vv
|
||||
case k == "cpuset-cpus":
|
||||
d.cpusetCpus = v
|
||||
case k == "cpuset-mems":
|
||||
d.cpusetMems = v
|
||||
case k == "cgroup-parent":
|
||||
d.cgroupParent = v
|
||||
case strings.HasPrefix(k, "env."):
|
||||
|
@@ -4,16 +4,21 @@ import (
|
||||
"context"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/buildx/driver"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/util/tracing/detect"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Driver struct {
|
||||
factory driver.Factory
|
||||
driver.InitConfig
|
||||
|
||||
features features
|
||||
hostGateway hostGateway
|
||||
}
|
||||
|
||||
func (d *Driver) Bootstrap(ctx context.Context, l progress.Logger) error {
|
||||
@@ -51,31 +56,85 @@ func (d *Driver) Rm(ctx context.Context, force, rmVolume, rmDaemon bool) error {
|
||||
}
|
||||
|
||||
func (d *Driver) Client(ctx context.Context) (*client.Client, error) {
|
||||
return client.New(ctx, "", client.WithContextDialer(func(context.Context, string) (net.Conn, error) {
|
||||
return d.DockerAPI.DialHijack(ctx, "/grpc", "h2c", nil)
|
||||
}), client.WithSessionDialer(func(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error) {
|
||||
return d.DockerAPI.DialHijack(ctx, "/session", proto, meta)
|
||||
}))
|
||||
opts := []client.ClientOpt{
|
||||
client.WithContextDialer(func(context.Context, string) (net.Conn, error) {
|
||||
return d.DockerAPI.DialHijack(ctx, "/grpc", "h2c", d.DialMeta)
|
||||
}), client.WithSessionDialer(func(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error) {
|
||||
return d.DockerAPI.DialHijack(ctx, "/session", proto, meta)
|
||||
}),
|
||||
}
|
||||
|
||||
exp, err := detect.Exporter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if td, ok := exp.(client.TracerDelegate); ok {
|
||||
opts = append(opts, client.WithTracerDelegate(td))
|
||||
}
|
||||
return client.New(ctx, "", opts...)
|
||||
}
|
||||
|
||||
type features struct {
|
||||
once sync.Once
|
||||
list map[driver.Feature]bool
|
||||
}
|
||||
|
||||
func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
|
||||
var useContainerdSnapshotter bool
|
||||
c, err := d.Client(ctx)
|
||||
if err == nil {
|
||||
workers, _ := c.ListWorkers(ctx)
|
||||
d.features.once.Do(func() {
|
||||
var useContainerdSnapshotter bool
|
||||
if c, err := d.Client(ctx); err == nil {
|
||||
workers, _ := c.ListWorkers(ctx)
|
||||
for _, w := range workers {
|
||||
if _, ok := w.Labels["org.mobyproject.buildkit.worker.snapshotter"]; ok {
|
||||
useContainerdSnapshotter = true
|
||||
}
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
d.features.list = map[driver.Feature]bool{
|
||||
driver.OCIExporter: useContainerdSnapshotter,
|
||||
driver.DockerExporter: useContainerdSnapshotter,
|
||||
driver.CacheExport: useContainerdSnapshotter,
|
||||
driver.MultiPlatform: useContainerdSnapshotter,
|
||||
}
|
||||
})
|
||||
return d.features.list
|
||||
}
|
||||
|
||||
type hostGateway struct {
|
||||
once sync.Once
|
||||
ip net.IP
|
||||
err error
|
||||
}
|
||||
|
||||
func (d *Driver) HostGatewayIP(ctx context.Context) (net.IP, error) {
|
||||
d.hostGateway.once.Do(func() {
|
||||
c, err := d.Client(ctx)
|
||||
if err != nil {
|
||||
d.hostGateway.err = err
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
workers, err := c.ListWorkers(ctx)
|
||||
if err != nil {
|
||||
d.hostGateway.err = errors.Wrap(err, "listing workers")
|
||||
return
|
||||
}
|
||||
for _, w := range workers {
|
||||
if _, ok := w.Labels["org.mobyproject.buildkit.worker.snapshotter"]; ok {
|
||||
useContainerdSnapshotter = true
|
||||
// should match github.com/docker/docker/builder/builder-next/worker/label.HostGatewayIP const
|
||||
if v, ok := w.Labels["org.mobyproject.buildkit.worker.moby.host-gateway-ip"]; ok && v != "" {
|
||||
ip := net.ParseIP(v)
|
||||
if ip == nil {
|
||||
d.hostGateway.err = errors.Errorf("failed to parse host-gateway IP: %s", v)
|
||||
return
|
||||
}
|
||||
d.hostGateway.ip = ip
|
||||
return
|
||||
}
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
return map[driver.Feature]bool{
|
||||
driver.OCIExporter: useContainerdSnapshotter,
|
||||
driver.DockerExporter: useContainerdSnapshotter,
|
||||
driver.CacheExport: useContainerdSnapshotter,
|
||||
driver.MultiPlatform: useContainerdSnapshotter,
|
||||
}
|
||||
d.hostGateway.err = errors.New("host-gateway IP not found")
|
||||
})
|
||||
return d.hostGateway.ip, d.hostGateway.err
|
||||
}
|
||||
|
||||
func (d *Driver) Factory() driver.Factory {
|
||||
|
@@ -26,12 +26,12 @@ func (*factory) Usage() string {
|
||||
return "docker"
|
||||
}
|
||||
|
||||
func (*factory) Priority(ctx context.Context, endpoint string, api dockerclient.APIClient) int {
|
||||
func (*factory) Priority(ctx context.Context, endpoint string, api dockerclient.APIClient, dialMeta map[string][]string) int {
|
||||
if api == nil {
|
||||
return priorityUnsupported
|
||||
}
|
||||
|
||||
c, err := api.DialHijack(ctx, "/grpc", "h2c", nil)
|
||||
c, err := api.DialHijack(ctx, "/grpc", "h2c", dialMeta)
|
||||
if err != nil {
|
||||
return priorityUnsupported
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package driver
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/docker/buildx/store"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
@@ -60,6 +61,7 @@ type Driver interface {
|
||||
Rm(ctx context.Context, force, rmVolume, rmDaemon bool) error
|
||||
Client(ctx context.Context) (*client.Client, error)
|
||||
Features(ctx context.Context) map[Feature]bool
|
||||
HostGatewayIP(ctx context.Context) (net.IP, error)
|
||||
IsMobyDriver() bool
|
||||
Config() InitConfig
|
||||
}
|
||||
|
@@ -6,4 +6,4 @@ const OCIExporter Feature = "OCI exporter"
|
||||
const DockerExporter Feature = "Docker exporter"
|
||||
|
||||
const CacheExport Feature = "Cache export"
|
||||
const MultiPlatform Feature = "Multiple platforms"
|
||||
const MultiPlatform Feature = "Multi-platform build"
|
||||
|
@@ -23,6 +23,7 @@ type EndpointMeta struct {
|
||||
AuthProvider *clientcmdapi.AuthProviderConfig `json:",omitempty"`
|
||||
Exec *clientcmdapi.ExecConfig `json:",omitempty"`
|
||||
UsernamePassword *UsernamePassword `json:"usernamePassword,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
}
|
||||
|
||||
// UsernamePassword contains username/password auth info
|
||||
@@ -77,6 +78,9 @@ func (c *Endpoint) KubernetesConfig() clientcmd.ClientConfig {
|
||||
authInfo.Username = c.UsernamePassword.Username
|
||||
authInfo.Password = c.UsernamePassword.Password
|
||||
}
|
||||
if c.Token != "" {
|
||||
authInfo.Token = c.Token
|
||||
}
|
||||
authInfo.AuthProvider = c.AuthProvider
|
||||
authInfo.Exec = c.Exec
|
||||
cfg.Clusters["cluster"] = cluster
|
||||
|
@@ -68,6 +68,7 @@ func FromKubeConfig(kubeconfig, kubeContext, namespaceOverride string) (Endpoint
|
||||
AuthProvider: clientcfg.AuthProvider,
|
||||
Exec: clientcfg.ExecProvider,
|
||||
UsernamePassword: usernamePassword,
|
||||
Token: clientcfg.BearerToken,
|
||||
},
|
||||
TLSData: tlsData,
|
||||
}, nil
|
||||
|
@@ -87,10 +87,7 @@ func (d *Driver) Bootstrap(ctx context.Context, l progress.Logger) error {
|
||||
return sub.Wrap(
|
||||
fmt.Sprintf("waiting for %d pods to be ready", d.minReplicas),
|
||||
func() error {
|
||||
if err := d.wait(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return d.wait(ctx)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -228,7 +225,7 @@ func (d *Driver) Factory() driver.Factory {
|
||||
return d.factory
|
||||
}
|
||||
|
||||
func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
|
||||
func (d *Driver) Features(_ context.Context) map[driver.Feature]bool {
|
||||
return map[driver.Feature]bool{
|
||||
driver.OCIExporter: true,
|
||||
driver.DockerExporter: d.DockerAPI != nil,
|
||||
@@ -236,3 +233,7 @@ func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
|
||||
driver.MultiPlatform: true, // Untested (needs multiple Driver instances)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Driver) HostGatewayIP(_ context.Context) (net.IP, error) {
|
||||
return nil, errors.New("host-gateway is not supported by the kubernetes driver")
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@ func (*factory) Usage() string {
|
||||
return DriverName
|
||||
}
|
||||
|
||||
func (*factory) Priority(ctx context.Context, endpoint string, api dockerclient.APIClient) int {
|
||||
func (*factory) Priority(ctx context.Context, endpoint string, api dockerclient.APIClient, dialMeta map[string][]string) int {
|
||||
if api == nil {
|
||||
return priorityUnsupported
|
||||
}
|
||||
@@ -148,15 +148,20 @@ func (f *factory) processDriverOpts(deploymentName string, namespace string, cfg
|
||||
case "serviceaccount":
|
||||
deploymentOpt.ServiceAccountName = v
|
||||
case "nodeselector":
|
||||
kvs := strings.Split(strings.Trim(v, `"`), ",")
|
||||
s := map[string]string{}
|
||||
for i := range kvs {
|
||||
kv := strings.Split(kvs[i], "=")
|
||||
if len(kv) == 2 {
|
||||
s[kv[0]] = kv[1]
|
||||
}
|
||||
deploymentOpt.NodeSelector, err = splitMultiValues(v, ",", "=")
|
||||
if err != nil {
|
||||
return nil, "", "", errors.Wrap(err, "cannot parse node selector")
|
||||
}
|
||||
case "annotations":
|
||||
deploymentOpt.CustomAnnotations, err = splitMultiValues(v, ",", "=")
|
||||
if err != nil {
|
||||
return nil, "", "", errors.Wrap(err, "cannot parse annotations")
|
||||
}
|
||||
case "labels":
|
||||
deploymentOpt.CustomLabels, err = splitMultiValues(v, ",", "=")
|
||||
if err != nil {
|
||||
return nil, "", "", errors.Wrap(err, "cannot parse labels")
|
||||
}
|
||||
deploymentOpt.NodeSelector = s
|
||||
case "tolerations":
|
||||
ts := strings.Split(v, ";")
|
||||
deploymentOpt.Tolerations = []corev1.Toleration{}
|
||||
@@ -217,6 +222,19 @@ func (f *factory) processDriverOpts(deploymentName string, namespace string, cfg
|
||||
return deploymentOpt, loadbalance, namespace, nil
|
||||
}
|
||||
|
||||
func splitMultiValues(in string, itemsep string, kvsep string) (map[string]string, error) {
|
||||
kvs := strings.Split(strings.Trim(in, `"`), itemsep)
|
||||
s := map[string]string{}
|
||||
for i := range kvs {
|
||||
kv := strings.Split(kvs[i], kvsep)
|
||||
if len(kv) != 2 {
|
||||
return nil, errors.Errorf("invalid key-value pair: %s", kvs[i])
|
||||
}
|
||||
s[kv[0]] = kv[1]
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (f *factory) AllowsInstances() bool {
|
||||
return true
|
||||
}
|
||||
|
@@ -47,13 +47,13 @@ func TestFactory_processDriverOpts(t *testing.T) {
|
||||
"rootless": "true",
|
||||
"nodeselector": "selector1=value1,selector2=value2",
|
||||
"tolerations": "key=tolerationKey1,value=tolerationValue1,operator=Equal,effect=NoSchedule,tolerationSeconds=60;key=tolerationKey2,operator=Exists",
|
||||
"annotations": "example.com/expires-after=annotation1,example.com/other=annotation2",
|
||||
"labels": "example.com/owner=label1,example.com/other=label2",
|
||||
"loadbalance": "random",
|
||||
"qemu.install": "true",
|
||||
"qemu.image": "qemu:latest",
|
||||
}
|
||||
ns := "test"
|
||||
|
||||
r, loadbalance, ns, err := f.processDriverOpts(cfg.Name, ns, cfg)
|
||||
r, loadbalance, ns, err := f.processDriverOpts(cfg.Name, "test", cfg)
|
||||
|
||||
nodeSelectors := map[string]string{
|
||||
"selector1": "value1",
|
||||
@@ -75,6 +75,16 @@ func TestFactory_processDriverOpts(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
customAnnotations := map[string]string{
|
||||
"example.com/expires-after": "annotation1",
|
||||
"example.com/other": "annotation2",
|
||||
}
|
||||
|
||||
customLabels := map[string]string{
|
||||
"example.com/owner": "label1",
|
||||
"example.com/other": "label2",
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "test-ns", ns)
|
||||
@@ -86,6 +96,8 @@ func TestFactory_processDriverOpts(t *testing.T) {
|
||||
require.Equal(t, "64Mi", r.LimitsMemory)
|
||||
require.True(t, r.Rootless)
|
||||
require.Equal(t, nodeSelectors, r.NodeSelector)
|
||||
require.Equal(t, customAnnotations, r.CustomAnnotations)
|
||||
require.Equal(t, customLabels, r.CustomLabels)
|
||||
require.Equal(t, tolerations, r.Tolerations)
|
||||
require.Equal(t, LoadbalanceRandom, loadbalance)
|
||||
require.True(t, r.Qemu.Install)
|
||||
@@ -110,6 +122,8 @@ func TestFactory_processDriverOpts(t *testing.T) {
|
||||
require.Equal(t, "", r.LimitsMemory)
|
||||
require.False(t, r.Rootless)
|
||||
require.Empty(t, r.NodeSelector)
|
||||
require.Empty(t, r.CustomAnnotations)
|
||||
require.Empty(t, r.CustomLabels)
|
||||
require.Empty(t, r.Tolerations)
|
||||
require.Equal(t, LoadbalanceSticky, loadbalance)
|
||||
require.False(t, r.Qemu.Install)
|
||||
@@ -137,6 +151,8 @@ func TestFactory_processDriverOpts(t *testing.T) {
|
||||
require.Equal(t, "", r.LimitsMemory)
|
||||
require.True(t, r.Rootless)
|
||||
require.Empty(t, r.NodeSelector)
|
||||
require.Empty(t, r.CustomAnnotations)
|
||||
require.Empty(t, r.CustomLabels)
|
||||
require.Empty(t, r.Tolerations)
|
||||
require.Equal(t, LoadbalanceSticky, loadbalance)
|
||||
require.False(t, r.Qemu.Install)
|
||||
@@ -149,9 +165,7 @@ func TestFactory_processDriverOpts(t *testing.T) {
|
||||
cfg.DriverOpts = map[string]string{
|
||||
"replicas": "invalid",
|
||||
}
|
||||
|
||||
_, _, _, err := f.processDriverOpts(cfg.Name, "test", cfg)
|
||||
|
||||
require.Error(t, err)
|
||||
},
|
||||
)
|
||||
@@ -161,9 +175,7 @@ func TestFactory_processDriverOpts(t *testing.T) {
|
||||
cfg.DriverOpts = map[string]string{
|
||||
"rootless": "invalid",
|
||||
}
|
||||
|
||||
_, _, _, err := f.processDriverOpts(cfg.Name, "test", cfg)
|
||||
|
||||
require.Error(t, err)
|
||||
},
|
||||
)
|
||||
@@ -173,9 +185,7 @@ func TestFactory_processDriverOpts(t *testing.T) {
|
||||
cfg.DriverOpts = map[string]string{
|
||||
"tolerations": "key=foo,value=bar,invalid=foo2",
|
||||
}
|
||||
|
||||
_, _, _, err := f.processDriverOpts(cfg.Name, "test", cfg)
|
||||
|
||||
require.Error(t, err)
|
||||
},
|
||||
)
|
||||
@@ -185,9 +195,27 @@ func TestFactory_processDriverOpts(t *testing.T) {
|
||||
cfg.DriverOpts = map[string]string{
|
||||
"tolerations": "key=foo,value=bar,tolerationSeconds=invalid",
|
||||
}
|
||||
|
||||
_, _, _, err := f.processDriverOpts(cfg.Name, "test", cfg)
|
||||
require.Error(t, err)
|
||||
},
|
||||
)
|
||||
|
||||
t.Run(
|
||||
"InvalidCustomAnnotation", func(t *testing.T) {
|
||||
cfg.DriverOpts = map[string]string{
|
||||
"annotations": "key,value",
|
||||
}
|
||||
_, _, _, err := f.processDriverOpts(cfg.Name, "test", cfg)
|
||||
require.Error(t, err)
|
||||
},
|
||||
)
|
||||
|
||||
t.Run(
|
||||
"InvalidCustomLabel", func(t *testing.T) {
|
||||
cfg.DriverOpts = map[string]string{
|
||||
"labels": "key=value=foo",
|
||||
}
|
||||
_, _, _, err := f.processDriverOpts(cfg.Name, "test", cfg)
|
||||
require.Error(t, err)
|
||||
},
|
||||
)
|
||||
@@ -197,9 +225,7 @@ func TestFactory_processDriverOpts(t *testing.T) {
|
||||
cfg.DriverOpts = map[string]string{
|
||||
"loadbalance": "invalid",
|
||||
}
|
||||
|
||||
_, _, _, err := f.processDriverOpts(cfg.Name, "test", cfg)
|
||||
|
||||
require.Error(t, err)
|
||||
},
|
||||
)
|
||||
@@ -209,9 +235,7 @@ func TestFactory_processDriverOpts(t *testing.T) {
|
||||
cfg.DriverOpts = map[string]string{
|
||||
"qemu.install": "invalid",
|
||||
}
|
||||
|
||||
_, _, _, err := f.processDriverOpts(cfg.Name, "test", cfg)
|
||||
|
||||
require.Error(t, err)
|
||||
},
|
||||
)
|
||||
@@ -221,9 +245,7 @@ func TestFactory_processDriverOpts(t *testing.T) {
|
||||
cfg.DriverOpts = map[string]string{
|
||||
"invalid": "foo",
|
||||
}
|
||||
|
||||
_, _, _, err := f.processDriverOpts(cfg.Name, "test", cfg)
|
||||
|
||||
require.Error(t, err)
|
||||
},
|
||||
)
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/docker/buildx/util/platformutil"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
@@ -31,24 +32,32 @@ type DeploymentOpt struct {
|
||||
// files mounted at /etc/buildkitd
|
||||
ConfigFiles map[string][]byte
|
||||
|
||||
Rootless bool
|
||||
NodeSelector map[string]string
|
||||
Tolerations []corev1.Toleration
|
||||
RequestsCPU string
|
||||
RequestsMemory string
|
||||
LimitsCPU string
|
||||
LimitsMemory string
|
||||
Platforms []v1.Platform
|
||||
Rootless bool
|
||||
NodeSelector map[string]string
|
||||
CustomAnnotations map[string]string
|
||||
CustomLabels map[string]string
|
||||
Tolerations []corev1.Toleration
|
||||
RequestsCPU string
|
||||
RequestsMemory string
|
||||
LimitsCPU string
|
||||
LimitsMemory string
|
||||
Platforms []v1.Platform
|
||||
}
|
||||
|
||||
const (
|
||||
containerName = "buildkitd"
|
||||
AnnotationPlatform = "buildx.docker.com/platform"
|
||||
LabelApp = "app"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrReservedAnnotationPlatform = errors.Errorf("the annotation \"%s\" is reserved and cannot be customized", AnnotationPlatform)
|
||||
ErrReservedLabelApp = errors.Errorf("the label \"%s\" is reserved and cannot be customized", LabelApp)
|
||||
)
|
||||
|
||||
func NewDeployment(opt *DeploymentOpt) (d *appsv1.Deployment, c []*corev1.ConfigMap, err error) {
|
||||
labels := map[string]string{
|
||||
"app": opt.Name,
|
||||
LabelApp: opt.Name,
|
||||
}
|
||||
annotations := map[string]string{}
|
||||
replicas := int32(opt.Replicas)
|
||||
@@ -59,6 +68,20 @@ func NewDeployment(opt *DeploymentOpt) (d *appsv1.Deployment, c []*corev1.Config
|
||||
annotations[AnnotationPlatform] = strings.Join(platformutil.Format(opt.Platforms), ",")
|
||||
}
|
||||
|
||||
for k, v := range opt.CustomAnnotations {
|
||||
if k == AnnotationPlatform {
|
||||
return nil, nil, ErrReservedAnnotationPlatform
|
||||
}
|
||||
annotations[k] = v
|
||||
}
|
||||
|
||||
for k, v := range opt.CustomLabels {
|
||||
if k == LabelApp {
|
||||
return nil, nil, ErrReservedLabelApp
|
||||
}
|
||||
labels[k] = v
|
||||
}
|
||||
|
||||
d = &appsv1.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: appsv1.SchemeGroupVersion.String(),
|
||||
|
@@ -7,18 +7,17 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
dockerclient "github.com/docker/docker/client"
|
||||
"github.com/moby/buildkit/client"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type Factory interface {
|
||||
Name() string
|
||||
Usage() string
|
||||
Priority(ctx context.Context, endpoint string, api dockerclient.APIClient) int
|
||||
Priority(ctx context.Context, endpoint string, api dockerclient.APIClient, dialMeta map[string][]string) int
|
||||
New(ctx context.Context, cfg InitConfig) (Driver, error)
|
||||
AllowsInstances() bool
|
||||
}
|
||||
@@ -58,8 +57,8 @@ type InitConfig struct {
|
||||
DriverOpts map[string]string
|
||||
Auth Auth
|
||||
Platforms []specs.Platform
|
||||
// ContextPathHash can be used for determining pods in the driver instance
|
||||
ContextPathHash string
|
||||
ContextPathHash string // can be used for determining pods in the driver instance
|
||||
DialMeta map[string][]string
|
||||
}
|
||||
|
||||
var drivers map[string]Factory
|
||||
@@ -71,7 +70,7 @@ func Register(f Factory) {
|
||||
drivers[f.Name()] = f
|
||||
}
|
||||
|
||||
func GetDefaultFactory(ctx context.Context, ep string, c dockerclient.APIClient, instanceRequired bool) (Factory, error) {
|
||||
func GetDefaultFactory(ctx context.Context, ep string, c dockerclient.APIClient, instanceRequired bool, dialMeta map[string][]string) (Factory, error) {
|
||||
if len(drivers) == 0 {
|
||||
return nil, errors.Errorf("no drivers available")
|
||||
}
|
||||
@@ -84,7 +83,7 @@ func GetDefaultFactory(ctx context.Context, ep string, c dockerclient.APIClient,
|
||||
if instanceRequired && !f.AllowsInstances() {
|
||||
continue
|
||||
}
|
||||
dd = append(dd, p{f: f, priority: f.Priority(ctx, ep, c)})
|
||||
dd = append(dd, p{f: f, priority: f.Priority(ctx, ep, c, dialMeta)})
|
||||
}
|
||||
sort.Slice(dd, func(i, j int) bool {
|
||||
return dd[i].priority < dd[j].priority
|
||||
@@ -104,7 +103,7 @@ func GetFactory(name string, instanceRequired bool) (Factory, error) {
|
||||
return nil, errors.Errorf("failed to find driver %q", name)
|
||||
}
|
||||
|
||||
func GetDriver(ctx context.Context, name string, f Factory, endpointAddr string, api dockerclient.APIClient, auth Auth, kcc KubeClientConfig, flags []string, files map[string][]byte, do map[string]string, platforms []specs.Platform, contextPathHash string) (*DriverHandle, error) {
|
||||
func GetDriver(ctx context.Context, name string, f Factory, endpointAddr string, api dockerclient.APIClient, auth Auth, kcc KubeClientConfig, flags []string, files map[string][]byte, do map[string]string, platforms []specs.Platform, contextPathHash string, dialMeta map[string][]string) (*DriverHandle, error) {
|
||||
ic := InitConfig{
|
||||
EndpointAddr: endpointAddr,
|
||||
DockerAPI: api,
|
||||
@@ -115,11 +114,12 @@ func GetDriver(ctx context.Context, name string, f Factory, endpointAddr string,
|
||||
Auth: auth,
|
||||
Platforms: platforms,
|
||||
ContextPathHash: contextPathHash,
|
||||
DialMeta: dialMeta,
|
||||
Files: files,
|
||||
}
|
||||
if f == nil {
|
||||
var err error
|
||||
f, err = GetDefaultFactory(ctx, endpointAddr, api, false)
|
||||
f, err = GetDefaultFactory(ctx, endpointAddr, api, false, dialMeta)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -150,8 +150,6 @@ type DriverHandle struct {
|
||||
client *client.Client
|
||||
err error
|
||||
once sync.Once
|
||||
featuresOnce sync.Once
|
||||
features map[Feature]bool
|
||||
historyAPISupportedOnce sync.Once
|
||||
historyAPISupported bool
|
||||
}
|
||||
@@ -163,13 +161,6 @@ func (d *DriverHandle) Client(ctx context.Context) (*client.Client, error) {
|
||||
return d.client, d.err
|
||||
}
|
||||
|
||||
func (d *DriverHandle) Features(ctx context.Context) map[Feature]bool {
|
||||
d.featuresOnce.Do(func() {
|
||||
d.features = d.Driver.Features(ctx)
|
||||
})
|
||||
return d.features
|
||||
}
|
||||
|
||||
func (d *DriverHandle) HistoryAPISupported(ctx context.Context) bool {
|
||||
d.historyAPISupportedOnce.Do(func() {
|
||||
if c, err := d.Client(ctx); err == nil {
|
||||
|
@@ -2,11 +2,13 @@ package remote
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/docker/buildx/driver"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/util/tracing/detect"
|
||||
)
|
||||
|
||||
type Driver struct {
|
||||
@@ -23,25 +25,11 @@ type tlsOpts struct {
|
||||
}
|
||||
|
||||
func (d *Driver) Bootstrap(ctx context.Context, l progress.Logger) error {
|
||||
for i := 0; ; i++ {
|
||||
info, err := d.Info(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.Status != driver.Inactive {
|
||||
return nil
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
if i > 10 {
|
||||
i = 10
|
||||
}
|
||||
time.Sleep(time.Duration(i) * time.Second)
|
||||
}
|
||||
c, err := d.Client(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Wait(ctx)
|
||||
}
|
||||
|
||||
func (d *Driver) Info(ctx context.Context) (*driver.Info, error) {
|
||||
@@ -77,6 +65,15 @@ func (d *Driver) Rm(ctx context.Context, force, rmVolume, rmDaemon bool) error {
|
||||
|
||||
func (d *Driver) Client(ctx context.Context) (*client.Client, error) {
|
||||
opts := []client.ClientOpt{}
|
||||
|
||||
exp, err := detect.Exporter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if td, ok := exp.(client.TracerDelegate); ok {
|
||||
opts = append(opts, client.WithTracerDelegate(td))
|
||||
}
|
||||
|
||||
if d.tlsOpts != nil {
|
||||
opts = append(opts, []client.ClientOpt{
|
||||
client.WithServerConfig(d.tlsOpts.serverName, d.tlsOpts.caCert),
|
||||
@@ -96,6 +93,10 @@ func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Driver) HostGatewayIP(ctx context.Context) (net.IP, error) {
|
||||
return nil, errors.New("host-gateway is not supported by the remote driver")
|
||||
}
|
||||
|
||||
func (d *Driver) Factory() driver.Factory {
|
||||
return d.factory
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ func (*factory) Usage() string {
|
||||
return "remote"
|
||||
}
|
||||
|
||||
func (*factory) Priority(ctx context.Context, endpoint string, api dockerclient.APIClient) int {
|
||||
func (*factory) Priority(ctx context.Context, endpoint string, api dockerclient.APIClient, dialMeta map[string][]string) int {
|
||||
if util.IsValidEndpoint(endpoint) != nil {
|
||||
return priorityUnsupported
|
||||
}
|
||||
|
95
go.mod
95
go.mod
@@ -5,58 +5,61 @@ go 1.20
|
||||
require (
|
||||
github.com/Masterminds/semver/v3 v3.2.1
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.16
|
||||
github.com/compose-spec/compose-go v1.14.0
|
||||
github.com/compose-spec/compose-go v1.20.0
|
||||
github.com/containerd/console v1.0.3
|
||||
github.com/containerd/containerd v1.7.2
|
||||
github.com/containerd/continuity v0.4.1
|
||||
github.com/containerd/containerd v1.7.7
|
||||
github.com/containerd/continuity v0.4.2
|
||||
github.com/containerd/log v0.1.0
|
||||
github.com/containerd/typeurl/v2 v2.1.1
|
||||
github.com/docker/cli v24.0.2+incompatible
|
||||
github.com/docker/cli-docs-tool v0.5.1
|
||||
github.com/docker/distribution v2.8.2+incompatible
|
||||
github.com/docker/docker v24.0.2+incompatible
|
||||
github.com/creack/pty v1.1.18
|
||||
github.com/distribution/reference v0.5.0
|
||||
github.com/docker/cli v24.0.5+incompatible
|
||||
github.com/docker/cli-docs-tool v0.6.0
|
||||
github.com/docker/docker v24.0.5+incompatible
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/gofrs/flock v0.8.1
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/protobuf v1.5.3
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/hashicorp/go-cty-funcs v0.0.0-20200930094925-2721b1e36840
|
||||
github.com/hashicorp/hcl/v2 v2.8.2
|
||||
github.com/moby/buildkit v0.11.0-rc3.0.20230609092854-67a08623b95a
|
||||
github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992
|
||||
github.com/hashicorp/hcl/v2 v2.19.1
|
||||
github.com/moby/buildkit v0.13.0-beta1.0.20231023114302-d5c1d785b042
|
||||
github.com/moby/sys/mountinfo v0.6.2
|
||||
github.com/moby/sys/signal v0.7.0
|
||||
github.com/morikuni/aec v1.0.0
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/opencontainers/image-spec v1.1.0-rc3
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/zclconf/go-cty v1.10.0
|
||||
github.com/zclconf/go-cty v1.14.1
|
||||
go.opentelemetry.io/otel v1.14.0
|
||||
go.opentelemetry.io/otel/trace v1.14.0
|
||||
golang.org/x/sync v0.2.0
|
||||
golang.org/x/term v0.6.0
|
||||
golang.org/x/mod v0.11.0
|
||||
golang.org/x/sync v0.3.0
|
||||
golang.org/x/term v0.13.0
|
||||
google.golang.org/grpc v1.53.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/api v0.26.2
|
||||
k8s.io/apimachinery v0.26.2
|
||||
k8s.io/apiserver v0.26.2
|
||||
k8s.io/client-go v0.26.2
|
||||
k8s.io/api v0.26.7
|
||||
k8s.io/apimachinery v0.26.7
|
||||
k8s.io/apiserver v0.26.7
|
||||
k8s.io/client-go v0.26.7
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/Microsoft/hcsshim v0.11.1 // indirect
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d // indirect
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect
|
||||
github.com/apparentlymart/go-cidr v1.0.1 // indirect
|
||||
github.com/apparentlymart/go-textseg/v12 v12.0.0 // indirect
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24 // indirect
|
||||
@@ -69,22 +72,15 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 // indirect
|
||||
github.com/aws/smithy-go v1.13.5 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bugsnag/bugsnag-go v1.4.1 // indirect
|
||||
github.com/bugsnag/panicwrap v1.2.0 // indirect
|
||||
github.com/cenkalti/backoff v2.1.1+incompatible // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cloudflare/cfssl v0.0.0-20181213083726-b94e044bb51e // indirect
|
||||
github.com/containerd/ttrpc v1.2.2 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/distribution/distribution/v3 v3.0.0-20230214150026-36d8c594d7aa // indirect
|
||||
github.com/docker/distribution v2.8.2+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-metrics v0.0.1 // indirect
|
||||
github.com/docker/libtrust v0.0.0-20150526203908-9cbd2a1374f4 // indirect
|
||||
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
||||
github.com/fvbommel/sortorder v1.0.1 // indirect
|
||||
@@ -93,26 +89,20 @@ require (
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
||||
github.com/gogo/googleapis v1.4.1 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.4 // indirect
|
||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect
|
||||
github.com/imdario/mergo v0.3.15 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/in-toto/in-toto-golang v0.5.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jinzhu/gorm v1.9.2 // indirect
|
||||
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
|
||||
github.com/klauspost/compress v1.16.3 // indirect
|
||||
github.com/kr/pretty v0.2.1 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/go-shellwords v1.0.12 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
@@ -120,28 +110,26 @@ require (
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/patternmatcher v0.5.0 // indirect
|
||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||
github.com/moby/spdystream v0.2.0 // indirect
|
||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/opencontainers/runc v1.1.7 // indirect
|
||||
github.com/opencontainers/runc v1.1.9 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
|
||||
github.com/sergi/go-diff v1.2.0 // indirect
|
||||
github.com/shibumi/go-pathspec v1.3.0 // indirect
|
||||
github.com/spf13/viper v1.14.0 // indirect
|
||||
github.com/theupdateframework/notary v0.6.1 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20230407161946-9e7a6df48576 // indirect
|
||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb // indirect
|
||||
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
|
||||
github.com/tonistiigi/vt100 v0.0.0-20210615222946-8066bb97264f // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
||||
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 // 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
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0 // indirect
|
||||
@@ -154,20 +142,17 @@ require (
|
||||
go.opentelemetry.io/otel/metric v0.37.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.14.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
|
||||
golang.org/x/crypto v0.2.0 // indirect
|
||||
golang.org/x/mod v0.9.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/oauth2 v0.5.0 // indirect
|
||||
golang.org/x/sys v0.7.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.7.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/dancannon/gorethink.v3 v3.0.5 // indirect
|
||||
gopkg.in/fatih/pool.v2 v2.0.0 // indirect
|
||||
gopkg.in/gorethink/gorethink.v3 v3.0.5 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/klog/v2 v2.90.1 // indirect
|
||||
|
294
go.sum
294
go.sum
@@ -34,37 +34,35 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0=
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20221215162035-5330a85ea652 h1:+vTEFqeoeur6XSq06bs+roX3YiT49gUniJK7Zky7Xjg=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59MxjQVfjXsBpLy+dbd2/ELV5ofnUkUZBvWSC85sheA=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/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/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
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=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/Microsoft/hcsshim v0.10.0-rc.8 h1:YSZVvlIIDD1UxQpJp0h+dnpLUw+TrY0cx8obKsp3bek=
|
||||
github.com/Microsoft/hcsshim v0.11.1 h1:hJ3s7GbWlGK4YVV92sO88BQSyF4ZLVy7/awqOlPxFbA=
|
||||
github.com/Microsoft/hcsshim v0.11.1/go.mod h1:nFJmaO4Zr5Y7eADdFOpYswDDlNVbvcIJJNJLECr5JQg=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
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/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
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/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI=
|
||||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 h1:aM1rlcoLz8y5B2r4tTLMiVTrMtpfY0O8EScKJxaSaEc=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/apparentlymart/go-cidr v1.0.1 h1:NmIwLZ/KdsjIUlhf+/Np40atNXm/+lZ5txfTJ/SpF+U=
|
||||
github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=
|
||||
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
|
||||
github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
|
||||
github.com/apparentlymart/go-textseg/v12 v12.0.0 h1:bNEQyAGak9tojivJNkoqWErVCQbjdL7GzRt3F8NvfJ0=
|
||||
github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.6 h1:Y773UK7OBqhzi5VDXMi1zVGsoj+CVHs2eaC2bDsLwi0=
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.6/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
||||
@@ -90,17 +88,21 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 h1:rIFn5J3yDoeuKCE9sESXqM5POTAh
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.18.6/go.mod h1:48WJ9l3dwP0GSHWGc5sFGGlCkuA82Mc2xnw+T6Q8aDw=
|
||||
github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
|
||||
github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
|
||||
github.com/beorn7/perks v0.0.0-20150223135152-b965b613227f/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw=
|
||||
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/bugsnag/bugsnag-go v1.4.1 h1:TT3P9AX69w8mbSGE8L7IJOO2KBlPN0iQtYD0dUlrWHc=
|
||||
github.com/bugsnag/bugsnag-go v1.4.1/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
||||
github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA=
|
||||
github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
||||
github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY=
|
||||
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
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.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
|
||||
github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
@@ -112,8 +114,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/cfssl v0.0.0-20181213083726-b94e044bb51e h1:Qux+lbuMaRzkQyTdzgtz8MgzPtzmaPQy6DXmxpdxT3U=
|
||||
github.com/cloudflare/cfssl v0.0.0-20181213083726-b94e044bb51e/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
|
||||
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/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
@@ -122,16 +124,18 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
|
||||
github.com/compose-spec/compose-go v1.14.0 h1:/+tQxBEPIrfsi87Qh7/VjMzcJN3BRNER/RO71ku+u6E=
|
||||
github.com/compose-spec/compose-go v1.14.0/go.mod h1:m0o4G6MQDHjjz9rY7No9FpnNi+9sKic262rzrwuCqic=
|
||||
github.com/compose-spec/compose-go v1.20.0 h1:h4ZKOst1EF/DwZp7dWkb+wbTVE4nEyT9Lc89to84Ol4=
|
||||
github.com/compose-spec/compose-go v1.20.0/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM=
|
||||
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
|
||||
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
|
||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||
github.com/containerd/containerd v1.7.2 h1:UF2gdONnxO8I6byZXDi5sXWiWvlW3D/sci7dTQimEJo=
|
||||
github.com/containerd/containerd v1.7.2/go.mod h1:afcz74+K10M/+cjGHIVQrCt3RAQhUSCAjJ9iMYhhkuI=
|
||||
github.com/containerd/continuity v0.4.1 h1:wQnVrjIyQ8vhU2sgOiL5T07jo+ouqc2bnKsv5/EqGhU=
|
||||
github.com/containerd/continuity v0.4.1/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
||||
github.com/containerd/containerd v1.7.7 h1:QOC2K4A42RQpcrZyptP6z9EJZnlHfHJUfZrAAHe15q4=
|
||||
github.com/containerd/containerd v1.7.7/go.mod h1:3c4XZv6VeT9qgf9GMTxNTMFxGJrGpI2vz1yk4ye+YY8=
|
||||
github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
|
||||
github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
||||
github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/nydus-snapshotter v0.8.2 h1:7SOrMU2YmLzfbsr5J7liMZJlNi5WT6vtIOxLGv+iz7E=
|
||||
github.com/containerd/stargz-snapshotter v0.14.3 h1:OTUVZoPSPs8mGgmQUE1dqw3WX/3nrsmsurW7UPLWl1U=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k=
|
||||
@@ -142,21 +146,22 @@ github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3H
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/distribution/distribution/v3 v3.0.0-20230214150026-36d8c594d7aa h1:L9Ay/slwQ4ERSPaurC+TVkZrM0K98GNrEEo1En3e8as=
|
||||
github.com/distribution/distribution/v3 v3.0.0-20230214150026-36d8c594d7aa/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI=
|
||||
github.com/docker/cli v24.0.2+incompatible h1:QdqR7znue1mtkXIJ+ruQMGQhpw2JzMJLRXp6zpzF6tM=
|
||||
github.com/docker/cli v24.0.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli-docs-tool v0.5.1 h1:jIk/cCZurZERhALPVKhqlNxTQGxn2kcI+56gE57PQXg=
|
||||
github.com/docker/cli-docs-tool v0.5.1/go.mod h1:zMjqTFCU361PRh8apiXzeAZ1Q/xupbIwTusYpzCXS/o=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v24.0.5+incompatible h1:WeBimjvS0eKdH4Ygx+ihVq1Q++xg36M/rMi4aXAvodc=
|
||||
github.com/docker/cli v24.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli-docs-tool v0.6.0 h1:Z9x10SaZgFaB6jHgz3OWooynhSa40CsWkpe5hEnG/qA=
|
||||
github.com/docker/cli-docs-tool v0.6.0/go.mod h1:zMjqTFCU361PRh8apiXzeAZ1Q/xupbIwTusYpzCXS/o=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v24.0.2+incompatible h1:eATx+oLz9WdNVkQrr0qjQ8HvRJ4bOOxfzEo8R+dA3cg=
|
||||
github.com/docker/docker v24.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY=
|
||||
github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
|
||||
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
||||
@@ -164,16 +169,16 @@ github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
|
||||
github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
|
||||
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
||||
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/libtrust v0.0.0-20150526203908-9cbd2a1374f4 h1:k8TfKGeAcDQFFQOGCQMRN04N4a9YrPlRMMKnzAuvM9Q=
|
||||
github.com/docker/libtrust v0.0.0-20150526203908-9cbd2a1374f4/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 h1:pEtiCjIXx3RvGjlUJuCNxNOw0MNblyR9Wi+vJGBFh+8=
|
||||
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
||||
github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ=
|
||||
github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
@@ -183,9 +188,10 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fvbommel/sortorder v1.0.1 h1:dSnXLt4mJYH25uDDGa3biZNQsozaUWDSWeKJ0qqFfzE=
|
||||
github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
@@ -210,19 +216,19 @@ github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXym
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
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-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||
github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0=
|
||||
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
|
||||
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
|
||||
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
|
||||
@@ -258,8 +264,8 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/certificate-transparency-go v1.1.4 h1:hCyXHDbtqlr/lMXU0D4WgbalXL0Zk4dSWWMbPV8VrqY=
|
||||
github.com/google/certificate-transparency-go v1.1.4/go.mod h1:D6lvbfwckhNrbM9WVl1EVeMOyzC19mpIjMOI4nxBHtQ=
|
||||
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 v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54=
|
||||
github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
@@ -296,6 +302,7 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
@@ -307,24 +314,28 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjd
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
|
||||
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/go-cty-funcs v0.0.0-20200930094925-2721b1e36840 h1:kgvybwEeu0SXktbB2y3uLHX9lklLo+nzUwh59A3jzQc=
|
||||
github.com/hashicorp/go-cty-funcs v0.0.0-20200930094925-2721b1e36840/go.mod h1:Abjk0jbRkDaNCzsRhOv2iDCofYpX1eVsjozoiK63qLA=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992 h1:fYOrSfO5C9PmFGtmRWSYGqq52SOoE2dXMtAn2Xzh1LQ=
|
||||
github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992/go.mod h1:Abjk0jbRkDaNCzsRhOv2iDCofYpX1eVsjozoiK63qLA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl/v2 v2.8.2 h1:wmFle3D1vu0okesm8BTLVDyJ6/OL9DCLUwn0b2OptiY=
|
||||
github.com/hashicorp/hcl/v2 v2.8.2/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY=
|
||||
github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI=
|
||||
github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
|
||||
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||
github.com/in-toto/in-toto-golang v0.5.0 h1:hb8bgwr0M2hGdDsLjkJ3ZqJ8JFLL/tgYdAxF/XEFBbY=
|
||||
github.com/in-toto/in-toto-golang v0.5.0/go.mod h1:/Rq0IZHLV7Ku5gielPT4wPHJfH1GdHMCq8+WPxw8/BE=
|
||||
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 v1.9.2 h1:lCvgEaqe/HVE+tjAR2mt4HbbHAZsQOv3XAZiEZV37iw=
|
||||
github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
|
||||
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a h1:eeaG9XMUvRBYXJi4pg1ZKM7nxc5AfXfojeLLW7O5J3k=
|
||||
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
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/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
@@ -335,48 +346,51 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||
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.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
|
||||
github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
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=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||
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.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
|
||||
github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
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.11.0-rc3.0.20230609092854-67a08623b95a h1:1k3bAXwxC2N1FncWijq/43sLj2OVIZ11FT0APIXWhMg=
|
||||
github.com/moby/buildkit v0.11.0-rc3.0.20230609092854-67a08623b95a/go.mod h1:4sM7BBBqXOQ+vV6LrVAOAMhZI9cVNYV5RhZCl906a64=
|
||||
github.com/moby/buildkit v0.13.0-beta1.0.20231023114302-d5c1d785b042 h1:1J+fRIucIeyl1gvSYOlTcN0gmsZ8SMlLdkwB01PEn94=
|
||||
github.com/moby/buildkit v0.13.0-beta1.0.20231023114302-d5c1d785b042/go.mod h1:3sbzGMUHhpx+6++efVlHhvcarzusX1+QbGTR/S4y9gI=
|
||||
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
|
||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
||||
github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
|
||||
github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
|
||||
@@ -400,40 +414,51 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
|
||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||
github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||
github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys=
|
||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
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.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk=
|
||||
github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/opencontainers/runc v1.1.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM=
|
||||
github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
|
||||
github.com/opencontainers/runtime-spec v1.1.0-rc.2 h1:ucBtEms2tamYYW/SvGpvq9yUN0NEVL6oyLEwDcTSrk8=
|
||||
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
|
||||
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=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.0-pre1.0.20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
|
||||
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
@@ -441,38 +466,40 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
|
||||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.4.0/go.mod h1:FGBZgq2tXWICsxWQW1msNf49F0Pf2Op5Htayx335Qbs=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 h1:ka9QPuQg2u4LGipiZGsgkg3rJCo4iIUCy75FddM0GRQ=
|
||||
github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002/go.mod h1:/yeG0My1xr/u+HZrFQ1tOQQQQrOawfyMUH13ai5brBc=
|
||||
github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=
|
||||
github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE=
|
||||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spdx/tools-golang v0.5.1 h1:fJg3SVOGG+eIva9ZUBm/hvyA7PIPVFjRxUKe6fdAgwE=
|
||||
github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw=
|
||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
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.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431 h1:XTHrT015sxHyJ5FnQ0AeemSspZWaDq7DoTRW0EVsDCE=
|
||||
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 v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU=
|
||||
github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As=
|
||||
github.com/spf13/viper v0.0.0-20150530192845-be5ff3e4840c h1:2EejZtjFjKJGk71ANb+wtFK5EjUzUkEM3R0xnp559xg=
|
||||
github.com/spf13/viper v0.0.0-20150530192845-be5ff3e4840c/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
|
||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||
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=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
@@ -481,21 +508,19 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
|
||||
github.com/theupdateframework/notary v0.6.1 h1:7wshjstgS9x9F5LuB1L5mBI2xNMObWqjz+cjWoom6l0=
|
||||
github.com/theupdateframework/notary v0.6.1/go.mod h1:MOfgIfmox8s7/7fduvB2xyPPMJCrjRLRizA8OFwpnKY=
|
||||
github.com/tonistiigi/fsutil v0.0.0-20230407161946-9e7a6df48576 h1:fZXPQDVh5fm2x7pA0CH1TtH80tiZ0L7i834kZqZN8Pw=
|
||||
github.com/tonistiigi/fsutil v0.0.0-20230407161946-9e7a6df48576/go.mod h1:q1CxMSzcAbjUkVGHoZeQUcCaALnaE4XdWk+zJcgMYFw=
|
||||
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/fsutil v0.0.0-20230629203738-36ef4d8c0dbb h1:uUe8rNyVXM8moActoBol6Xf6xX2GMr7SosR2EywMvGg=
|
||||
github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb/go.mod h1:SxX/oNQ/ag6Vaoli547ipFK9J7BZn5JqJG0JE8lf8bA=
|
||||
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-20210615222946-8066bb97264f h1:DLpt6B5oaaS8jyXHa9VA4rrZloBVPVXeCtrOsrFauxc=
|
||||
github.com/tonistiigi/vt100 v0.0.0-20210615222946-8066bb97264f/go.mod h1:ulncasL3N9uLrVann0m+CDlJKWsIAP34MPcOJF6VRvc=
|
||||
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 h1:Y/M5lygoNPKwVNLMPXgVfsRT40CSFKXCxuU8LoHySjs=
|
||||
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531/go.mod h1:ulncasL3N9uLrVann0m+CDlJKWsIAP34MPcOJF6VRvc=
|
||||
github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME=
|
||||
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
|
||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
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=
|
||||
@@ -504,10 +529,9 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
|
||||
github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ=
|
||||
github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0=
|
||||
github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||
github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA=
|
||||
github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
@@ -545,14 +569,16 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
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.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE=
|
||||
golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -563,6 +589,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw=
|
||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -583,11 +611,11 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
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.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -616,8 +644,8 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -636,17 +664,17 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
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=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -654,6 +682,7 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -679,19 +708,20 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/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.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -804,6 +834,7 @@ google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
||||
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
@@ -837,22 +868,23 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
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=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/dancannon/gorethink.v3 v3.0.5 h1:/g7PWP7zUS6vSNmHSDbjCHQh1Rqn8Jy6zSMQxAsBSMQ=
|
||||
gopkg.in/dancannon/gorethink.v3 v3.0.5/go.mod h1:GXsi1e3N2OcKhcP6nsYABTiUejbWMFO4GY5a4pEaeEc=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fatih/pool.v2 v2.0.0 h1:xIFeWtxifuQJGk/IEPKsTduEKcKvPmhoiVDGpC40nKg=
|
||||
gopkg.in/fatih/pool.v2 v2.0.0/go.mod h1:8xVGeu1/2jr2wm5V9SPuMht2H5AEmf5aFMGSQixtjTY=
|
||||
gopkg.in/gorethink/gorethink.v3 v3.0.5 h1:e2Uc/Xe+hpcVQFsj6MuHlYog3r0JYpnTzwDj/y2O4MU=
|
||||
gopkg.in/gorethink/gorethink.v3 v3.0.5/go.mod h1:+3yIIHJUGMBK+wyPH+iN5TP+88ikFDfZdqTlK3Y9q8I=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
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/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
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=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
@@ -872,14 +904,14 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.26.2 h1:dM3cinp3PGB6asOySalOZxEG4CZ0IAdJsrYZXE/ovGQ=
|
||||
k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU=
|
||||
k8s.io/apimachinery v0.26.2 h1:da1u3D5wfR5u2RpLhE/ZtZS2P7QvDgLZTi9wrNZl/tQ=
|
||||
k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I=
|
||||
k8s.io/apiserver v0.26.2 h1:Pk8lmX4G14hYqJd1poHGC08G03nIHVqdJMR0SD3IH3o=
|
||||
k8s.io/apiserver v0.26.2/go.mod h1:GHcozwXgXsPuOJ28EnQ/jXEM9QeG6HT22YxSNmpYNh8=
|
||||
k8s.io/client-go v0.26.2 h1:s1WkVujHX3kTp4Zn4yGNFK+dlDXy1bAAkIl+cFAiuYI=
|
||||
k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU=
|
||||
k8s.io/api v0.26.7 h1:Lf4iEBEJb5OFNmawtBfSZV/UNi9riSJ0t1qdhyZqI40=
|
||||
k8s.io/api v0.26.7/go.mod h1:Vk9bMadzA49UHPmHB//lX7VRCQSXGoVwfLd3Sc1SSXI=
|
||||
k8s.io/apimachinery v0.26.7 h1:590jSBwaSHCAFCqltaEogY/zybFlhGsnLteLpuF2wig=
|
||||
k8s.io/apimachinery v0.26.7/go.mod h1:qYzLkrQ9lhrZRh0jNKo2cfvf/R1/kQONnSiyB7NUJU0=
|
||||
k8s.io/apiserver v0.26.7 h1:NX/zBZZn4R+Cq6shwyn8Pn8REd0yJJ16dbtv9WkEVEU=
|
||||
k8s.io/apiserver v0.26.7/go.mod h1:r0wDRWHI7VL/KlQLTkJJBVGZ3KeNfv+VetlyRtr86xs=
|
||||
k8s.io/client-go v0.26.7 h1:hyU9aKHlwVOykgyxzGYkrDSLCc4+mimZVyUJjPyUn1E=
|
||||
k8s.io/client-go v0.26.7/go.mod h1:okYjy0jtq6sdeztALDvCh24tg4opOQS1XNvsJlERDAo=
|
||||
k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
|
||||
k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E=
|
||||
|
@@ -9,8 +9,9 @@ set -e
|
||||
|
||||
: "${CGO_ENABLED=0}"
|
||||
: "${GO_PKG=github.com/docker/buildx}"
|
||||
: "${GO_EXTRA_FLAGS=}"
|
||||
: "${GO_LDFLAGS=-X ${GO_PKG}/version.Version=${VERSION} -X ${GO_PKG}/version.Revision=${REVISION} -X ${GO_PKG}/version.Package=${PACKAGE}}"
|
||||
: "${GO_EXTRA_LDFLAGS=}"
|
||||
|
||||
set -x
|
||||
CGO_ENABLED=$CGO_ENABLED go build -mod vendor -trimpath -ldflags "${GO_LDFLAGS} ${GO_EXTRA_LDFLAGS}" -o "${DESTDIR}/docker-buildx" ./cmd/buildx
|
||||
CGO_ENABLED=$CGO_ENABLED go build -mod vendor -trimpath ${GO_EXTRA_FLAGS} -ldflags "${GO_LDFLAGS} ${GO_EXTRA_LDFLAGS}" -o "${DESTDIR}/docker-buildx" ./cmd/buildx
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG GO_VERSION=1.20
|
||||
ARG GO_VERSION=1.21.3
|
||||
ARG FORMATS=md,yaml
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine AS docsgen
|
||||
|
@@ -5,11 +5,11 @@
|
||||
# Copyright The Buildx Authors.
|
||||
# Licensed under the Apache License, Version 2.0
|
||||
|
||||
ARG GO_VERSION="1.20"
|
||||
ARG GO_VERSION="1.21.3"
|
||||
ARG PROTOC_VERSION="3.11.4"
|
||||
|
||||
# protoc is dynamically linked to glibc so can't use alpine base
|
||||
FROM golang:${GO_VERSION}-buster AS base
|
||||
FROM golang:${GO_VERSION}-bookworm AS base
|
||||
RUN apt-get update && apt-get --no-install-recommends install -y git unzip
|
||||
ARG PROTOC_VERSION
|
||||
ARG TARGETOS
|
||||
|
@@ -1,10 +1,14 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG GO_VERSION=1.20
|
||||
ARG GO_VERSION=1.21.3
|
||||
ARG GOLANGCI_LINT_VERSION=1.54.2
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine
|
||||
RUN apk add --no-cache git gcc musl-dev
|
||||
RUN wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.51.1
|
||||
ENV GOFLAGS="-buildvcs=false"
|
||||
ARG GOLANGCI_LINT_VERSION
|
||||
RUN wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v${GOLANGCI_LINT_VERSION}
|
||||
WORKDIR /go/src/github.com/docker/buildx
|
||||
RUN --mount=target=/go/src/github.com/docker/buildx --mount=target=/root/.cache,type=cache \
|
||||
golangci-lint run
|
||||
RUN --mount=target=/go/src/github.com/docker/buildx \
|
||||
--mount=target=/root/.cache,type=cache \
|
||||
golangci-lint run
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG GO_VERSION=1.20
|
||||
ARG GO_VERSION=1.21.3
|
||||
ARG MODOUTDATED_VERSION=v0.8.0
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine AS base
|
||||
|
@@ -1,19 +1,43 @@
|
||||
package localstate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
const refsDir = "refs"
|
||||
const (
|
||||
refsDir = "refs"
|
||||
groupDir = "__group__"
|
||||
)
|
||||
|
||||
type State struct {
|
||||
LocalPath string
|
||||
// Target is the name of the invoked target (default if empty)
|
||||
Target string
|
||||
// LocalPath is the absolute path to the context
|
||||
LocalPath string
|
||||
// DockerfilePath is the absolute path to the Dockerfile
|
||||
DockerfilePath string
|
||||
// GroupRef is the ref of the state group that this ref belongs to
|
||||
GroupRef string `json:",omitempty"`
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type LocalState struct {
|
||||
@@ -62,13 +86,58 @@ func (ls *LocalState) SaveRef(builderName, nodeName, id string, st State) error
|
||||
return ioutils.AtomicWriteFile(filepath.Join(refDir, id), dt, 0600)
|
||||
}
|
||||
|
||||
func (ls *LocalState) ReadGroup(id string) (*StateGroup, error) {
|
||||
dt, err := os.ReadFile(filepath.Join(ls.root, refsDir, groupDir, id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var stg StateGroup
|
||||
if err := json.Unmarshal(dt, &stg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &stg, nil
|
||||
}
|
||||
|
||||
func (ls *LocalState) SaveGroup(id string, stg StateGroup) error {
|
||||
refDir := filepath.Join(ls.root, refsDir, groupDir)
|
||||
if err := os.MkdirAll(refDir, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
dt, err := json.Marshal(stg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutils.AtomicWriteFile(filepath.Join(refDir, id), dt, 0600)
|
||||
}
|
||||
|
||||
func (ls *LocalState) RemoveBuilder(builderName string) error {
|
||||
if builderName == "" {
|
||||
return errors.Errorf("builder name empty")
|
||||
}
|
||||
return os.RemoveAll(filepath.Join(ls.root, refsDir, builderName))
|
||||
|
||||
dir := filepath.Join(ls.root, refsDir, builderName)
|
||||
if _, err := os.Lstat(dir); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
fis, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, fi := range fis {
|
||||
if err := ls.RemoveBuilderNode(builderName, fi.Name()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return os.RemoveAll(dir)
|
||||
}
|
||||
|
||||
// RemoveBuilderNode removes all refs for a builder node.
|
||||
// This func is not safe for concurrent use from multiple goroutines.
|
||||
func (ls *LocalState) RemoveBuilderNode(builderName string, nodeName string) error {
|
||||
if builderName == "" {
|
||||
return errors.Errorf("builder name empty")
|
||||
@@ -76,7 +145,76 @@ func (ls *LocalState) RemoveBuilderNode(builderName string, nodeName string) err
|
||||
if nodeName == "" {
|
||||
return errors.Errorf("node name empty")
|
||||
}
|
||||
return os.RemoveAll(filepath.Join(ls.root, refsDir, builderName, nodeName))
|
||||
|
||||
dir := filepath.Join(ls.root, refsDir, builderName, nodeName)
|
||||
if _, err := os.Lstat(dir); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
fis, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var murefs sync.Mutex
|
||||
grefs := make(map[string][]string)
|
||||
srefs := make(map[string][]string)
|
||||
eg, _ := errgroup.WithContext(context.TODO())
|
||||
for _, fi := range fis {
|
||||
func(fi os.DirEntry) {
|
||||
eg.Go(func() error {
|
||||
st, err := ls.ReadRef(builderName, nodeName, fi.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if st.GroupRef == "" {
|
||||
return nil
|
||||
}
|
||||
murefs.Lock()
|
||||
defer murefs.Unlock()
|
||||
if _, ok := grefs[st.GroupRef]; !ok {
|
||||
if grp, err := ls.ReadGroup(st.GroupRef); err == nil {
|
||||
grefs[st.GroupRef] = grp.Refs
|
||||
}
|
||||
}
|
||||
srefs[st.GroupRef] = append(srefs[st.GroupRef], fmt.Sprintf("%s/%s/%s", builderName, nodeName, fi.Name()))
|
||||
return nil
|
||||
})
|
||||
}(fi)
|
||||
}
|
||||
if err := eg.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for gid, refs := range grefs {
|
||||
if s, ok := srefs[gid]; ok {
|
||||
if len(s) != len(refs) {
|
||||
continue
|
||||
}
|
||||
if err := ls.removeGroup(gid); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return os.RemoveAll(dir)
|
||||
}
|
||||
|
||||
func (ls *LocalState) removeGroup(id string) error {
|
||||
if id == "" {
|
||||
return errors.Errorf("group ref empty")
|
||||
}
|
||||
f := filepath.Join(ls.root, refsDir, groupDir, id)
|
||||
if _, err := os.Lstat(f); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return os.Remove(f)
|
||||
}
|
||||
|
||||
func (ls *LocalState) validate(builderName, nodeName, id string) error {
|
||||
|
99
localstate/localstate_test.go
Normal file
99
localstate/localstate_test.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package localstate
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
_ = newls(t)
|
||||
}
|
||||
|
||||
func TestReadRef(t *testing.T) {
|
||||
l := newls(t)
|
||||
r, err := l.ReadRef(testBuilderName, testNodeName, testStateRefID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, testStateRef, *r)
|
||||
}
|
||||
|
||||
func TestReadGroup(t *testing.T) {
|
||||
l := newls(t)
|
||||
g, err := l.ReadGroup(testStateGroupID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, testStateGroup, *g)
|
||||
}
|
||||
|
||||
func TestRemoveBuilder(t *testing.T) {
|
||||
l := newls(t)
|
||||
require.NoError(t, l.RemoveBuilder(testBuilderName))
|
||||
}
|
||||
|
||||
func TestRemoveBuilderNode(t *testing.T) {
|
||||
l := newls(t)
|
||||
require.NoError(t, l.RemoveBuilderNode(testBuilderName, testNodeName))
|
||||
}
|
||||
|
||||
func newls(t *testing.T) *LocalState {
|
||||
t.Helper()
|
||||
tmpdir := t.TempDir()
|
||||
|
||||
l, err := New(tmpdir)
|
||||
require.NoError(t, err)
|
||||
require.DirExists(t, filepath.Join(tmpdir, refsDir))
|
||||
require.Equal(t, tmpdir, l.root)
|
||||
|
||||
require.NoError(t, l.SaveRef(testBuilderName, testNodeName, testStateRefID, testStateRef))
|
||||
|
||||
require.NoError(t, l.SaveGroup(testStateGroupID, testStateGroup))
|
||||
require.NoError(t, l.SaveRef(testBuilderName, testNodeName, testStateGroupRef1ID, testStateGroupRef1))
|
||||
require.NoError(t, l.SaveRef(testBuilderName, testNodeName, testStateGroupRef2ID, testStateGroupRef2))
|
||||
require.NoError(t, l.SaveRef(testBuilderName, testNodeName, testStateGroupRef3ID, testStateGroupRef3))
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
var (
|
||||
testBuilderName = "builder"
|
||||
testNodeName = "builder0"
|
||||
|
||||
testStateRefID = "32n3ffqrxjw41ok5zxd2qhume"
|
||||
testStateRef = State{
|
||||
Target: "default",
|
||||
LocalPath: "/home/foo/github.com/docker/docker-bake-action",
|
||||
DockerfilePath: "/home/foo/github.com/docker/docker-bake-action/dev.Dockerfile",
|
||||
}
|
||||
|
||||
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"},
|
||||
}
|
||||
|
||||
testStateGroupRef1ID = "hx2qf1w11qvz1x3k471c5i8xw"
|
||||
testStateGroupRef1 = State{
|
||||
Target: "format",
|
||||
LocalPath: "/home/foo/github.com/docker/docker-bake-action",
|
||||
DockerfilePath: "/home/foo/github.com/docker/docker-bake-action/dev.Dockerfile",
|
||||
GroupRef: "kvqs0sgly2rmitz84r25u9qd0",
|
||||
}
|
||||
|
||||
testStateGroupRef2ID = "968zj0g03jmlx0s8qslnvh6rl"
|
||||
testStateGroupRef2 = State{
|
||||
Target: "build",
|
||||
LocalPath: "/home/foo/github.com/docker/docker-bake-action",
|
||||
DockerfilePath: "/home/foo/github.com/docker/docker-bake-action/dev.Dockerfile",
|
||||
GroupRef: "kvqs0sgly2rmitz84r25u9qd0",
|
||||
}
|
||||
|
||||
testStateGroupRef3ID = "naf44f9i1710lf7y12lv5hb1z"
|
||||
testStateGroupRef3 = State{
|
||||
Target: "vendor-update",
|
||||
LocalPath: "/home/foo/github.com/docker/docker-bake-action",
|
||||
DockerfilePath: "/home/foo/github.com/docker/docker-bake-action/dev.Dockerfile",
|
||||
GroupRef: "kvqs0sgly2rmitz84r25u9qd0",
|
||||
}
|
||||
)
|
@@ -28,7 +28,7 @@ Usage:
|
||||
attach ID
|
||||
|
||||
ID is for a session (visible via list command) or a process (visible via ps command).
|
||||
If you attached to a process, use Ctrl-c-a for switching the monitor to that process's STDIO.
|
||||
If you attached to a process, use Ctrl-a-c for switching the monitor to that process's STDIO.
|
||||
`,
|
||||
}
|
||||
}
|
||||
|
@@ -35,12 +35,16 @@ COMMAND and ARG... will be executed in the container.
|
||||
}
|
||||
|
||||
func (cm *ExecCmd) Exec(ctx context.Context, args []string) error {
|
||||
if ref := cm.m.AttachedSessionID(); ref == "" {
|
||||
return errors.Errorf("no attaching session")
|
||||
}
|
||||
if len(args) < 2 {
|
||||
return errors.Errorf("command must be passed")
|
||||
}
|
||||
cfg := controllerapi.InvokeConfig{
|
||||
Entrypoint: []string{args[1]},
|
||||
Cmd: args[2:],
|
||||
NoCmd: false,
|
||||
// TODO: support other options as well via flags
|
||||
Env: cm.invokeConfig.Env,
|
||||
User: cm.invokeConfig.User,
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
controllerapi "github.com/docker/buildx/controller/pb"
|
||||
"github.com/docker/buildx/monitor/types"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/moby/buildkit/solver/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -70,6 +71,11 @@ func (cm *ReloadCmd) Exec(ctx context.Context, args []string) error {
|
||||
} else {
|
||||
fmt.Printf("failed to reload: %v\n", err)
|
||||
}
|
||||
// report error
|
||||
for _, s := range errdefs.Sources(err) {
|
||||
s.Print(cm.stdout)
|
||||
}
|
||||
fmt.Fprintf(cm.stdout, "ERROR: %v\n", err)
|
||||
} else {
|
||||
resultUpdated = true
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
controllerapi "github.com/docker/buildx/controller/pb"
|
||||
"github.com/docker/buildx/monitor/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type RollbackCmd struct {
|
||||
@@ -37,6 +38,9 @@ COMMAND and ARG... will be executed in the container.
|
||||
}
|
||||
|
||||
func (cm *RollbackCmd) Exec(ctx context.Context, args []string) error {
|
||||
if ref := cm.m.AttachedSessionID(); ref == "" {
|
||||
return errors.Errorf("no attaching session")
|
||||
}
|
||||
cfg := cm.invokeConfig
|
||||
if len(args) >= 2 {
|
||||
cmds := args[1:]
|
||||
@@ -47,6 +51,7 @@ func (cm *RollbackCmd) Exec(ctx context.Context, args []string) error {
|
||||
if len(cmds) > 0 {
|
||||
cfg.Entrypoint = []string{cmds[0]}
|
||||
cfg.Cmd = cmds[1:]
|
||||
cfg.NoCmd = false
|
||||
}
|
||||
}
|
||||
id := cm.m.Rollback(ctx, cfg)
|
||||
|
@@ -17,14 +17,20 @@ import (
|
||||
"github.com/docker/buildx/util/ioset"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/google/shlex"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/identity"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
type MonitorBuildResult struct {
|
||||
Resp *client.SolveResponse
|
||||
Err error
|
||||
}
|
||||
|
||||
// RunMonitor provides an interactive session for running and managing containers via specified IO.
|
||||
func RunMonitor(ctx context.Context, curRef string, options *controllerapi.BuildOptions, invokeConfig controllerapi.InvokeConfig, c control.BuildxController, stdin io.ReadCloser, stdout io.WriteCloser, stderr console.File, progress *progress.Printer) error {
|
||||
func RunMonitor(ctx context.Context, curRef string, options *controllerapi.BuildOptions, invokeConfig controllerapi.InvokeConfig, c control.BuildxController, stdin io.ReadCloser, stdout io.WriteCloser, stderr console.File, progress *progress.Printer) (*MonitorBuildResult, error) {
|
||||
defer func() {
|
||||
if err := c.Disconnect(ctx, curRef); err != nil {
|
||||
logrus.Warnf("disconnect error: %v", err)
|
||||
@@ -32,7 +38,7 @@ func RunMonitor(ctx context.Context, curRef string, options *controllerapi.Build
|
||||
}()
|
||||
|
||||
if err := progress.Pause(); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
defer progress.Unpause()
|
||||
|
||||
@@ -169,10 +175,10 @@ func RunMonitor(ctx context.Context, curRef string, options *controllerapi.Build
|
||||
select {
|
||||
case <-doneCh:
|
||||
m.close()
|
||||
return nil
|
||||
return m.lastBuildResult, nil
|
||||
case err := <-errCh:
|
||||
m.close()
|
||||
return err
|
||||
return m.lastBuildResult, err
|
||||
case <-monitorDisableCh:
|
||||
}
|
||||
monitorForwarder.SetOut(nil)
|
||||
@@ -233,6 +239,14 @@ type monitor struct {
|
||||
invokeIO *ioset.Forwarder
|
||||
invokeCancel func()
|
||||
attachedPid atomic.Value
|
||||
|
||||
lastBuildResult *MonitorBuildResult
|
||||
}
|
||||
|
||||
func (m *monitor) Build(ctx context.Context, options controllerapi.BuildOptions, in io.ReadCloser, progress progress.Writer) (ref string, resp *client.SolveResponse, err error) {
|
||||
ref, resp, err = m.BuildxController.Build(ctx, options, in, progress)
|
||||
m.lastBuildResult = &MonitorBuildResult{Resp: resp, Err: err} // Record build result
|
||||
return
|
||||
}
|
||||
|
||||
func (m *monitor) DisconnectSession(ctx context.Context, targetID string) error {
|
||||
@@ -283,11 +297,16 @@ func (m *monitor) startInvoke(ctx context.Context, pid string, cfg controllerapi
|
||||
if len(cfg.Entrypoint) == 0 && len(cfg.Cmd) == 0 {
|
||||
cfg.Entrypoint = []string{"sh"} // launch shell by default
|
||||
cfg.Cmd = []string{}
|
||||
cfg.NoCmd = false
|
||||
}
|
||||
go func() {
|
||||
// Start a new invoke
|
||||
if err := m.invoke(ctx, pid, cfg); err != nil {
|
||||
logrus.Debugf("invoke error: %v", err)
|
||||
if errors.Is(err, context.Canceled) {
|
||||
logrus.Debugf("process canceled: %v", err)
|
||||
} else {
|
||||
logrus.Errorf("invoke: %v", err)
|
||||
}
|
||||
}
|
||||
if pid == m.attachedPid.Load() {
|
||||
m.attachedPid.Store("")
|
||||
|
@@ -102,10 +102,7 @@ func (ng *NodeGroup) Update(name, endpoint string, platforms []string, endpoints
|
||||
}
|
||||
|
||||
ng.Nodes[i] = n
|
||||
if err := ng.validateDuplicates(endpoint, i); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return ng.validateDuplicates(endpoint, i)
|
||||
}
|
||||
|
||||
if name == "" {
|
||||
@@ -127,11 +124,7 @@ func (ng *NodeGroup) Update(name, endpoint string, platforms []string, endpoints
|
||||
}
|
||||
|
||||
ng.Nodes = append(ng.Nodes, n)
|
||||
|
||||
if err := ng.validateDuplicates(endpoint, len(ng.Nodes)-1); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return ng.validateDuplicates(endpoint, len(ng.Nodes)-1)
|
||||
}
|
||||
|
||||
func (ng *NodeGroup) Copy() *NodeGroup {
|
||||
|
@@ -185,10 +185,7 @@ func (t *Txn) reset(key string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutils.AtomicWriteFile(filepath.Join(t.s.root, "current"), dt, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return ioutils.AtomicWriteFile(filepath.Join(t.s.root, "current"), dt, 0600)
|
||||
}
|
||||
|
||||
func (t *Txn) Current(key string) (*NodeGroup, error) {
|
||||
|
@@ -18,9 +18,9 @@ func TestEmptyStartup(t *testing.T) {
|
||||
s, err := New(tmpdir)
|
||||
require.NoError(t, err)
|
||||
|
||||
txn, close, err := s.Txn()
|
||||
txn, release, err := s.Txn()
|
||||
require.NoError(t, err)
|
||||
defer close()
|
||||
defer release()
|
||||
|
||||
ng, err := txn.Current("foo")
|
||||
require.NoError(t, err)
|
||||
@@ -235,3 +235,26 @@ func TestNodeManagement(t *testing.T) {
|
||||
require.NotNil(t, ng)
|
||||
require.Equal(t, "mybuild", ng.Name)
|
||||
}
|
||||
|
||||
func TestNodeInvalidName(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpdir := t.TempDir()
|
||||
|
||||
s, err := New(tmpdir)
|
||||
require.NoError(t, err)
|
||||
|
||||
txn, release, err := s.Txn()
|
||||
require.NoError(t, err)
|
||||
defer release()
|
||||
|
||||
_, err = txn.NodeGroupByName("123builder")
|
||||
require.Error(t, err)
|
||||
require.True(t, IsErrInvalidName(err))
|
||||
|
||||
err = txn.Save(&NodeGroup{
|
||||
Name: "123builder",
|
||||
Driver: "mydriver",
|
||||
})
|
||||
require.Error(t, err)
|
||||
require.True(t, IsErrInvalidName(err))
|
||||
}
|
||||
|
@@ -74,7 +74,7 @@ func GetCurrentInstance(txn *store.Txn, dockerCli command.Cli) (*store.NodeGroup
|
||||
func GetNodeGroup(txn *store.Txn, dockerCli command.Cli, name string) (*store.NodeGroup, error) {
|
||||
ng, err := txn.NodeGroupByName(name)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(errors.Cause(err)) {
|
||||
if !os.IsNotExist(errors.Cause(err)) && !store.IsErrInvalidName(err) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@@ -11,9 +11,28 @@ import (
|
||||
|
||||
var namePattern = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9\.\-_]*$`)
|
||||
|
||||
type errInvalidName struct {
|
||||
error
|
||||
}
|
||||
|
||||
func (e *errInvalidName) Error() string {
|
||||
return e.error.Error()
|
||||
}
|
||||
|
||||
func (e *errInvalidName) Unwrap() error {
|
||||
return e.error
|
||||
}
|
||||
|
||||
func IsErrInvalidName(err error) bool {
|
||||
_, ok := err.(*errInvalidName)
|
||||
return ok
|
||||
}
|
||||
|
||||
func ValidateName(s string) (string, error) {
|
||||
if !namePattern.MatchString(s) {
|
||||
return "", errors.Errorf("invalid name %s, name needs to start with a letter and may not contain symbols, except ._-", s)
|
||||
return "", &errInvalidName{
|
||||
errors.Errorf("invalid name %s, name needs to start with a letter and may not contain symbols, except ._-", s),
|
||||
}
|
||||
}
|
||||
return strings.ToLower(s), nil
|
||||
}
|
||||
|
221
tests/bake.go
221
tests/bake.go
@@ -1,6 +1,7 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
@@ -18,12 +19,86 @@ func bakeCmd(sb integration.Sandbox, opts ...cmdOpt) (string, error) {
|
||||
}
|
||||
|
||||
var bakeTests = []func(t *testing.T, sb integration.Sandbox){
|
||||
testBakeLocal,
|
||||
testBakeLocalMulti,
|
||||
testBakeRemote,
|
||||
testBakeRemoteCmdContext,
|
||||
testBakeRemoteLocalOverride,
|
||||
testBakeRemoteCmdContextOverride,
|
||||
testBakeRemoteContextSubdir,
|
||||
testBakeRemoteCmdContextEscapeRoot,
|
||||
testBakeRemoteCmdContextEscapeRelative,
|
||||
testBakeRemoteDockerfileCwd,
|
||||
testBakeRemoteLocalContextRemoteDockerfile,
|
||||
testBakeEmpty,
|
||||
}
|
||||
|
||||
func testBakeLocal(t *testing.T, sb integration.Sandbox) {
|
||||
dockerfile := []byte(`
|
||||
FROM scratch
|
||||
COPY foo /foo
|
||||
`)
|
||||
bakefile := []byte(`
|
||||
target "default" {
|
||||
}
|
||||
`)
|
||||
dir := tmpdir(
|
||||
t,
|
||||
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
|
||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
||||
)
|
||||
|
||||
dirDest := t.TempDir()
|
||||
|
||||
cmd := buildxCmd(sb, withDir(dir), withArgs("bake", "--progress=plain", "--set", "*.output=type=local,dest="+dirDest))
|
||||
out, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, out)
|
||||
require.Contains(t, string(out), `#1 [internal] load local bake definitions`)
|
||||
require.Contains(t, string(out), `#1 reading docker-bake.hcl`)
|
||||
|
||||
require.FileExists(t, filepath.Join(dirDest, "foo"))
|
||||
}
|
||||
|
||||
func testBakeLocalMulti(t *testing.T, sb integration.Sandbox) {
|
||||
dockerfile := []byte(`
|
||||
FROM scratch
|
||||
COPY foo /foo
|
||||
`)
|
||||
bakefile := []byte(`
|
||||
target "default" {
|
||||
}
|
||||
`)
|
||||
composefile := []byte(`
|
||||
services:
|
||||
app:
|
||||
build: {}
|
||||
`)
|
||||
|
||||
dir := tmpdir(
|
||||
t,
|
||||
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
|
||||
fstest.CreateFile("compose.yaml", composefile, 0600),
|
||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
||||
)
|
||||
|
||||
dirDest := t.TempDir()
|
||||
|
||||
cmd := buildxCmd(sb, withDir(dir), withArgs("bake", "--progress=plain", "--set", "*.output=type=local,dest="+dirDest))
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
require.Contains(t, string(dt), `#1 [internal] load local bake definitions`)
|
||||
require.Contains(t, string(dt), `#1 reading compose.yaml`)
|
||||
require.Contains(t, string(dt), `#1 reading docker-bake.hcl`)
|
||||
require.FileExists(t, filepath.Join(dirDest, "foo"))
|
||||
|
||||
dirDest2 := t.TempDir()
|
||||
|
||||
out, err := bakeCmd(sb, withDir(dir), withArgs("--file", "cwd://docker-bake.hcl", "--set", "*.output=type=local,dest="+dirDest2))
|
||||
require.NoError(t, err, out)
|
||||
|
||||
require.FileExists(t, filepath.Join(dirDest2, "foo"))
|
||||
}
|
||||
|
||||
func testBakeRemote(t *testing.T, sb integration.Sandbox) {
|
||||
@@ -56,6 +131,48 @@ EOT
|
||||
require.FileExists(t, filepath.Join(dirDest, "foo"))
|
||||
}
|
||||
|
||||
func testBakeRemoteLocalOverride(t *testing.T, sb integration.Sandbox) {
|
||||
remoteBakefile := []byte(`
|
||||
target "default" {
|
||||
dockerfile-inline = <<EOT
|
||||
FROM scratch
|
||||
COPY foo /foo
|
||||
EOT
|
||||
}
|
||||
`)
|
||||
localBakefile := []byte(`
|
||||
target "default" {
|
||||
dockerfile-inline = <<EOT
|
||||
FROM scratch
|
||||
COPY bar /bar
|
||||
EOT
|
||||
}
|
||||
`)
|
||||
dirSpec := tmpdir(
|
||||
t,
|
||||
fstest.CreateFile("docker-bake.hcl", remoteBakefile, 0600),
|
||||
fstest.CreateFile("bar", []byte("bar"), 0600),
|
||||
)
|
||||
dirSrc := tmpdir(
|
||||
t,
|
||||
fstest.CreateFile("local-docker-bake.hcl", localBakefile, 0600),
|
||||
)
|
||||
dirDest := t.TempDir()
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
require.FileExists(t, filepath.Join(dirDest, "bar"))
|
||||
}
|
||||
|
||||
func testBakeRemoteCmdContext(t *testing.T, sb integration.Sandbox) {
|
||||
bakefile := []byte(`
|
||||
target "default" {
|
||||
@@ -263,3 +380,107 @@ EOT
|
||||
require.NoError(t, err, out)
|
||||
require.FileExists(t, filepath.Join(dirDest, "foo"))
|
||||
}
|
||||
|
||||
func testBakeRemoteDockerfileCwd(t *testing.T, sb integration.Sandbox) {
|
||||
bakefile := []byte(`
|
||||
target "default" {
|
||||
context = "."
|
||||
dockerfile = "cwd://Dockerfile.app"
|
||||
}
|
||||
`)
|
||||
dockerfile := []byte(`
|
||||
FROM scratch
|
||||
COPY bar /bar
|
||||
`)
|
||||
dockerfileApp := []byte(`
|
||||
FROM scratch
|
||||
COPY foo /foo
|
||||
`)
|
||||
|
||||
dirSpec := tmpdir(
|
||||
t,
|
||||
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
|
||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
||||
fstest.CreateFile("bar", []byte("bar"), 0600),
|
||||
)
|
||||
dirSrc := tmpdir(
|
||||
t,
|
||||
fstest.CreateFile("Dockerfile.app", dockerfileApp, 0600),
|
||||
)
|
||||
dirDest := t.TempDir()
|
||||
|
||||
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)
|
||||
|
||||
out, err := bakeCmd(
|
||||
sb,
|
||||
withDir(dirSrc),
|
||||
withArgs(addr, "--set", "*.output=type=local,dest="+dirDest),
|
||||
)
|
||||
require.NoError(t, err, out)
|
||||
require.FileExists(t, filepath.Join(dirDest, "foo"))
|
||||
|
||||
err = os.Remove(filepath.Join(dirSrc, "Dockerfile.app"))
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err = bakeCmd(
|
||||
sb,
|
||||
withDir(dirSrc),
|
||||
withArgs(addr, "--set", "*.output=type=cacheonly"),
|
||||
)
|
||||
require.Error(t, err, out)
|
||||
}
|
||||
|
||||
func testBakeRemoteLocalContextRemoteDockerfile(t *testing.T, sb integration.Sandbox) {
|
||||
bakefile := []byte(`
|
||||
target "default" {
|
||||
context = BAKE_CMD_CONTEXT
|
||||
dockerfile = "Dockerfile.app"
|
||||
}
|
||||
`)
|
||||
dockerfileApp := []byte(`
|
||||
FROM scratch
|
||||
COPY foo /foo
|
||||
`)
|
||||
|
||||
dirSpec := tmpdir(
|
||||
t,
|
||||
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
|
||||
)
|
||||
dirSrc := tmpdir(
|
||||
t,
|
||||
fstest.CreateFile("Dockerfile.app", dockerfileApp, 0600),
|
||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
out, err := bakeCmd(
|
||||
sb,
|
||||
withDir(dirSrc),
|
||||
withArgs(addr, "--set", "*.output=type=cacheonly"),
|
||||
)
|
||||
require.Error(t, err, out)
|
||||
require.Contains(t, out, "reading a dockerfile for a remote build invocation is currently not supported")
|
||||
}
|
||||
|
||||
func testBakeEmpty(t *testing.T, sb integration.Sandbox) {
|
||||
out, err := bakeCmd(sb)
|
||||
require.Error(t, err, out)
|
||||
require.Contains(t, out, "couldn't find a bake definition")
|
||||
}
|
||||
|
283
tests/build.go
283
tests/build.go
@@ -3,19 +3,24 @@ package tests
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/continuity/fs/fstest"
|
||||
"github.com/creack/pty"
|
||||
"github.com/moby/buildkit/util/contentutil"
|
||||
"github.com/moby/buildkit/util/testutil"
|
||||
"github.com/moby/buildkit/util/testutil/integration"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -31,7 +36,18 @@ var buildTests = []func(t *testing.T, sb integration.Sandbox){
|
||||
testImageIDOutput,
|
||||
testBuildLocalExport,
|
||||
testBuildRegistryExport,
|
||||
testBuildRegistryExportAttestations,
|
||||
testBuildTarExport,
|
||||
testBuildMobyFromLocalImage,
|
||||
testBuildDetailsLink,
|
||||
testBuildProgress,
|
||||
testBuildAnnotations,
|
||||
testBuildBuildArgNoKey,
|
||||
testBuildLabelNoKey,
|
||||
testBuildCacheExportNotSupported,
|
||||
testBuildOCIExportNotSupported,
|
||||
testBuildMultiPlatformNotSupported,
|
||||
testDockerHostGateway,
|
||||
}
|
||||
|
||||
func testBuild(t *testing.T, sb integration.Sandbox) {
|
||||
@@ -89,6 +105,40 @@ func testBuildRegistryExport(t *testing.T, sb integration.Sandbox) {
|
||||
require.Equal(t, img.Layers[0]["bar"].Data, []byte("foo"))
|
||||
}
|
||||
|
||||
func testBuildRegistryExportAttestations(t *testing.T, sb integration.Sandbox) {
|
||||
dir := createTestProject(t)
|
||||
|
||||
registry, err := sb.NewRegistry()
|
||||
if errors.Is(err, integration.ErrRequirements) {
|
||||
t.Skip(err.Error())
|
||||
}
|
||||
require.NoError(t, err)
|
||||
target := registry + "/buildx/registry:latest"
|
||||
|
||||
out, err := buildCmd(sb, withArgs(fmt.Sprintf("--output=type=image,name=%s,push=true", target), "--provenance=true", dir))
|
||||
if sb.Name() == "docker" {
|
||||
require.Error(t, err)
|
||||
require.Contains(t, out, "attestations are not supported")
|
||||
return
|
||||
}
|
||||
require.NoError(t, err, string(out))
|
||||
|
||||
desc, provider, err := contentutil.ProviderFromRef(target)
|
||||
require.NoError(t, err)
|
||||
imgs, err := testutil.ReadImages(sb.Context(), provider, desc)
|
||||
require.NoError(t, err)
|
||||
|
||||
pk := platforms.Format(platforms.Normalize(platforms.DefaultSpec()))
|
||||
img := imgs.Find(pk)
|
||||
require.NotNil(t, img)
|
||||
require.Len(t, img.Layers, 1)
|
||||
require.Equal(t, img.Layers[0]["bar"].Data, []byte("foo"))
|
||||
|
||||
att := imgs.FindAttestation(pk)
|
||||
require.NotNil(t, att)
|
||||
require.Len(t, att.Layers, 1)
|
||||
}
|
||||
|
||||
func testImageIDOutput(t *testing.T, sb integration.Sandbox) {
|
||||
dockerfile := []byte(`FROM busybox:latest`)
|
||||
|
||||
@@ -99,14 +149,14 @@ func testImageIDOutput(t *testing.T, sb integration.Sandbox) {
|
||||
|
||||
outFlag := "--output=type=docker"
|
||||
|
||||
if sb.Name() == "remote" {
|
||||
if sb.DockerAddress() == "" {
|
||||
// there is no Docker atm to load the image
|
||||
outFlag += ",dest=" + targetDir + "/image.tar"
|
||||
}
|
||||
|
||||
cmd := buildxCmd(
|
||||
sb,
|
||||
withArgs("build", "-q", outFlag, "--iidfile", filepath.Join(targetDir, "iid.txt"), "--metadata-file", filepath.Join(targetDir, "md.json"), dir),
|
||||
withArgs("build", "-q", "--provenance", "false", outFlag, "--iidfile", filepath.Join(targetDir, "iid.txt"), "--metadata-file", filepath.Join(targetDir, "md.json"), dir),
|
||||
)
|
||||
stdout := bytes.NewBuffer(nil)
|
||||
cmd.Stdout = stdout
|
||||
@@ -139,6 +189,96 @@ func testImageIDOutput(t *testing.T, sb integration.Sandbox) {
|
||||
require.Equal(t, dgst, digest.Digest(md.ConfigDigest))
|
||||
}
|
||||
|
||||
func testBuildMobyFromLocalImage(t *testing.T, sb integration.Sandbox) {
|
||||
if !isDockerWorker(sb) {
|
||||
t.Skip("skipping test for non-docker workers")
|
||||
}
|
||||
|
||||
// pull image
|
||||
cmd := dockerCmd(sb, withArgs("pull", "-q", "busybox:latest"))
|
||||
stdout := bytes.NewBuffer(nil)
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
require.NoError(t, cmd.Run())
|
||||
require.Equal(t, "docker.io/library/busybox:latest", strings.TrimSpace(stdout.String()))
|
||||
|
||||
// create local tag
|
||||
cmd = dockerCmd(sb, withArgs("tag", "busybox:latest", "buildx-test:busybox"))
|
||||
cmd.Stderr = os.Stderr
|
||||
require.NoError(t, cmd.Run())
|
||||
|
||||
// build image
|
||||
dockerfile := []byte(`FROM buildx-test:busybox`)
|
||||
dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0600))
|
||||
cmd = buildxCmd(
|
||||
sb,
|
||||
withArgs("build", "-q", "--output=type=cacheonly", dir),
|
||||
)
|
||||
cmd.Stderr = os.Stderr
|
||||
require.NoError(t, cmd.Run())
|
||||
|
||||
// create local tag matching a remote one
|
||||
cmd = dockerCmd(sb, withArgs("tag", "busybox:latest", "busybox:1.35"))
|
||||
cmd.Stderr = os.Stderr
|
||||
require.NoError(t, cmd.Run())
|
||||
|
||||
// build image and check that it uses the local tag
|
||||
// (note: the version check should match the version of busybox in pins.go)
|
||||
dockerfile = []byte(`
|
||||
FROM busybox:1.35
|
||||
RUN busybox | head -1 | grep v1.36.1
|
||||
`)
|
||||
dir = tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0600))
|
||||
cmd = buildxCmd(
|
||||
sb,
|
||||
withArgs("build", "-q", "--output=type=cacheonly", dir),
|
||||
)
|
||||
cmd.Stderr = os.Stderr
|
||||
require.NoError(t, cmd.Run())
|
||||
}
|
||||
|
||||
func testBuildDetailsLink(t *testing.T, sb integration.Sandbox) {
|
||||
buildDetailsPattern := regexp.MustCompile(`(?m)^View build details: docker-desktop://dashboard/build/[^/]+/[^/]+/[^/]+\n$`)
|
||||
|
||||
// build simple dockerfile
|
||||
dockerfile := []byte(`FROM busybox:latest
|
||||
RUN echo foo > /bar`)
|
||||
dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0600))
|
||||
cmd := buildxCmd(sb, withArgs("build", "--output=type=cacheonly", dir))
|
||||
out, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(out))
|
||||
require.False(t, buildDetailsPattern.MatchString(string(out)), fmt.Sprintf("build details link not expected in output, got %q", out))
|
||||
|
||||
// create desktop-build .lastaccess file
|
||||
home, err := os.UserHomeDir() // TODO: sandbox should create a temp home dir and expose it through its interface
|
||||
require.NoError(t, err)
|
||||
dbDir := path.Join(home, ".docker", "desktop-build")
|
||||
require.NoError(t, os.MkdirAll(dbDir, 0755))
|
||||
dblaFile, err := os.Create(path.Join(dbDir, ".lastaccess"))
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
dblaFile.Close()
|
||||
if err := os.Remove(dblaFile.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// build again
|
||||
cmd = buildxCmd(sb, withArgs("build", "--output=type=cacheonly", dir))
|
||||
out, err = cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(out))
|
||||
require.True(t, buildDetailsPattern.MatchString(string(out)), fmt.Sprintf("expected build details link in output, got %q", out))
|
||||
|
||||
// build erroneous dockerfile
|
||||
dockerfile = []byte(`FROM busybox:latest
|
||||
RUN exit 1`)
|
||||
dir = tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0600))
|
||||
cmd = buildxCmd(sb, withArgs("build", "--output=type=cacheonly", dir))
|
||||
out, err = cmd.CombinedOutput()
|
||||
require.Error(t, err, string(out))
|
||||
require.True(t, buildDetailsPattern.MatchString(string(out)), fmt.Sprintf("expected build details link in output, got %q", out))
|
||||
}
|
||||
|
||||
func createTestProject(t *testing.T) string {
|
||||
dockerfile := []byte(`
|
||||
FROM busybox:latest AS base
|
||||
@@ -155,3 +295,140 @@ COPY --from=base /etc/bar /bar
|
||||
)
|
||||
return dir
|
||||
}
|
||||
|
||||
func testBuildProgress(t *testing.T, sb integration.Sandbox) {
|
||||
dir := createTestProject(t)
|
||||
driver, _, _ := strings.Cut(sb.Name(), "+")
|
||||
name := sb.Address()
|
||||
|
||||
// progress=tty
|
||||
cmd := buildxCmd(sb, withArgs("build", "--progress=tty", "--output=type=cacheonly", dir))
|
||||
f, err := pty.Start(cmd)
|
||||
require.NoError(t, err)
|
||||
buf := bytes.NewBuffer(nil)
|
||||
io.Copy(buf, f)
|
||||
ttyOutput := buf.String()
|
||||
require.Contains(t, ttyOutput, "[+] Building")
|
||||
require.Contains(t, ttyOutput, fmt.Sprintf("%s:%s", driver, name))
|
||||
require.Contains(t, ttyOutput, "=> [internal] load build definition from Dockerfile")
|
||||
require.Contains(t, ttyOutput, "=> [base 1/3] FROM docker.io/library/busybox:latest")
|
||||
|
||||
// progress=plain
|
||||
cmd = buildxCmd(sb, withArgs("build", "--progress=plain", "--output=type=cacheonly", dir))
|
||||
plainOutput, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, string(plainOutput), fmt.Sprintf(`#0 building with "%s" instance using %s driver`, name, driver))
|
||||
require.Contains(t, string(plainOutput), "[internal] load build definition from Dockerfile")
|
||||
require.Contains(t, string(plainOutput), "[base 1/3] FROM docker.io/library/busybox:latest")
|
||||
}
|
||||
|
||||
func testBuildAnnotations(t *testing.T, sb integration.Sandbox) {
|
||||
if sb.Name() == "docker" {
|
||||
t.Skip("annotations not supported on docker worker")
|
||||
}
|
||||
|
||||
dir := createTestProject(t)
|
||||
|
||||
registry, err := sb.NewRegistry()
|
||||
if errors.Is(err, integration.ErrRequirements) {
|
||||
t.Skip(err.Error())
|
||||
}
|
||||
require.NoError(t, err)
|
||||
target := registry + "/buildx/registry:latest"
|
||||
|
||||
annotations := []string{
|
||||
"--annotation", "example1=www",
|
||||
"--annotation", "index:example2=xxx",
|
||||
"--annotation", "manifest:example3=yyy",
|
||||
"--annotation", "manifest-descriptor[" + platforms.DefaultString() + "]:example4=zzz",
|
||||
}
|
||||
out, err := buildCmd(sb, withArgs(annotations...), withArgs(fmt.Sprintf("--output=type=image,name=%s,push=true", target), dir))
|
||||
require.NoError(t, err, string(out))
|
||||
|
||||
desc, provider, err := contentutil.ProviderFromRef(target)
|
||||
require.NoError(t, err)
|
||||
imgs, err := testutil.ReadImages(sb.Context(), provider, desc)
|
||||
require.NoError(t, err)
|
||||
|
||||
pk := platforms.Format(platforms.Normalize(platforms.DefaultSpec()))
|
||||
img := imgs.Find(pk)
|
||||
require.NotNil(t, img)
|
||||
|
||||
require.NotNil(t, imgs.Index)
|
||||
assert.Equal(t, "xxx", imgs.Index.Annotations["example2"])
|
||||
|
||||
require.NotNil(t, img.Manifest)
|
||||
assert.Equal(t, "www", img.Manifest.Annotations["example1"])
|
||||
assert.Equal(t, "yyy", img.Manifest.Annotations["example3"])
|
||||
|
||||
require.NotNil(t, img.Desc)
|
||||
assert.Equal(t, "zzz", img.Desc.Annotations["example4"])
|
||||
}
|
||||
|
||||
func testBuildBuildArgNoKey(t *testing.T, sb integration.Sandbox) {
|
||||
dir := createTestProject(t)
|
||||
cmd := buildxCmd(sb, withArgs("build", "--build-arg", "=TEST_STRING", dir))
|
||||
out, err := cmd.CombinedOutput()
|
||||
require.Error(t, err, string(out))
|
||||
require.Equal(t, strings.TrimSpace(string(out)), `ERROR: invalid key-value pair "=TEST_STRING": empty key`)
|
||||
}
|
||||
|
||||
func testBuildLabelNoKey(t *testing.T, sb integration.Sandbox) {
|
||||
dir := createTestProject(t)
|
||||
cmd := buildxCmd(sb, withArgs("build", "--label", "=TEST_STRING", dir))
|
||||
out, err := cmd.CombinedOutput()
|
||||
require.Error(t, err, string(out))
|
||||
require.Equal(t, strings.TrimSpace(string(out)), `ERROR: invalid key-value pair "=TEST_STRING": empty key`)
|
||||
}
|
||||
|
||||
func testBuildCacheExportNotSupported(t *testing.T, sb integration.Sandbox) {
|
||||
if sb.Name() != "docker" {
|
||||
t.Skip("skipping test for non-docker workers")
|
||||
}
|
||||
|
||||
dir := createTestProject(t)
|
||||
cmd := buildxCmd(sb, withArgs("build", "--cache-to=type=registry", dir))
|
||||
out, err := cmd.CombinedOutput()
|
||||
require.Error(t, err, string(out))
|
||||
require.Contains(t, string(out), "Cache export is not supported")
|
||||
}
|
||||
|
||||
func testBuildOCIExportNotSupported(t *testing.T, sb integration.Sandbox) {
|
||||
if sb.Name() != "docker" {
|
||||
t.Skip("skipping test for non-docker workers")
|
||||
}
|
||||
|
||||
dir := createTestProject(t)
|
||||
cmd := buildxCmd(sb, withArgs("build", fmt.Sprintf("--output=type=oci,dest=%s/result", dir), dir))
|
||||
out, err := cmd.CombinedOutput()
|
||||
require.Error(t, err, string(out))
|
||||
require.Contains(t, string(out), "OCI exporter is not supported")
|
||||
}
|
||||
|
||||
func testBuildMultiPlatformNotSupported(t *testing.T, sb integration.Sandbox) {
|
||||
if sb.Name() != "docker" {
|
||||
t.Skip("skipping test for non-docker workers")
|
||||
}
|
||||
|
||||
dir := createTestProject(t)
|
||||
cmd := buildxCmd(sb, withArgs("build", "--platform=linux/amd64,linux/arm64", dir))
|
||||
out, err := cmd.CombinedOutput()
|
||||
require.Error(t, err, string(out))
|
||||
require.Contains(t, string(out), "Multi-platform build is not supported")
|
||||
}
|
||||
|
||||
func testDockerHostGateway(t *testing.T, sb integration.Sandbox) {
|
||||
dockerfile := []byte(`
|
||||
FROM busybox
|
||||
RUN ping -c 1 buildx.host-gateway-ip.local
|
||||
`)
|
||||
dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0600))
|
||||
cmd := buildxCmd(sb, withArgs("build", "--add-host=buildx.host-gateway-ip.local:host-gateway", "--output=type=cacheonly", dir))
|
||||
out, err := cmd.CombinedOutput()
|
||||
if !isDockerWorker(sb) {
|
||||
require.Error(t, err, string(out))
|
||||
require.Contains(t, string(out), "host-gateway is not supported")
|
||||
} else {
|
||||
require.NoError(t, err, string(out))
|
||||
}
|
||||
}
|
||||
|
267
tests/imagetools.go
Normal file
267
tests/imagetools.go
Normal file
@@ -0,0 +1,267 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/continuity/fs/fstest"
|
||||
"github.com/moby/buildkit/util/testutil/integration"
|
||||
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var imagetoolsTests = []func(t *testing.T, sb integration.Sandbox){
|
||||
testImagetoolsCopyManifest,
|
||||
testImagetoolsCopyIndex,
|
||||
testImagetoolsInspectAndFilter,
|
||||
testImagetoolsAnnotation,
|
||||
}
|
||||
|
||||
func testImagetoolsCopyManifest(t *testing.T, sb integration.Sandbox) {
|
||||
if sb.Name() != "docker-container" {
|
||||
t.Skip("imagetools tests are not driver specific and only run on docker-container")
|
||||
}
|
||||
|
||||
dir := createDockerfile(t)
|
||||
registry, err := sb.NewRegistry()
|
||||
if errors.Is(err, integration.ErrRequirements) {
|
||||
t.Skip(err.Error())
|
||||
}
|
||||
require.NoError(t, err)
|
||||
target := registry + "/buildx/imtools-manifest:latest"
|
||||
|
||||
out, err := buildCmd(sb, withArgs("-t", target, "--push", "--platform=linux/amd64", "--provenance=false", dir))
|
||||
require.NoError(t, err, string(out))
|
||||
|
||||
cmd := buildxCmd(sb, withArgs("imagetools", "inspect", target, "--raw"))
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
|
||||
var mfst ocispecs.Manifest
|
||||
err = json.Unmarshal(dt, &mfst)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, images.MediaTypeDockerSchema2Manifest, mfst.MediaType)
|
||||
|
||||
registry2, err := sb.NewRegistry()
|
||||
require.NoError(t, err)
|
||||
target2 := registry2 + "/buildx/imtools2-manifest:latest"
|
||||
|
||||
cmd = buildxCmd(sb, withArgs("imagetools", "create", "-t", target2, target))
|
||||
dt, err = cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
|
||||
cmd = buildxCmd(sb, withArgs("imagetools", "inspect", target2, "--raw"))
|
||||
dt, err = cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
|
||||
var idx2 ocispecs.Index
|
||||
err = json.Unmarshal(dt, &idx2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, images.MediaTypeDockerSchema2ManifestList, idx2.MediaType)
|
||||
require.Equal(t, 1, len(idx2.Manifests))
|
||||
|
||||
cmd = buildxCmd(sb, withArgs("imagetools", "inspect", target2+"@"+string(idx2.Manifests[0].Digest), "--raw"))
|
||||
dt, err = cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
|
||||
var mfst2 ocispecs.Manifest
|
||||
err = json.Unmarshal(dt, &mfst2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, images.MediaTypeDockerSchema2Manifest, mfst2.MediaType)
|
||||
|
||||
require.Equal(t, mfst.Config.Digest, mfst2.Config.Digest)
|
||||
require.Equal(t, len(mfst.Layers), len(mfst2.Layers))
|
||||
for i := range mfst.Layers {
|
||||
require.Equal(t, mfst.Layers[i].Digest, mfst2.Layers[i].Digest)
|
||||
}
|
||||
}
|
||||
|
||||
func testImagetoolsCopyIndex(t *testing.T, sb integration.Sandbox) {
|
||||
if sb.Name() != "docker-container" {
|
||||
t.Skip("imagetools tests are not driver specific and only run on docker-container")
|
||||
}
|
||||
|
||||
dir := createDockerfile(t)
|
||||
registry, err := sb.NewRegistry()
|
||||
if errors.Is(err, integration.ErrRequirements) {
|
||||
t.Skip(err.Error())
|
||||
}
|
||||
require.NoError(t, err)
|
||||
target := registry + "/buildx/imtools:latest"
|
||||
|
||||
out, err := buildCmd(sb, withArgs("-t", target, "--push", "--platform=linux/amd64,linux/arm64", "--provenance=false", dir))
|
||||
require.NoError(t, err, string(out))
|
||||
|
||||
cmd := buildxCmd(sb, withArgs("imagetools", "inspect", target, "--raw"))
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
|
||||
var idx ocispecs.Index
|
||||
err = json.Unmarshal(dt, &idx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, images.MediaTypeDockerSchema2ManifestList, idx.MediaType)
|
||||
require.Equal(t, 2, len(idx.Manifests))
|
||||
|
||||
registry2, err := sb.NewRegistry()
|
||||
require.NoError(t, err)
|
||||
target2 := registry2 + "/buildx/imtools2:latest"
|
||||
|
||||
cmd = buildxCmd(sb, withArgs("imagetools", "create", "-t", target2, target))
|
||||
dt, err = cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
|
||||
cmd = buildxCmd(sb, withArgs("imagetools", "inspect", target2, "--raw"))
|
||||
dt, err = cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
|
||||
var idx2 ocispecs.Index
|
||||
err = json.Unmarshal(dt, &idx2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, images.MediaTypeDockerSchema2ManifestList, idx2.MediaType)
|
||||
|
||||
require.Equal(t, len(idx.Manifests), len(idx2.Manifests))
|
||||
for i := range idx.Manifests {
|
||||
require.Equal(t, idx.Manifests[i].Digest, idx2.Manifests[i].Digest)
|
||||
}
|
||||
}
|
||||
|
||||
func testImagetoolsInspectAndFilter(t *testing.T, sb integration.Sandbox) {
|
||||
if sb.Name() != "docker-container" {
|
||||
t.Skip("imagetools tests are not driver specific and only run on docker-container")
|
||||
}
|
||||
|
||||
dir := createDockerfile(t)
|
||||
registry, err := sb.NewRegistry()
|
||||
if errors.Is(err, integration.ErrRequirements) {
|
||||
t.Skip(err.Error())
|
||||
}
|
||||
require.NoError(t, err)
|
||||
target := registry + "/buildx/imtools:latest"
|
||||
|
||||
out, err := buildCmd(sb, withArgs("-t", target, "--push", "--platform=linux/amd64,linux/arm64", "--provenance=false", dir))
|
||||
require.NoError(t, err, string(out))
|
||||
|
||||
cmd := buildxCmd(sb, withArgs("imagetools", "inspect", target, "--raw"))
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
|
||||
var idx ocispecs.Index
|
||||
err = json.Unmarshal(dt, &idx)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 2, len(idx.Manifests))
|
||||
|
||||
mfst := idx.Manifests[0]
|
||||
require.Equal(t, "linux/amd64", platforms.Format(*mfst.Platform))
|
||||
|
||||
mfst = idx.Manifests[1]
|
||||
require.Equal(t, "linux/arm64", platforms.Format(*mfst.Platform))
|
||||
|
||||
// create amd64 only image
|
||||
cmd = buildxCmd(sb, withArgs("imagetools", "create", "-t", target+"-arm64", target+"@"+string(idx.Manifests[1].Digest)))
|
||||
dt, err = cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
|
||||
cmd = buildxCmd(sb, withArgs("imagetools", "inspect", target+"-arm64", "--raw"))
|
||||
dt, err = cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
|
||||
var idx2 ocispecs.Index
|
||||
err = json.Unmarshal(dt, &idx2)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(idx2.Manifests))
|
||||
|
||||
require.Equal(t, idx.Manifests[1].Digest, idx2.Manifests[0].Digest)
|
||||
require.Equal(t, platforms.Format(*idx.Manifests[1].Platform), platforms.Format(*idx2.Manifests[0].Platform))
|
||||
}
|
||||
|
||||
func testImagetoolsAnnotation(t *testing.T, sb integration.Sandbox) {
|
||||
if sb.Name() != "docker-container" {
|
||||
t.Skip("imagetools tests are not driver specific and only run on docker-container")
|
||||
}
|
||||
|
||||
dir := createDockerfile(t)
|
||||
registry, err := sb.NewRegistry()
|
||||
if errors.Is(err, integration.ErrRequirements) {
|
||||
t.Skip(err.Error())
|
||||
}
|
||||
require.NoError(t, err)
|
||||
target := registry + "/buildx/imtools:latest"
|
||||
|
||||
out, err := buildCmd(sb, withArgs("--output", "type=registry,oci-mediatypes=true,name="+target, "--platform=linux/amd64,linux/arm64", "--provenance=false", dir))
|
||||
require.NoError(t, err, string(out))
|
||||
|
||||
cmd := buildxCmd(sb, withArgs("imagetools", "inspect", target, "--raw"))
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
|
||||
var idx ocispecs.Index
|
||||
err = json.Unmarshal(dt, &idx)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, idx.Annotations)
|
||||
|
||||
imagetoolsCmd := func(source []string) *exec.Cmd {
|
||||
args := []string{"imagetools", "create", "-t", target, "--annotation", "index:foo=bar", "--annotation", "index:bar=baz",
|
||||
"--annotation", "manifest-descriptor:foo=bar", "--annotation", "manifest-descriptor[linux/amd64]:bar=baz"}
|
||||
args = append(args, source...)
|
||||
return buildxCmd(sb, withArgs(args...))
|
||||
}
|
||||
sources := [][]string{
|
||||
{
|
||||
target,
|
||||
},
|
||||
{
|
||||
target + "@" + string(idx.Manifests[0].Digest),
|
||||
target + "@" + string(idx.Manifests[1].Digest),
|
||||
},
|
||||
}
|
||||
for _, source := range sources {
|
||||
cmd = imagetoolsCmd(source)
|
||||
dt, err = cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
|
||||
newTarget := registry + "/buildx/imtools:annotations"
|
||||
cmd = buildxCmd(sb, withArgs("imagetools", "create", "-t", newTarget, target))
|
||||
dt, err = cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
|
||||
cmd = buildxCmd(sb, withArgs("imagetools", "inspect", newTarget, "--raw"))
|
||||
dt, err = cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
|
||||
err = json.Unmarshal(dt, &idx)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, idx.Annotations, 2)
|
||||
require.Equal(t, "bar", idx.Annotations["foo"])
|
||||
require.Equal(t, "baz", idx.Annotations["bar"])
|
||||
require.Len(t, idx.Manifests, 2)
|
||||
for _, mfst := range idx.Manifests {
|
||||
require.Equal(t, "bar", mfst.Annotations["foo"])
|
||||
if platforms.Format(*mfst.Platform) == "linux/amd64" {
|
||||
require.Equal(t, "baz", mfst.Annotations["bar"])
|
||||
} else {
|
||||
require.Empty(t, mfst.Annotations["bar"])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createDockerfile(t *testing.T) string {
|
||||
dockerfile := []byte(`
|
||||
FROM scratch
|
||||
ARG TARGETARCH
|
||||
COPY foo-${TARGETARCH} /foo
|
||||
`)
|
||||
dir := tmpdir(
|
||||
t,
|
||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
||||
fstest.CreateFile("foo-amd64", []byte("foo-amd64"), 0600),
|
||||
fstest.CreateFile("foo-arm64", []byte("foo-arm64"), 0600),
|
||||
)
|
||||
return dir
|
||||
}
|
@@ -25,6 +25,7 @@ func testInspect(t *testing.T, sb integration.Sandbox) {
|
||||
|
||||
var name string
|
||||
var driver string
|
||||
var hostGatewayIP string
|
||||
for _, line := range strings.Split(out, "\n") {
|
||||
if v, ok := strings.CutPrefix(line, "Name:"); ok && name == "" {
|
||||
name = strings.TrimSpace(v)
|
||||
@@ -32,7 +33,17 @@ func testInspect(t *testing.T, sb integration.Sandbox) {
|
||||
if v, ok := strings.CutPrefix(line, "Driver:"); ok && driver == "" {
|
||||
driver = strings.TrimSpace(v)
|
||||
}
|
||||
if v, ok := strings.CutPrefix(line, " org.mobyproject.buildkit.worker.moby.host-gateway-ip:"); ok {
|
||||
hostGatewayIP = strings.TrimSpace(v)
|
||||
}
|
||||
}
|
||||
|
||||
require.Equal(t, sb.Address(), name)
|
||||
require.Equal(t, sb.Name(), driver)
|
||||
sbDriver, _, _ := strings.Cut(sb.Name(), "+")
|
||||
require.Equal(t, sbDriver, driver)
|
||||
if isDockerWorker(sb) {
|
||||
require.NotEmpty(t, hostGatewayIP, "host-gateway-ip worker label should be set with docker driver")
|
||||
} else {
|
||||
require.Empty(t, hostGatewayIP, "host-gateway-ip worker label should not be set with non-docker driver")
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package tests
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/continuity/fs/fstest"
|
||||
@@ -47,6 +48,7 @@ func buildxCmd(sb integration.Sandbox, opts ...cmdOpt) *exec.Cmd {
|
||||
|
||||
if builder := sb.Address(); builder != "" {
|
||||
cmd.Args = append(cmd.Args, "--builder="+builder)
|
||||
cmd.Env = append(cmd.Env, "BUILDX_CONFIG=/tmp/buildx-"+builder)
|
||||
}
|
||||
if context := sb.DockerAddress(); context != "" {
|
||||
cmd.Env = append(cmd.Env, "DOCKER_CONTEXT="+context)
|
||||
@@ -54,3 +56,20 @@ func buildxCmd(sb integration.Sandbox, opts ...cmdOpt) *exec.Cmd {
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func dockerCmd(sb integration.Sandbox, opts ...cmdOpt) *exec.Cmd {
|
||||
cmd := exec.Command("docker")
|
||||
cmd.Env = append([]string{}, os.Environ()...)
|
||||
for _, opt := range opts {
|
||||
opt(cmd)
|
||||
}
|
||||
if context := sb.DockerAddress(); context != "" {
|
||||
cmd.Env = append(cmd.Env, "DOCKER_CONTEXT="+context)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func isDockerWorker(sb integration.Sandbox) bool {
|
||||
sbDriver, _, _ := strings.Cut(sb.Name(), "+")
|
||||
return sbDriver == "docker"
|
||||
}
|
||||
|
@@ -4,13 +4,14 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/buildx/tests/workers"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/moby/buildkit/util/testutil/integration"
|
||||
bkworkers "github.com/moby/buildkit/util/testutil/workers"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if integration.IsTestDockerd() {
|
||||
if bkworkers.IsTestDockerd() {
|
||||
workers.InitDockerWorker()
|
||||
workers.InitDockerContainerWorker()
|
||||
} else {
|
||||
@@ -24,13 +25,15 @@ func TestIntegration(t *testing.T) {
|
||||
tests = append(tests, bakeTests...)
|
||||
tests = append(tests, inspectTests...)
|
||||
tests = append(tests, lsTests...)
|
||||
tests = append(tests, imagetoolsTests...)
|
||||
tests = append(tests, versionTests...)
|
||||
testIntegration(t, tests...)
|
||||
}
|
||||
|
||||
func testIntegration(t *testing.T, funcs ...func(t *testing.T, sb integration.Sandbox)) {
|
||||
mirroredImages := integration.OfficialImages("busybox:latest", "alpine:latest")
|
||||
buildkitImage := "docker.io/moby/buildkit:buildx-stable-1"
|
||||
if integration.IsTestDockerd() {
|
||||
if bkworkers.IsTestDockerd() {
|
||||
if img, ok := os.LookupEnv("TEST_BUILDKIT_IMAGE"); ok {
|
||||
ref, err := reference.ParseNormalizedNamed(img)
|
||||
if err == nil {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user